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 | 0 | 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 | 0 | Project antProject = antProject(); |
149 | |
|
150 | 0 | if ( !"nbm-application".equals( project.getPackaging() ) ) |
151 | |
{ |
152 | 0 | throw new MojoExecutionException( |
153 | |
"This goal only makes sense on project with 'nbm-application' packaging." ); |
154 | |
} |
155 | |
|
156 | 0 | if (!installerOsLinux && !installerOsMacosx && !installerOsSolaris && !installerOsWindows) { |
157 | 0 | getLog().warn( "None of the Operating System Installers selected, skipping 'build-installers' goal."); |
158 | 0 | return; |
159 | |
} |
160 | |
|
161 | 0 | String zipName = finalName + ".zip"; |
162 | 0 | File zipFile = new File( outputDirectory, zipName ); |
163 | 0 | 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 | 0 | FileUrlUtils fu = new FileUrlUtils(); |
171 | 0 | File harnessDir = new File( outputDirectory, "installer" ); |
172 | 0 | fu.copyResourcesRecursively( getClass().getClassLoader().getResource( "harness" ), harnessDir ); |
173 | |
|
174 | |
|
175 | 0 | if ( templateFile != null ) |
176 | |
{ |
177 | 0 | File template = new File( harnessDir, "nbi/stub/template.xml" ); |
178 | 0 | fu.copyFile( templateFile, template ); |
179 | |
} |
180 | |
|
181 | 0 | appIconIcnsFile = new File( harnessDir, "etc" + File.separatorChar + "applicationIcon.icns" ); |
182 | 0 | getLog().info( "Application icon:" + appIconIcnsFile.getAbsolutePath() ); |
183 | |
|
184 | 0 | Map<String, String> props = new HashMap<String, String> (); |
185 | |
|
186 | 0 | props.put( "suite.location", basedir.getAbsolutePath().replace( "\\", "/" ) ); |
187 | 0 | props.put( "suite.props.app.name", brandingToken); |
188 | 0 | props.put( "suite.dist.zip", zipFile.getAbsolutePath().replace( "\\", "/" ) ); |
189 | 0 | props.put( "suite.dist.directory", outputDirectory.getAbsolutePath().replace( "\\", "/" ) ); |
190 | 0 | props.put( "installer.build.dir", new File( outputDirectory, "installerbuild" ).getAbsolutePath().replace( "\\", "/" ) ); |
191 | |
|
192 | 0 | props.put( "installers.file.prefix", installersFilePrefix ); |
193 | |
|
194 | |
|
195 | |
|
196 | |
|
197 | 0 | String appName = project.getParent().getArtifactId().replace( ".", "" ).replace( "-", "" ).replace( "_", "" ).replaceAll( "[0-9]+", "" ); |
198 | 0 | props.put( "suite.nbi.product.uid", appName.toLowerCase( Locale.ENGLISH ) ); |
199 | |
|
200 | 0 | props.put( "suite.props.app.title", ( project.getName() + " " + project.getVersion() ).replaceAll( "-SNAPSHOT", "" ) ); |
201 | |
|
202 | 0 | String appVersion = project.getVersion().replaceAll( "-SNAPSHOT", "" ); |
203 | 0 | props.put( "suite.nbi.product.version.short", appVersion ); |
204 | 0 | while ( appVersion.split( "\\." ).length < 5 ) |
205 | |
{ |
206 | 0 | appVersion += ".0"; |
207 | |
} |
208 | 0 | props.put( "suite.nbi.product.version", appVersion ); |
209 | |
|
210 | 0 | props.put( "nbi.stub.location", new File( harnessDir, "nbi/stub" ).getAbsolutePath().replace( "\\", "/" ) ); |
211 | |
|
212 | 0 | props.put( "nbi.stub.common.location", new File( harnessDir, "nbi/.common" ).getAbsolutePath().replace( "\\", "/" ) ); |
213 | |
|
214 | 0 | props.put( "nbi.ant.tasks.jar", new File( harnessDir, "modules/ext/nbi-ant-tasks.jar" ).getAbsolutePath().replace( "\\", "/" ) ); |
215 | |
|
216 | 0 | props.put( "nbi.registries.management.jar", new File( harnessDir, "modules/ext/nbi-registries-management.jar" ).getAbsolutePath().replace( "\\", "/" ) ); |
217 | |
|
218 | 0 | props.put( "nbi.engine.jar", new File( harnessDir, "modules/ext/nbi-engine.jar" ).getAbsolutePath().replace( "\\", "/" ) ); |
219 | |
|
220 | 0 | if ( installerLicenseFile != null ) |
221 | |
{ |
222 | 0 | getLog().info( String.format( "License file is at %1s, exist = %2$s", installerLicenseFile, installerLicenseFile.exists() ) ); |
223 | 0 | props.put( "nbi.license.file", installerLicenseFile.getAbsolutePath() ); |
224 | |
} |
225 | |
|
226 | 0 | List<String> platforms = new ArrayList<String>(); |
227 | |
|
228 | 0 | if ( this.installerOsLinux ) |
229 | |
{ |
230 | 0 | platforms.add( "linux" ); |
231 | 0 | File linuxFile = new File( outputDirectory, installersFilePrefix + "-linux.sh" ); |
232 | 0 | projectHelper.attachArtifact( project, "sh", "linux", linuxFile ); |
233 | |
} |
234 | 0 | if ( this.installerOsSolaris ) |
235 | |
{ |
236 | 0 | platforms.add( "solaris" ); |
237 | 0 | File solarisFile = new File( outputDirectory, installersFilePrefix + "-solaris.sh" ); |
238 | 0 | projectHelper.attachArtifact( project, "sh", "solaris", solarisFile ); |
239 | |
} |
240 | 0 | if ( this.installerOsWindows ) |
241 | |
{ |
242 | 0 | platforms.add( "windows" ); |
243 | 0 | File windowsFile = new File( outputDirectory, installersFilePrefix + "-windows.exe" ); |
244 | 0 | projectHelper.attachArtifact( project, "exe", "windows", windowsFile ); |
245 | |
} |
246 | 0 | if ( this.installerOsMacosx ) |
247 | |
{ |
248 | 0 | platforms.add( "macosx" ); |
249 | 0 | File macosxFile = new File( outputDirectory, installersFilePrefix + "-macosx.tgz" ); |
250 | 0 | projectHelper.attachArtifact( project, "tgz", "macosx", macosxFile ); |
251 | |
} |
252 | |
|
253 | 0 | StringBuilder sb = new StringBuilder(); |
254 | 0 | for ( int i = 0; i < platforms.size(); i++ ) |
255 | |
{ |
256 | 0 | if ( i != 0 ) |
257 | |
{ |
258 | 0 | sb.append( " " ); |
259 | |
} |
260 | 0 | sb.append( platforms.get( i ) ); |
261 | |
} |
262 | 0 | if ( sb.length() == 0 ) |
263 | |
{ |
264 | |
|
265 | 0 | getLog().warn( "Nothing to build." ); |
266 | |
} |
267 | |
|
268 | 0 | props.put( "generate.installer.for.platforms", sb.toString() ); |
269 | |
|
270 | 0 | File javaHome = new File( System.getProperty( "java.home" ) ); |
271 | 0 | if ( new File( javaHome, "lib/rt.jar" ).exists() && javaHome.getName().equals( "jre" ) ) |
272 | |
{ |
273 | 0 | javaHome = javaHome.getParentFile(); |
274 | |
} |
275 | 0 | props.put( "generator-jdk-location-forward-slashes", javaHome.getAbsolutePath().replace( "\\", "/" ) ); |
276 | |
|
277 | 0 | props.put( "pack200.enabled", "" + installerPack200Enable ); |
278 | |
|
279 | 0 | if ( appIconIcnsFile != null ) |
280 | |
{ |
281 | 0 | props.put( "nbi.dock.icon.file", appIconIcnsFile.getAbsolutePath() ); |
282 | |
} |
283 | |
|
284 | |
try |
285 | |
{ |
286 | 0 | antProject.setUserProperty( "ant.file", new File( harnessDir, "nbi/stub/template.xml" ).getAbsolutePath().replace( "\\", "/" ) ); |
287 | 0 | ProjectHelper helper = ProjectHelper.getProjectHelper(); |
288 | 0 | antProject.addReference( "ant.projectHelper", helper ); |
289 | 0 | helper.parse( antProject, new File( harnessDir, "nbi/stub/template.xml" ) ); |
290 | 0 | for ( Map.Entry<String, String> e : props.entrySet() ) |
291 | |
{ |
292 | 0 | antProject.setProperty( e.getKey(), e.getValue() ); |
293 | 0 | } |
294 | 0 | if ( userSettings != null ) |
295 | |
{ |
296 | 0 | for ( Map.Entry<String, String> e : userSettings.entrySet() ) |
297 | |
{ |
298 | 0 | antProject.setProperty( e.getKey(), e.getValue() ); |
299 | 0 | } |
300 | |
} |
301 | 0 | antProject.executeTarget( "build" ); |
302 | |
} |
303 | 0 | catch ( Exception ex ) |
304 | |
{ |
305 | 0 | throw new MojoExecutionException( "Installers creation failed: " + ex, ex ); |
306 | 0 | } |
307 | 0 | } |
308 | |
|
309 | |
|
310 | 0 | private class FileUrlUtils |
311 | |
{ |
312 | |
|
313 | |
boolean copyFile( final File toCopy, final File destFile ) |
314 | |
throws MojoExecutionException |
315 | |
{ |
316 | |
try |
317 | |
{ |
318 | 0 | return copyStream( new FileInputStream( toCopy ), new FileOutputStream( destFile ) ); |
319 | |
} |
320 | 0 | catch ( final FileNotFoundException e ) |
321 | |
{ |
322 | 0 | 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 | 0 | assert destDir.isDirectory(); |
330 | |
|
331 | 0 | if ( !toCopy.isDirectory() ) |
332 | |
{ |
333 | 0 | return copyFile( toCopy, new File( destDir, toCopy.getName() ) ); |
334 | |
} |
335 | |
else |
336 | |
{ |
337 | 0 | final File newDestDir = new File( destDir, toCopy.getName() ); |
338 | 0 | if ( !newDestDir.exists() && !newDestDir.mkdir() ) |
339 | |
{ |
340 | 0 | return false; |
341 | |
} |
342 | 0 | for ( final File child : toCopy.listFiles() ) |
343 | |
{ |
344 | 0 | if ( !copyFilesRecusively( child, newDestDir ) ) |
345 | |
{ |
346 | 0 | return false; |
347 | |
} |
348 | |
} |
349 | |
} |
350 | 0 | return true; |
351 | |
} |
352 | |
|
353 | |
boolean copyJarResourcesRecursively( final File destDir, final JarURLConnection jarConnection ) |
354 | |
throws IOException, MojoExecutionException |
355 | |
{ |
356 | |
|
357 | 0 | final JarFile jarFile = jarConnection.getJarFile(); |
358 | |
|
359 | 0 | for ( final Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements(); ) |
360 | |
{ |
361 | 0 | final JarEntry entry = e.nextElement(); |
362 | 0 | if ( entry.getName().startsWith( jarConnection.getEntryName() ) ) |
363 | |
{ |
364 | 0 | final String filename = StringUtils.removePrefix( entry.getName(), |
365 | |
jarConnection.getEntryName() ); |
366 | |
|
367 | 0 | final File f = new File( destDir, filename ); |
368 | 0 | if ( !entry.isDirectory() ) |
369 | |
{ |
370 | 0 | final InputStream entryInputStream = jarFile.getInputStream( entry ); |
371 | 0 | if ( !copyStream( entryInputStream, f ) ) |
372 | |
{ |
373 | 0 | return false; |
374 | |
} |
375 | 0 | entryInputStream.close(); |
376 | 0 | } |
377 | |
else |
378 | |
{ |
379 | 0 | if ( !ensureDirectoryExists( f ) ) |
380 | |
{ |
381 | 0 | throw new IOException( "Could not create directory: " |
382 | |
+ f.getAbsolutePath() ); |
383 | |
} |
384 | |
} |
385 | |
} |
386 | 0 | } |
387 | 0 | return true; |
388 | |
} |
389 | |
|
390 | |
boolean copyResourcesRecursively( final URL originUrl, final File destination ) |
391 | |
throws MojoExecutionException |
392 | |
{ |
393 | |
try |
394 | |
{ |
395 | 0 | final URLConnection urlConnection = originUrl.openConnection(); |
396 | 0 | if ( urlConnection instanceof JarURLConnection ) |
397 | |
{ |
398 | 0 | return copyJarResourcesRecursively( destination, (JarURLConnection) urlConnection ); |
399 | |
} |
400 | |
else |
401 | |
{ |
402 | 0 | return copyFilesRecusively( new File( originUrl.getPath() ), destination ); |
403 | |
} |
404 | |
} |
405 | 0 | catch ( final IOException e ) |
406 | |
{ |
407 | 0 | 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 | 0 | return copyStream( is, new FileOutputStream( f ) ); |
417 | |
} |
418 | 0 | catch ( final FileNotFoundException e ) |
419 | |
{ |
420 | 0 | 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 | 0 | final byte[] buf = new byte[1024]; |
430 | |
|
431 | |
int len; |
432 | 0 | while ( ( len = is.read( buf ) ) > 0 ) |
433 | |
{ |
434 | 0 | os.write( buf, 0, len ); |
435 | |
} |
436 | 0 | is.close(); |
437 | 0 | os.close(); |
438 | 0 | return true; |
439 | |
} |
440 | 0 | catch ( final IOException e ) |
441 | |
{ |
442 | 0 | throw new MojoExecutionException( "Installers creation failed: " + e, e ); |
443 | |
} |
444 | |
} |
445 | |
|
446 | |
boolean ensureDirectoryExists( final File f ) |
447 | |
{ |
448 | 0 | return f.exists() || f.mkdir(); |
449 | |
} |
450 | |
} |
451 | |
} |