Coverage Report - org.codehaus.mojo.nbm.BuildInstallersMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
BuildInstallersMojo
0%
0/90
0%
0/42
8
BuildInstallersMojo$1
N/A
N/A
8
BuildInstallersMojo$FileUrlUtils
0%
0/48
0%
0/32
8
 
 1  
 /*
 2  
  * Copyright 2012 Frantisek Mantlik <frantisek at mantlik.cz>.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  * under the License.
 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  
  * Build installers for Mavenized NetBeans application.
 41  
  * Creates installers for supported operating systems
 42  
  * and packages each installer as a deployable artifact.
 43  
  * <p>See a <a href="http://mojo.codehaus.org/nbm-maven/nbm-maven-plugin/buildinstexample.html">how-to</a> on customizing the installer.
 44  
  * @author <a href="mailto:frantisek@mantlik.cz">Frantisek Mantlik</a>
 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  
     * output directory.
 57  
     */
 58  
     @Parameter(defaultValue="${project.build.directory}", required=true)
 59  
     protected File outputDirectory;
 60  
     /**
 61  
     * The branding token for the application based on NetBeans platform.
 62  
     */
 63  
     @Parameter(property="netbeans.branding.token", required=true)
 64  
     protected String brandingToken;
 65  
     /**
 66  
     * Installation directory name at the destination system
 67  
     * Deprecated, to be removed, was never actually used.
 68  
     */
 69  
     @Parameter(property="netbeans.branding.token")
 70  
     protected String installDirName;
 71  
     /**
 72  
     * Prefix of all generated installers files
 73  
     */
 74  
     @Parameter(defaultValue="${project.build.finalName}")
 75  
     private String installersFilePrefix;
 76  
     /**
 77  
      * Create installer for Windows
 78  
      */
 79  
     @Parameter(defaultValue="true")
 80  
     private boolean installerOsWindows;
 81  
     /**
 82  
      * Create installer for Solaris
 83  
      */
 84  
     @Parameter(defaultValue="true")
 85  
     private boolean installerOsSolaris;
 86  
     /**
 87  
      * Create installer for Linux
 88  
      */
 89  
     @Parameter(defaultValue="true")    
 90  
     private boolean installerOsLinux;
 91  
     /**
 92  
      * Create installer for MacOSx
 93  
      */
 94  
     @Parameter(defaultValue="true")    
 95  
     private boolean installerOsMacosx;
 96  
     /**
 97  
      * Enable Pack200 compression
 98  
      */
 99  
     @Parameter(defaultValue="true")
 100  
     private boolean installerPack200Enable;
 101  
     /**
 102  
      * License file
 103  
      */
 104  
     @Parameter(defaultValue="${basedir}/license.txt")
 105  
     private File installerLicenseFile;
 106  
     /**
 107  
      * Custom installer template.
 108  
      * This file, if provided, will replace default template from
 109  
      * &lt;NetBeansInstallation&gt;/harness/nbi/stub/template.xml
 110  
      */
 111  
     @Parameter
 112  
     private File templateFile;
 113  
     /**
 114  
      * Parameters passed to templateFile 
 115  
      * or to installer/nbi/stub/template.xml 
 116  
      * to customize generated installers.
 117  
      *
 118  
      */
 119  
     @Parameter
 120  
     private Map<String, String> userSettings;
 121  
     
 122  
     /**
 123  
      * Name of the zip artifact used to produce installers from (without .zip extension)
 124  
      */
 125  
     @Parameter(defaultValue="${project.build.finalName}")
 126  
     private String finalName;
 127  
 
 128  
     // <editor-fold defaultstate="collapsed" desc="Component parameters">
 129  
     /**
 130  
      * Used for attaching the artifact in the project
 131  
      */
 132  
     @Component
 133  
     private MavenProjectHelper projectHelper;
 134  
         
 135  
     @Parameter(readonly=true, required=true, property="basedir")
 136  
     private File basedir;
 137  
     /**
 138  
     * The Maven Project.
 139  
     */
 140  
     @Parameter(required=true, readonly=true, property="project")    
 141  
     private MavenProject project;    
 142  
 
 143  
     // </editor-fold>
 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  
         // Copy Netbeans Installer resources
 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  
         // Overwrite template file with modified version to accept branded images etc.
 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  
 //        props.put( "install.dir.name", installDirName );
 195  
 
 196  
         //mkleint: this is a flawed pattern! cannot make any assumption on multimodule layout
 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() ); //mkleint: no path replacement here??
 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  
             //nothing to build
 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" ) ) //mkleint: does this work on mac? no rt.jar there
 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  
     //mkleint: could this be replaced by something from plexus-utils?
 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  
 }