1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.mojo.nbm;
18
19 import java.io.*;
20 import java.net.JarURLConnection;
21 import java.net.URL;
22 import java.net.URLConnection;
23 import java.util.*;
24 import java.util.jar.JarEntry;
25 import java.util.jar.JarFile;
26 import org.apache.maven.plugin.MojoExecutionException;
27 import org.apache.maven.plugin.MojoFailureException;
28 import org.apache.maven.plugins.annotations.Component;
29 import org.apache.maven.plugins.annotations.LifecyclePhase;
30 import org.apache.maven.plugins.annotations.Mojo;
31 import org.apache.maven.plugins.annotations.Parameter;
32 import org.apache.maven.plugins.annotations.ResolutionScope;
33 import org.apache.maven.project.MavenProject;
34 import org.apache.maven.project.MavenProjectHelper;
35 import org.apache.tools.ant.Project;
36 import org.apache.tools.ant.ProjectHelper;
37 import org.apache.tools.ant.util.StringUtils;
38
39
40
41
42
43
44
45
46 @Mojo(name="build-installers",
47 requiresProject=true,
48 requiresDependencyResolution=ResolutionScope.RUNTIME,
49 threadSafe = true,
50 defaultPhase=LifecyclePhase.PACKAGE )
51 public class BuildInstallersMojo
52 extends AbstractNbmMojo
53 {
54
55
56
57
58 @Parameter(defaultValue="${project.build.directory}", required=true)
59 protected File outputDirectory;
60
61
62
63 @Parameter(property="netbeans.branding.token", required=true)
64 protected String brandingToken;
65
66
67
68
69 @Parameter(property="netbeans.branding.token")
70 protected String installDirName;
71
72
73
74 @Parameter(defaultValue="${project.build.finalName}")
75 private String installersFilePrefix;
76
77
78
79 @Parameter(defaultValue="true")
80 private boolean installerOsWindows;
81
82
83
84 @Parameter(defaultValue="true")
85 private boolean installerOsSolaris;
86
87
88
89 @Parameter(defaultValue="true")
90 private boolean installerOsLinux;
91
92
93
94 @Parameter(defaultValue="true")
95 private boolean installerOsMacosx;
96
97
98
99 @Parameter(defaultValue="true")
100 private boolean installerPack200Enable;
101
102
103
104 @Parameter(defaultValue="${basedir}/license.txt")
105 private File installerLicenseFile;
106
107
108
109
110
111 @Parameter
112 private File templateFile;
113
114
115
116
117
118
119 @Parameter
120 private Map<String, String> userSettings;
121
122
123
124
125 @Parameter(defaultValue="${project.build.finalName}")
126 private String finalName;
127
128
129
130
131
132 @Component
133 private MavenProjectHelper projectHelper;
134
135 @Parameter(readonly=true, required=true, property="basedir")
136 private File basedir;
137
138
139
140 @Parameter(required=true, readonly=true, property="project")
141 private MavenProject project;
142
143
144 @Override
145 public void execute()
146 throws MojoExecutionException, MojoFailureException
147 {
148 Project antProject = antProject();
149
150 if ( !"nbm-application".equals( project.getPackaging() ) )
151 {
152 throw new MojoExecutionException(
153 "This goal only makes sense on project with 'nbm-application' packaging." );
154 }
155
156 if (!installerOsLinux && !installerOsMacosx && !installerOsSolaris && !installerOsWindows) {
157 getLog().warn( "None of the Operating System Installers selected, skipping 'build-installers' goal.");
158 return;
159 }
160
161 String zipName = finalName + ".zip";
162 File zipFile = new File( outputDirectory, zipName );
163 getLog().info( String.format( "Running Build Installers action for (existing=%2$s) zip file %1$s",
164 zipFile, zipFile.exists() ) );
165
166
167 File appIconIcnsFile;
168
169
170 FileUrlUtils fu = new FileUrlUtils();
171 File harnessDir = new File( outputDirectory, "installer" );
172 fu.copyResourcesRecursively( getClass().getClassLoader().getResource( "harness" ), harnessDir );
173
174
175 if ( templateFile != null )
176 {
177 File template = new File( harnessDir, "nbi/stub/template.xml" );
178 fu.copyFile( templateFile, template );
179 }
180
181 appIconIcnsFile = new File( harnessDir, "etc" + File.separatorChar + "applicationIcon.icns" );
182 getLog().info( "Application icon:" + appIconIcnsFile.getAbsolutePath() );
183
184 Map<String, String> props = new HashMap<String, String> ();
185
186 props.put( "suite.location", basedir.getAbsolutePath().replace( "\\", "/" ) );
187 props.put( "suite.props.app.name", brandingToken);
188 props.put( "suite.dist.zip", zipFile.getAbsolutePath().replace( "\\", "/" ) );
189 props.put( "suite.dist.directory", outputDirectory.getAbsolutePath().replace( "\\", "/" ) );
190 props.put( "installer.build.dir", new File( outputDirectory, "installerbuild" ).getAbsolutePath().replace( "\\", "/" ) );
191
192 props.put( "installers.file.prefix", installersFilePrefix );
193
194
195
196
197 String appName = project.getParent().getArtifactId().replace( ".", "" ).replace( "-", "" ).replace( "_", "" ).replaceAll( "[0-9]+", "" );
198 props.put( "suite.nbi.product.uid", appName.toLowerCase( Locale.ENGLISH ) );
199
200 props.put( "suite.props.app.title", ( project.getName() + " " + project.getVersion() ).replaceAll( "-SNAPSHOT", "" ) );
201
202 String appVersion = project.getVersion().replaceAll( "-SNAPSHOT", "" );
203 props.put( "suite.nbi.product.version.short", appVersion );
204 while ( appVersion.split( "\\." ).length < 5 )
205 {
206 appVersion += ".0";
207 }
208 props.put( "suite.nbi.product.version", appVersion );
209
210 props.put( "nbi.stub.location", new File( harnessDir, "nbi/stub" ).getAbsolutePath().replace( "\\", "/" ) );
211
212 props.put( "nbi.stub.common.location", new File( harnessDir, "nbi/.common" ).getAbsolutePath().replace( "\\", "/" ) );
213
214 props.put( "nbi.ant.tasks.jar", new File( harnessDir, "modules/ext/nbi-ant-tasks.jar" ).getAbsolutePath().replace( "\\", "/" ) );
215
216 props.put( "nbi.registries.management.jar", new File( harnessDir, "modules/ext/nbi-registries-management.jar" ).getAbsolutePath().replace( "\\", "/" ) );
217
218 props.put( "nbi.engine.jar", new File( harnessDir, "modules/ext/nbi-engine.jar" ).getAbsolutePath().replace( "\\", "/" ) );
219
220 if ( installerLicenseFile != null )
221 {
222 getLog().info( String.format( "License file is at %1s, exist = %2$s", installerLicenseFile, installerLicenseFile.exists() ) );
223 props.put( "nbi.license.file", installerLicenseFile.getAbsolutePath() );
224 }
225
226 List<String> platforms = new ArrayList<String>();
227
228 if ( this.installerOsLinux )
229 {
230 platforms.add( "linux" );
231 File linuxFile = new File( outputDirectory, installersFilePrefix + "-linux.sh" );
232 projectHelper.attachArtifact( project, "sh", "linux", linuxFile );
233 }
234 if ( this.installerOsSolaris )
235 {
236 platforms.add( "solaris" );
237 File solarisFile = new File( outputDirectory, installersFilePrefix + "-solaris.sh" );
238 projectHelper.attachArtifact( project, "sh", "solaris", solarisFile );
239 }
240 if ( this.installerOsWindows )
241 {
242 platforms.add( "windows" );
243 File windowsFile = new File( outputDirectory, installersFilePrefix + "-windows.exe" );
244 projectHelper.attachArtifact( project, "exe", "windows", windowsFile );
245 }
246 if ( this.installerOsMacosx )
247 {
248 platforms.add( "macosx" );
249 File macosxFile = new File( outputDirectory, installersFilePrefix + "-macosx.tgz" );
250 projectHelper.attachArtifact( project, "tgz", "macosx", macosxFile );
251 }
252
253 StringBuilder sb = new StringBuilder();
254 for ( int i = 0; i < platforms.size(); i++ )
255 {
256 if ( i != 0 )
257 {
258 sb.append( " " );
259 }
260 sb.append( platforms.get( i ) );
261 }
262 if ( sb.length() == 0 )
263 {
264
265 getLog().warn( "Nothing to build." );
266 }
267
268 props.put( "generate.installer.for.platforms", sb.toString() );
269
270 File javaHome = new File( System.getProperty( "java.home" ) );
271 if ( new File( javaHome, "lib/rt.jar" ).exists() && javaHome.getName().equals( "jre" ) )
272 {
273 javaHome = javaHome.getParentFile();
274 }
275 props.put( "generator-jdk-location-forward-slashes", javaHome.getAbsolutePath().replace( "\\", "/" ) );
276
277 props.put( "pack200.enabled", "" + installerPack200Enable );
278
279 if ( appIconIcnsFile != null )
280 {
281 props.put( "nbi.dock.icon.file", appIconIcnsFile.getAbsolutePath() );
282 }
283
284 try
285 {
286 antProject.setUserProperty( "ant.file", new File( harnessDir, "nbi/stub/template.xml" ).getAbsolutePath().replace( "\\", "/" ) );
287 ProjectHelper helper = ProjectHelper.getProjectHelper();
288 antProject.addReference( "ant.projectHelper", helper );
289 helper.parse( antProject, new File( harnessDir, "nbi/stub/template.xml" ) );
290 for ( Map.Entry<String, String> e : props.entrySet() )
291 {
292 antProject.setProperty( e.getKey(), e.getValue() );
293 }
294 if ( userSettings != null )
295 {
296 for ( Map.Entry<String, String> e : userSettings.entrySet() )
297 {
298 antProject.setProperty( e.getKey(), e.getValue() );
299 }
300 }
301 antProject.executeTarget( "build" );
302 }
303 catch ( Exception ex )
304 {
305 throw new MojoExecutionException( "Installers creation failed: " + ex, ex );
306 }
307 }
308
309
310 private class FileUrlUtils
311 {
312
313 boolean copyFile( final File toCopy, final File destFile )
314 throws MojoExecutionException
315 {
316 try
317 {
318 return copyStream( new FileInputStream( toCopy ), new FileOutputStream( destFile ) );
319 }
320 catch ( final FileNotFoundException e )
321 {
322 throw new MojoExecutionException( "Installers creation failed: " + e, e );
323 }
324 }
325
326 boolean copyFilesRecusively( final File toCopy, final File destDir )
327 throws MojoExecutionException
328 {
329 assert destDir.isDirectory();
330
331 if ( !toCopy.isDirectory() )
332 {
333 return copyFile( toCopy, new File( destDir, toCopy.getName() ) );
334 }
335 else
336 {
337 final File newDestDir = new File( destDir, toCopy.getName() );
338 if ( !newDestDir.exists() && !newDestDir.mkdir() )
339 {
340 return false;
341 }
342 for ( final File child : toCopy.listFiles() )
343 {
344 if ( !copyFilesRecusively( child, newDestDir ) )
345 {
346 return false;
347 }
348 }
349 }
350 return true;
351 }
352
353 boolean copyJarResourcesRecursively( final File destDir, final JarURLConnection jarConnection )
354 throws IOException, MojoExecutionException
355 {
356
357 final JarFile jarFile = jarConnection.getJarFile();
358
359 for ( final Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); )
360 {
361 final JarEntry entry = e.nextElement();
362 if ( entry.getName().startsWith( jarConnection.getEntryName() ) )
363 {
364 final String filename = StringUtils.removePrefix( entry.getName(),
365 jarConnection.getEntryName() );
366
367 final File f = new File( destDir, filename );
368 if ( !entry.isDirectory() )
369 {
370 final InputStream entryInputStream = jarFile.getInputStream( entry );
371 if ( !copyStream( entryInputStream, f ) )
372 {
373 return false;
374 }
375 entryInputStream.close();
376 }
377 else
378 {
379 if ( !ensureDirectoryExists( f ) )
380 {
381 throw new IOException( "Could not create directory: "
382 + f.getAbsolutePath() );
383 }
384 }
385 }
386 }
387 return true;
388 }
389
390 boolean copyResourcesRecursively( final URL originUrl, final File destination )
391 throws MojoExecutionException
392 {
393 try
394 {
395 final URLConnection urlConnection = originUrl.openConnection();
396 if ( urlConnection instanceof JarURLConnection )
397 {
398 return copyJarResourcesRecursively( destination, (JarURLConnection) urlConnection );
399 }
400 else
401 {
402 return copyFilesRecusively( new File( originUrl.getPath() ), destination );
403 }
404 }
405 catch ( final IOException e )
406 {
407 throw new MojoExecutionException( "Installers creation failed: " + e, e );
408 }
409 }
410
411 boolean copyStream( final InputStream is, final File f )
412 throws MojoExecutionException
413 {
414 try
415 {
416 return copyStream( is, new FileOutputStream( f ) );
417 }
418 catch ( final FileNotFoundException e )
419 {
420 throw new MojoExecutionException( "Installers creation failed: " + e, e );
421 }
422 }
423
424 boolean copyStream( final InputStream is, final OutputStream os )
425 throws MojoExecutionException
426 {
427 try
428 {
429 final byte[] buf = new byte[1024];
430
431 int len;
432 while ( ( len = is.read( buf ) ) > 0 )
433 {
434 os.write( buf, 0, len );
435 }
436 is.close();
437 os.close();
438 return true;
439 }
440 catch ( final IOException e )
441 {
442 throw new MojoExecutionException( "Installers creation failed: " + e, e );
443 }
444 }
445
446 boolean ensureDirectoryExists( final File f )
447 {
448 return f.exists() || f.mkdir();
449 }
450 }
451 }