Coverage Report - org.apache.maven.plugin.eclipse.InstallPluginsMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
InstallPluginsMojo
0% 
0% 
7.333
 
 1  
 package org.apache.maven.plugin.eclipse;
 2  
 
 3  
 import org.apache.maven.artifact.Artifact;
 4  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 5  
 import org.apache.maven.plugin.AbstractMojo;
 6  
 import org.apache.maven.plugin.MojoExecutionException;
 7  
 import org.apache.maven.plugin.MojoFailureException;
 8  
 import org.apache.maven.plugin.logging.Log;
 9  
 import org.apache.maven.project.MavenProject;
 10  
 import org.apache.maven.project.MavenProjectBuilder;
 11  
 import org.apache.maven.project.ProjectBuildingException;
 12  
 import org.codehaus.plexus.archiver.ArchiverException;
 13  
 import org.codehaus.plexus.archiver.UnArchiver;
 14  
 import org.codehaus.plexus.archiver.manager.ArchiverManager;
 15  
 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
 16  
 import org.codehaus.plexus.components.interactivity.InputHandler;
 17  
 import org.codehaus.plexus.util.FileUtils;
 18  
 import org.codehaus.plexus.util.StringUtils;
 19  
 
 20  
 import java.io.File;
 21  
 import java.io.IOException;
 22  
 import java.util.Collection;
 23  
 import java.util.Collections;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 import java.util.Properties;
 27  
 import java.util.jar.Attributes;
 28  
 import java.util.jar.JarFile;
 29  
 import java.util.jar.Manifest;
 30  
 
 31  
 /**
 32  
  * Install plugins resolved from the Maven repository system into an Eclipse instance.
 33  
  * 
 34  
  * @goal install-plugins
 35  
  * @author jdcasey
 36  
  * @requiresDependencyResolution compile
 37  
  */
 38  
 public class InstallPluginsMojo
 39  
     extends AbstractMojo
 40  
 {
 41  
 
 42  
     /**
 43  
      * Set this property in a plugin POM's <properties/> section to determine whether that
 44  
      * plugin should be expanded during installation, or left as a jar file.
 45  
      */
 46  
     public static final String PROP_UNPACK_PLUGIN = "eclipse.unpack";
 47  
 
 48  
     /**
 49  
      * This is the installed base directory of the Eclipse instance you want to modify.
 50  
      * 
 51  
      * @parameter expression="${eclipseDir}"
 52  
      */
 53  
     private File eclipseDir;
 54  
 
 55  
     /**
 56  
      * Determines whether this mojo leaves existing installed plugins as-is, or overwrites them.
 57  
      * 
 58  
      * @parameter expression="${overwrite}" default-value="false"
 59  
      */
 60  
     private boolean overwrite;
 61  
 
 62  
     /**
 63  
      * The list of resolved dependencies from the current project. Since we're not resolving the
 64  
      * dependencies by hand here, the build will fail if some of these dependencies do not resolve.
 65  
      * 
 66  
      * @parameter default-value="${project.artifacts}"
 67  
      * @required
 68  
      * @readonly
 69  
      */
 70  
     private Collection artifacts;
 71  
 
 72  
     /**
 73  
      * Comma-delimited list of dependency <type/> values which will be installed in the eclipse
 74  
      * instance's plugins directory.
 75  
      * 
 76  
      * @parameter expression="${pluginDependencyTypes}" default-value="jar"
 77  
      */
 78  
     private String pluginDependencyTypes;
 79  
 
 80  
     /**
 81  
      * The location of the Maven local repository, from which to install resolved dependency plugins.
 82  
      * 
 83  
      * @parameter default-value="${localRepository}"
 84  
      * @required
 85  
      * @readonly
 86  
      */
 87  
     private ArtifactRepository localRepository;
 88  
 
 89  
     /**
 90  
      * Used to retrieve the project metadata (POM) associated with each plugin dependency, to help
 91  
      * determine whether that plugin should be installed as a jar, or expanded into a directory.
 92  
      * 
 93  
      * @component
 94  
      */
 95  
     private MavenProjectBuilder projectBuilder;
 96  
 
 97  
     /**
 98  
      * Used to configure and retrieve an appropriate tool for extracting each resolved plugin 
 99  
      * dependency. It is conceivable that some resolved dependencies could be zip files, jar files,
 100  
      * or other types, so the manager approach is a convenient way to provide extensibility here.
 101  
      * 
 102  
      * @component
 103  
      */
 104  
     private ArchiverManager archiverManager;
 105  
 
 106  
     /**
 107  
      * Input handler, needed for comand line handling.
 108  
      * @component
 109  
      */
 110  
     private InputHandler inputHandler;
 111  
 
 112  
     // calculated below. Value will be ${eclipseDir}/plugins.
 113  
     private File pluginsDir;
 114  
 
 115  
     public InstallPluginsMojo()
 116  0
     {
 117  
         //used for plexus init.
 118  0
     }
 119  
 
 120  
     // used primarily for testing.
 121  
     protected InstallPluginsMojo( File eclipseDir, boolean overwrite, List dependencyArtifacts,
 122  
                                   String pluginDependencyTypes, ArtifactRepository localRepository,
 123  
                                   MavenProjectBuilder projectBuilder, ArchiverManager archiverManager,
 124  
                                   InputHandler inputHandler, Log log )
 125  0
     {
 126  0
         this.eclipseDir = eclipseDir;
 127  0
         this.overwrite = overwrite;
 128  0
         this.artifacts = dependencyArtifacts;
 129  0
         this.pluginDependencyTypes = pluginDependencyTypes;
 130  0
         this.localRepository = localRepository;
 131  0
         this.projectBuilder = projectBuilder;
 132  0
         this.archiverManager = archiverManager;
 133  0
         this.inputHandler = inputHandler;
 134  0
         setLog( log );
 135  0
     }
 136  
 
 137  
     /**
 138  
      * Traverse the list of resolved dependency artifacts. For each one having a type that is listed
 139  
      * in the pluginDependencyTypes parameter value, resolve the associated project metadata (POM),
 140  
      * and perform install(..) on that artifact.
 141  
      */
 142  
     public void execute()
 143  
         throws MojoExecutionException, MojoFailureException
 144  
     {
 145  0
         if ( eclipseDir == null )
 146  
         {
 147  0
             getLog().info( "Eclipse directory? " );
 148  
 
 149  
             String eclipseDirString;
 150  
             try
 151  
             {
 152  0
                 eclipseDirString = inputHandler.readLine();
 153  
             }
 154  0
             catch ( IOException e )
 155  
             {
 156  0
                 throw new MojoExecutionException( "Unable to read from standard input", e );
 157  0
             }
 158  
 
 159  0
             eclipseDir = new File( eclipseDirString );
 160  
         }
 161  
 
 162  0
         if ( eclipseDir.exists() && !eclipseDir.isDirectory() )
 163  
         {
 164  0
             throw new MojoFailureException( "Invalid Eclipse directory: " + eclipseDir );
 165  
         }
 166  0
         else if ( !eclipseDir.exists() )
 167  
         {
 168  0
             eclipseDir.mkdirs();
 169  
         }
 170  
 
 171  0
         for ( Iterator it = artifacts.iterator(); it.hasNext(); )
 172  
         {
 173  0
             Artifact artifact = (Artifact) it.next();
 174  
 
 175  0
             if ( pluginDependencyTypes.indexOf( artifact.getType() ) > -1 )
 176  
             {
 177  0
                 getLog().debug( "Processing Eclipse plugin dependency: " + artifact.getId() );
 178  
 
 179  
                 MavenProject project;
 180  
 
 181  
                 try
 182  
                 {
 183  0
                     project = projectBuilder.buildFromRepository( artifact, Collections.EMPTY_LIST, localRepository,
 184  
                                                                   true );
 185  
                 }
 186  0
                 catch ( ProjectBuildingException e )
 187  
                 {
 188  0
                     throw new MojoExecutionException( "Failed to load project metadata (POM) for: " + artifact.getId(),
 189  
                                                       e );
 190  0
                 }
 191  
 
 192  0
                 install( artifact, project );
 193  0
             }
 194  
             else
 195  
             {
 196  0
                 getLog()
 197  
                     .debug(
 198  
                             "Skipping dependency: " + artifact.getId()
 199  
                                 + ". Set pluginDependencyTypes with a comma-separated list of types to change this." );
 200  
             }
 201  0
         }
 202  0
     }
 203  
 
 204  
     /**
 205  
      * <p>Install the plugin into the eclipse instance's /plugins directory</p>
 206  
      * 
 207  
      * <ol>
 208  
      * <li>Determine whether the plugin should be extracted into a directory or not</li>
 209  
      * <li>If the plugin's target location exists, or overwrite is set to true:
 210  
      * <ol type="a">
 211  
      *   <li>if extract, ensure the plugin target location exists (mkdirs), and extract there.</li>
 212  
      *   <li>copy the plugin file from the local repository to the target location</li>
 213  
      * </ol>
 214  
      * 
 215  
      * <p>
 216  
      * Warn whenever a plugin will overwrite an existing file or directory, and emit an INFO message
 217  
      * whenever a plugin installation is skipped because of an existing file and overwrite == false.
 218  
      * </p>
 219  
      * 
 220  
      * @param artifact The plugin dependency as it has been resolved.
 221  
      * @param project The project metadata for the accompanying plugin-dependency artifact, used to
 222  
      * determine whether to install as a jar or as a directory
 223  
      * 
 224  
      * @throws MojoExecutionException In the event the plugin should be extracted but cannot, or the
 225  
      * file copy fails (in the event it should not be extracted)
 226  
      * @throws MojoFailureException In the event that the plugins target directory (inside the 
 227  
      * Eclipse instance directory) does not exist, or is not a directory.
 228  
      */
 229  
     private void install( Artifact artifact, MavenProject project )
 230  
         throws MojoExecutionException, MojoFailureException
 231  
     {
 232  0
         if ( pluginsDir == null )
 233  
         {
 234  0
             pluginsDir = new File( eclipseDir, "plugins" );
 235  
         }
 236  
 
 237  0
         if ( !pluginsDir.exists() || !pluginsDir.isDirectory() )
 238  
         {
 239  0
             throw new MojoFailureException( "Invalid Eclipse directory: " + eclipseDir
 240  
                 + " (plugins directory is missing or not a directory)." );
 241  
         }
 242  
 
 243  0
         boolean installAsJar = true;
 244  
 
 245  0
         Properties properties = project.getProperties();
 246  0
         if ( properties != null )
 247  
         {
 248  0
             installAsJar = !Boolean.valueOf( properties.getProperty( PROP_UNPACK_PLUGIN, "false" ) ).booleanValue();
 249  
         }
 250  
 
 251  0
         Attributes attributes = null;
 252  
         try
 253  
         {
 254  0
             JarFile jar = new JarFile( artifact.getFile() );
 255  0
             Manifest manifest = jar.getManifest();
 256  0
             attributes = manifest.getMainAttributes();
 257  
         }
 258  0
         catch ( IOException e )
 259  
         {
 260  0
             throw new MojoExecutionException( "Unable to read manifest of plugin "
 261  
                 + artifact.getFile().getAbsolutePath(), e );
 262  0
         }
 263  
 
 264  0
         String bundleVersion = attributes.getValue( "Bundle-Version" );
 265  0
         String pluginName = formatEclipsePluginName( artifact, bundleVersion );
 266  
 
 267  0
         File pluginFile = new File( pluginsDir, pluginName + ".jar" );
 268  0
         File pluginDir = new File( pluginsDir, pluginName );
 269  
 
 270  0
         boolean skipped = true;
 271  
 
 272  
         /* check if artifact is an OSGi bundle and ignore if not */
 273  0
         Object bundleName = attributes.getValue( "Bundle-Name" );
 274  0
         if ( bundleName == null )
 275  
         {
 276  0
             getLog().debug(
 277  
                             "Ignoring " + artifact.getArtifactId()
 278  
                                 + " as it is not an OSGi bundle (no Bundle-Name in manifest)" );
 279  0
             return;
 280  
         }
 281  
 
 282  0
         if ( overwrite )
 283  
         {
 284  0
             if ( pluginFile.exists() || pluginDir.exists() )
 285  
             {
 286  0
                 getLog().warn( "Overwriting old plugin with contents of: " + artifact.getId() );
 287  
 
 288  0
                 getLog().debug( "Removing old plugin from both: " + pluginFile + " and: " + pluginDir );
 289  
 
 290  
                 try
 291  
                 {
 292  0
                     FileUtils.forceDelete( pluginDir );
 293  0
                     FileUtils.forceDelete( pluginFile );
 294  
                 }
 295  0
                 catch ( IOException e )
 296  
                 {
 297  0
                     throw new MojoExecutionException( "Failed to remove old plugin from: " + pluginFile + " or: "
 298  
                         + pluginDir, e );
 299  0
                 }
 300  
 
 301  0
                 getLog().debug( "Removal of old plugin is complete; proceeding with plugin installation." );
 302  
             }
 303  
 
 304  0
             performFileOperations( installAsJar, artifact, pluginFile, pluginDir );
 305  
 
 306  0
             skipped = false;
 307  0
         }
 308  0
         else if ( installAsJar && !pluginFile.exists() )
 309  
         {
 310  0
             performFileOperations( installAsJar, artifact, pluginFile, pluginDir );
 311  
 
 312  0
             skipped = false;
 313  0
         }
 314  0
         else if ( !installAsJar && !pluginDir.exists() )
 315  
         {
 316  0
             performFileOperations( installAsJar, artifact, pluginFile, pluginDir );
 317  
 
 318  0
             skipped = false;
 319  
         }
 320  
 
 321  0
         if ( skipped )
 322  
         {
 323  0
             if ( installAsJar )
 324  
             {
 325  0
                 getLog().info(
 326  
                                "Skipping plugin installation for: " + artifact.getId() + "; file: " + pluginFile
 327  
                                    + " already exists. Set overwrite = true to override this." );
 328  0
             }
 329  0
             else if ( !installAsJar )
 330  
             {
 331  0
                 getLog().info(
 332  
                                "Skipping plugin installation for: " + artifact.getId() + "; directory: " + pluginDir
 333  
                                    + " already exists. Set overwrite = true to override this." );
 334  
             }
 335  
         }
 336  0
     }
 337  
 
 338  
     private void performFileOperations( boolean installAsJar, Artifact artifact, File pluginFile, File pluginDir )
 339  
         throws MojoExecutionException
 340  
     {
 341  0
         File artifactFile = artifact.getFile();
 342  
 
 343  0
         if ( installAsJar )
 344  
         {
 345  
             try
 346  
             {
 347  0
                 getLog().debug( "Copying: " + artifact.getId() + " to: " + pluginFile );
 348  
 
 349  0
                 FileUtils.copyFile( artifactFile, pluginFile );
 350  
             }
 351  0
             catch ( IOException e )
 352  
             {
 353  0
                 throw new MojoExecutionException( "Failed to copy Eclipse plugin: " + artifact.getId() + "\nfrom: "
 354  
                     + artifact.getFile() + "\nto: " + pluginFile, e );
 355  0
             }
 356  
         }
 357  
         else
 358  
         {
 359  
             try
 360  
             {
 361  0
                 getLog().debug( "Expanding: " + artifact.getId() + " into: " + pluginDir );
 362  
 
 363  0
                 pluginDir.mkdirs();
 364  
 
 365  0
                 UnArchiver unarchiver = archiverManager.getUnArchiver( artifactFile );
 366  
 
 367  0
                 unarchiver.setSourceFile( artifactFile );
 368  0
                 unarchiver.setDestDirectory( pluginDir );
 369  0
                 unarchiver.extract();
 370  
             }
 371  0
             catch ( NoSuchArchiverException e )
 372  
             {
 373  0
                 throw new MojoExecutionException( "Could not find unarchiver for: " + artifactFile, e );
 374  
             }
 375  0
             catch ( ArchiverException e )
 376  
             {
 377  0
                 throw new MojoExecutionException( "Could not extract: " + artifactFile, e );
 378  
             }
 379  0
             catch ( IOException e )
 380  
             {
 381  0
                 throw new MojoExecutionException( "Could not extract: " + artifactFile, e );
 382  0
             }
 383  
         }
 384  0
     }
 385  
 
 386  
     /**
 387  
      * <p>
 388  
      * Format the artifact information into an Eclipse-friendly plugin name. Currently, this is just:
 389  
      * <code>artifactId + "_" + bundle version</code> if bundle version is not null.
 390  
      * </p>
 391  
      */
 392  
     private String formatEclipsePluginName( Artifact artifact, String bundleVersion )
 393  
     {
 394  0
         if ( bundleVersion == null )
 395  
         {
 396  0
             return artifact.getArtifactId() + StringUtils.replace( artifact.getVersion(), "-", "." );
 397  
         }
 398  
         else
 399  
         {
 400  0
             return artifact.getArtifactId() + "_" + bundleVersion;
 401  
         }
 402  
     }
 403  
 
 404  
 }