Coverage Report - org.apache.maven.plugin.invoker.InstallMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
InstallMojo
0%
0/129
0%
0/58
5.273
 
 1  
 package org.apache.maven.plugin.invoker;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *  http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.util.Collection;
 25  
 import java.util.HashMap;
 26  
 import java.util.HashSet;
 27  
 import java.util.Iterator;
 28  
 import java.util.LinkedHashSet;
 29  
 import java.util.Map;
 30  
 
 31  
 import org.apache.maven.artifact.Artifact;
 32  
 import org.apache.maven.artifact.factory.ArtifactFactory;
 33  
 import org.apache.maven.artifact.installer.ArtifactInstaller;
 34  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 35  
 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
 36  
 import org.apache.maven.model.Model;
 37  
 import org.apache.maven.model.Parent;
 38  
 import org.apache.maven.plugin.AbstractMojo;
 39  
 import org.apache.maven.plugin.MojoExecutionException;
 40  
 import org.apache.maven.project.MavenProject;
 41  
 import org.codehaus.plexus.util.FileUtils;
 42  
 
 43  
 /**
 44  
  * Installs the project artifacts of the main build into the local repository as a preparation to run the sub projects.
 45  
  * More precisely, all artifacts of the project itself, all its locally reachable parent POMs and all its dependencies
 46  
  * from the reactor will be installed to the local repository.
 47  
  * 
 48  
  * @goal install
 49  
  * @phase pre-integration-test
 50  
  * @requiresDependencyResolution runtime
 51  
  * @since 1.2
 52  
  * @author Paul Gier
 53  
  * @author Benjamin Bentmann
 54  
  * @version $Id: InstallMojo.java 814226 2009-09-12 20:01:59Z bentmann $
 55  
  */
 56  0
 public class InstallMojo
 57  
     extends AbstractMojo
 58  
 {
 59  
 
 60  
     /**
 61  
      * Maven artifact install component to copy artifacts to the local repository.
 62  
      * 
 63  
      * @component
 64  
      */
 65  
     private ArtifactInstaller installer;
 66  
 
 67  
     /**
 68  
      * The component used to create artifacts.
 69  
      * 
 70  
      * @component
 71  
      */
 72  
     private ArtifactFactory artifactFactory;
 73  
 
 74  
     /**
 75  
      * The component used to create artifacts.
 76  
      * 
 77  
      * @component
 78  
      */
 79  
     private ArtifactRepositoryFactory repositoryFactory;
 80  
 
 81  
     /**
 82  
      * @parameter expression="${localRepository}"
 83  
      * @required
 84  
      * @readonly
 85  
      */
 86  
     private ArtifactRepository localRepository;
 87  
 
 88  
     /**
 89  
      * The path to the local repository into which the project artifacts should be installed for the integration tests.
 90  
      * If not set, the regular local repository will be used. To prevent soiling of your regular local repository with
 91  
      * possibly broken artifacts, it is strongly recommended to use an isolated repository for the integration tests
 92  
      * (e.g. <code>${project.build.directory}/it-repo</code>).
 93  
      * 
 94  
      * @parameter expression="${invoker.localRepositoryPath}"
 95  
      */
 96  
     private File localRepositoryPath;
 97  
 
 98  
     /**
 99  
      * The current Maven project.
 100  
      * 
 101  
      * @parameter expression="${project}"
 102  
      * @required
 103  
      * @readonly
 104  
      */
 105  
     private MavenProject project;
 106  
 
 107  
     /**
 108  
      * The set of Maven projects in the reactor build.
 109  
      * 
 110  
      * @parameter default-value="${reactorProjects}"
 111  
      * @readonly
 112  
      */
 113  
     private Collection reactorProjects;
 114  
 
 115  
     /**
 116  
      * A flag used to disable the installation procedure. This is primarily intended for usage from the command line to
 117  
      * occasionally adjust the build.
 118  
      * 
 119  
      * @parameter expression="${invoker.skip}" default-value="false"
 120  
      * @since 1.4
 121  
      */
 122  
     private boolean skipInstallation;
 123  
 
 124  
     /**
 125  
      * The identifiers of already installed artifacts, used to avoid multiple installation of the same artifact.
 126  
      */
 127  
     private Collection installedArtifacts;
 128  
 
 129  
     /**
 130  
      * The identifiers of already copied artifacts, used to avoid multiple installation of the same artifact.
 131  
      */
 132  
     private Collection copiedArtifacts;
 133  
 
 134  
     /**
 135  
      * Performs this mojo's tasks.
 136  
      * 
 137  
      * @throws MojoExecutionException If the artifacts could not be installed.
 138  
      */
 139  
     public void execute()
 140  
         throws MojoExecutionException
 141  
     {
 142  0
         if ( skipInstallation )
 143  
         {
 144  0
             getLog().info( "Skipping artifact installation per configuration." );
 145  0
             return;
 146  
         }
 147  
 
 148  0
         ArtifactRepository testRepository = createTestRepository();
 149  
 
 150  0
         installedArtifacts = new HashSet();
 151  0
         copiedArtifacts = new HashSet();
 152  
 
 153  0
         installProjectDependencies( project, reactorProjects, testRepository );
 154  0
         installProjectParents( project, testRepository );
 155  0
         installProjectArtifacts( project, testRepository );
 156  0
     }
 157  
 
 158  
     /**
 159  
      * Creates the local repository for the integration tests. If the user specified a custom repository location, the
 160  
      * custom repository will have the same identifier, layout and policies as the real local repository. That means
 161  
      * apart from the location, the custom repository will be indistinguishable from the real repository such that its
 162  
      * usage is transparent to the integration tests.
 163  
      * 
 164  
      * @return The local repository for the integration tests, never <code>null</code>.
 165  
      * @throws MojoExecutionException If the repository could not be created.
 166  
      */
 167  
     private ArtifactRepository createTestRepository()
 168  
         throws MojoExecutionException
 169  
     {
 170  0
         ArtifactRepository testRepository = localRepository;
 171  
 
 172  0
         if ( localRepositoryPath != null )
 173  
         {
 174  
             try
 175  
             {
 176  0
                 if ( !localRepositoryPath.exists() && !localRepositoryPath.mkdirs() )
 177  
                 {
 178  0
                     throw new IOException( "Failed to create directory: " + localRepositoryPath );
 179  
                 }
 180  
 
 181  0
                 testRepository =
 182  
                     repositoryFactory.createArtifactRepository( localRepository.getId(),
 183  
                                                                 localRepositoryPath.toURL().toExternalForm(),
 184  
                                                                 localRepository.getLayout(),
 185  
                                                                 localRepository.getSnapshots(),
 186  
                                                                 localRepository.getReleases() );
 187  
             }
 188  0
             catch ( Exception e )
 189  
             {
 190  0
                 throw new MojoExecutionException( "Failed to create local repository: " + localRepositoryPath, e );
 191  0
             }
 192  
         }
 193  
 
 194  0
         return testRepository;
 195  
     }
 196  
 
 197  
     /**
 198  
      * Installs the specified artifact to the local repository. Note: This method should only be used for artifacts that
 199  
      * originate from the current (reactor) build. Artifacts that have been grabbed from the user's local repository
 200  
      * should be installed to the test repository via {@link #copyArtifact(File, Artifact, ArtifactRepository)}.
 201  
      * 
 202  
      * @param file The file associated with the artifact, must not be <code>null</code>. This is in most cases the value
 203  
      *            of <code>artifact.getFile()</code> with the exception of the main artifact from a project with
 204  
      *            packaging "pom". Projects with packaging "pom" have no main artifact file. They have however artifact
 205  
      *            metadata (e.g. site descriptors) which needs to be installed.
 206  
      * @param artifact The artifact to install, must not be <code>null</code>.
 207  
      * @param testRepository The local repository to install the artifact to, must not be <code>null</code>.
 208  
      * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).
 209  
      */
 210  
     private void installArtifact( File file, Artifact artifact, ArtifactRepository testRepository )
 211  
         throws MojoExecutionException
 212  
     {
 213  
         try
 214  
         {
 215  0
             if ( file == null )
 216  
             {
 217  0
                 throw new IllegalStateException( "Artifact has no associated file: " + file );
 218  
             }
 219  0
             if ( !file.isFile() )
 220  
             {
 221  0
                 throw new IllegalStateException( "Artifact is not fully assembled: " + file );
 222  
             }
 223  
 
 224  0
             if ( installedArtifacts.add( artifact.getId() ) )
 225  
             {
 226  0
                 installer.install( file, artifact, testRepository );
 227  
             }
 228  
             else
 229  
             {
 230  0
                 getLog().debug( "Not re-installing " + artifact + ", " + file );
 231  
             }
 232  
         }
 233  0
         catch ( Exception e )
 234  
         {
 235  0
             throw new MojoExecutionException( "Failed to install artifact: " + artifact, e );
 236  0
         }
 237  0
     }
 238  
 
 239  
     /**
 240  
      * Installs the specified artifact to the local repository. This method serves basically the same purpose as
 241  
      * {@link #installArtifact(File, Artifact, ArtifactRepository)} but is meant for artifacts that have been resolved
 242  
      * from the user's local repository (and not the current build outputs). The subtle difference here is that
 243  
      * artifacts from the repository have already undergone transformations and these manipulations should not be redone
 244  
      * by the artifact installer. For this reason, this method performs plain copy operations to install the artifacts.
 245  
      * 
 246  
      * @param file The file associated with the artifact, must not be <code>null</code>.
 247  
      * @param artifact The artifact to install, must not be <code>null</code>.
 248  
      * @param testRepository The local repository to install the artifact to, must not be <code>null</code>.
 249  
      * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).
 250  
      */
 251  
     private void copyArtifact( File file, Artifact artifact, ArtifactRepository testRepository )
 252  
         throws MojoExecutionException
 253  
     {
 254  
         try
 255  
         {
 256  0
             if ( file == null )
 257  
             {
 258  0
                 throw new IllegalStateException( "Artifact has no associated file: " + file );
 259  
             }
 260  0
             if ( !file.isFile() )
 261  
             {
 262  0
                 throw new IllegalStateException( "Artifact is not fully assembled: " + file );
 263  
             }
 264  
 
 265  0
             if ( copiedArtifacts.add( artifact.getId() ) )
 266  
             {
 267  0
                 File destination = new File( testRepository.getBasedir(), testRepository.pathOf( artifact ) );
 268  
 
 269  0
                 getLog().debug( "Installing " + file + " to " + destination );
 270  
 
 271  0
                 copyFileIfDifferent( file, destination );
 272  
 
 273  0
                 MetadataUtils.createMetadata( destination, artifact );
 274  
             }
 275  
             else
 276  
             {
 277  0
                 getLog().debug( "Not re-installing " + artifact + ", " + file );
 278  
             }
 279  
         }
 280  0
         catch ( Exception e )
 281  
         {
 282  0
             throw new MojoExecutionException( "Failed to stage artifact: " + artifact, e );
 283  0
         }
 284  0
     }
 285  
 
 286  
     private void copyFileIfDifferent( File src, File dst )
 287  
         throws IOException
 288  
     {
 289  0
         if ( src.lastModified() != dst.lastModified() || src.length() != dst.length() )
 290  
         {
 291  0
             FileUtils.copyFile( src, dst );
 292  0
             dst.setLastModified( src.lastModified() );
 293  
         }
 294  0
     }
 295  
 
 296  
     /**
 297  
      * Installs the main artifact and any attached artifacts of the specified project to the local repository.
 298  
      * 
 299  
      * @param mvnProject The project whose artifacts should be installed, must not be <code>null</code>.
 300  
      * @param testRepository The local repository to install the artifacts to, must not be <code>null</code>.
 301  
      * @throws MojoExecutionException If any artifact could not be installed.
 302  
      */
 303  
     private void installProjectArtifacts( MavenProject mvnProject, ArtifactRepository testRepository )
 304  
         throws MojoExecutionException
 305  
     {
 306  
         try
 307  
         {
 308  
             // Install POM (usually attached as metadata but that happens only as a side effect of the Install Plugin)
 309  0
             installProjectPom( mvnProject, testRepository );
 310  
 
 311  
             // Install the main project artifact (if the project has one, e.g. has no "pom" packaging)
 312  0
             Artifact mainArtifact = mvnProject.getArtifact();
 313  0
             if ( mainArtifact.getFile() != null )
 314  
             {
 315  0
                 installArtifact( mainArtifact.getFile(), mainArtifact, testRepository );
 316  
             }
 317  
 
 318  
             // Install any attached project artifacts
 319  0
             Collection attachedArtifacts = mvnProject.getAttachedArtifacts();
 320  0
             for ( Iterator artifactIter = attachedArtifacts.iterator(); artifactIter.hasNext(); )
 321  
             {
 322  0
                 Artifact attachedArtifact = (Artifact) artifactIter.next();
 323  0
                 installArtifact( attachedArtifact.getFile(), attachedArtifact, testRepository );
 324  
             }
 325  
         }
 326  0
         catch ( Exception e )
 327  
         {
 328  0
             throw new MojoExecutionException( "Failed to install project artifacts: " + mvnProject, e );
 329  0
         }
 330  0
     }
 331  
 
 332  
     /**
 333  
      * Installs the (locally reachable) parent POMs of the specified project to the local repository. The parent POMs
 334  
      * from the reactor must be installed or the forked IT builds will fail when using a clean repository.
 335  
      * 
 336  
      * @param mvnProject The project whose parent POMs should be installed, must not be <code>null</code>.
 337  
      * @param testRepository The local repository to install the POMs to, must not be <code>null</code>.
 338  
      * @throws MojoExecutionException If any POM could not be installed.
 339  
      */
 340  
     private void installProjectParents( MavenProject mvnProject, ArtifactRepository testRepository )
 341  
         throws MojoExecutionException
 342  
     {
 343  
         try
 344  
         {
 345  0
             for ( MavenProject parent = mvnProject.getParent(); parent != null; parent = parent.getParent() )
 346  
             {
 347  0
                 if ( parent.getFile() == null )
 348  
                 {
 349  0
                     copyParentPoms( parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), testRepository );
 350  0
                     break;
 351  
                 }
 352  0
                 installProjectPom( parent, testRepository );
 353  
             }
 354  
         }
 355  0
         catch ( Exception e )
 356  
         {
 357  0
             throw new MojoExecutionException( "Failed to install project parents: " + mvnProject, e );
 358  0
         }
 359  0
     }
 360  
 
 361  
     /**
 362  
      * Installs the POM of the specified project to the local repository.
 363  
      * 
 364  
      * @param mvnProject The project whose POM should be installed, must not be <code>null</code>.
 365  
      * @param testRepository The local repository to install the POM to, must not be <code>null</code>.
 366  
      * @throws MojoExecutionException If the POM could not be installed.
 367  
      */
 368  
     private void installProjectPom( MavenProject mvnProject, ArtifactRepository testRepository )
 369  
         throws MojoExecutionException
 370  
     {
 371  
         try
 372  
         {
 373  0
             Artifact pomArtifact = null;
 374  0
             if ( "pom".equals( mvnProject.getPackaging() ) )
 375  
             {
 376  0
                 pomArtifact = mvnProject.getArtifact();
 377  
             }
 378  0
             if ( pomArtifact == null )
 379  
             {
 380  0
                 pomArtifact =
 381  
                     artifactFactory.createProjectArtifact( mvnProject.getGroupId(), mvnProject.getArtifactId(),
 382  
                                                            mvnProject.getVersion() );
 383  
             }
 384  0
             installArtifact( mvnProject.getFile(), pomArtifact, testRepository );
 385  
         }
 386  0
         catch ( Exception e )
 387  
         {
 388  0
             throw new MojoExecutionException( "Failed to install POM: " + mvnProject, e );
 389  0
         }
 390  0
     }
 391  
 
 392  
     /**
 393  
      * Installs the dependent projects from the reactor to the local repository. The dependencies on other modules from
 394  
      * the reactor must be installed or the forked IT builds will fail when using a clean repository.
 395  
      * 
 396  
      * @param mvnProject The project whose dependent projects should be installed, must not be <code>null</code>.
 397  
      * @param reactorProjects The set of projects in the reactor build, must not be <code>null</code>.
 398  
      * @param testRepository The local repository to install the POMs to, must not be <code>null</code>.
 399  
      * @throws MojoExecutionException If any dependency could not be installed.
 400  
      */
 401  
     private void installProjectDependencies( MavenProject mvnProject, Collection reactorProjects,
 402  
                                              ArtifactRepository testRepository )
 403  
         throws MojoExecutionException
 404  
     {
 405  
         // index available reactor projects
 406  0
         Map projects = new HashMap();
 407  0
         for ( Iterator it = reactorProjects.iterator(); it.hasNext(); )
 408  
         {
 409  0
             MavenProject reactorProject = (MavenProject) it.next();
 410  
 
 411  0
             String projectId =
 412  
                 reactorProject.getGroupId() + ':' + reactorProject.getArtifactId() + ':' + reactorProject.getVersion();
 413  
 
 414  0
             projects.put( projectId, reactorProject );
 415  
         }
 416  
 
 417  
         // group transitive dependencies (even those that don't contribute to the class path like POMs) ...
 418  0
         Collection artifacts = mvnProject.getArtifacts();
 419  
         // ... into dependencies that were resolved from reactor projects ...
 420  0
         Collection dependencyProjects = new LinkedHashSet();
 421  
         // ... and those that were resolved from the (local) repo
 422  0
         Collection dependencyArtifacts = new LinkedHashSet();
 423  0
         for ( Iterator it = artifacts.iterator(); it.hasNext(); )
 424  
         {
 425  0
             Artifact artifact = (Artifact) it.next();
 426  
 
 427  
             // workaround for MNG-2961 to ensure the base version does not contain a timestamp
 428  0
             artifact.isSnapshot();
 429  
 
 430  0
             String projectId = artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion();
 431  
 
 432  0
             if ( projects.containsKey( projectId ) )
 433  
             {
 434  0
                 dependencyProjects.add( projectId );
 435  
             }
 436  
             else
 437  
             {
 438  0
                 dependencyArtifacts.add( artifact );
 439  
             }
 440  
         }
 441  
 
 442  
         // install dependencies
 443  
         try
 444  
         {
 445  
             // copy dependencies that where resolved from the local repo
 446  0
             for ( Iterator it = dependencyArtifacts.iterator(); it.hasNext(); )
 447  
             {
 448  0
                 Artifact artifact = (Artifact) it.next();
 449  
 
 450  0
                 Artifact depArtifact =
 451  
                     artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
 452  
                                                                   artifact.getBaseVersion(), artifact.getType(),
 453  
                                                                   artifact.getClassifier() );
 454  
 
 455  0
                 File artifactFile = artifact.getFile();
 456  
 
 457  0
                 Artifact pomArtifact =
 458  
                     artifactFactory.createProjectArtifact( depArtifact.getGroupId(), depArtifact.getArtifactId(),
 459  
                                                            depArtifact.getBaseVersion() );
 460  
 
 461  0
                 File pomFile = new File( localRepository.getBasedir(), localRepository.pathOf( pomArtifact ) );
 462  
 
 463  0
                 if ( pomFile.isFile() )
 464  
                 {
 465  0
                     if ( !pomArtifact.getId().equals( depArtifact.getId() ) )
 466  
                     {
 467  0
                         copyArtifact( pomFile, pomArtifact, testRepository );
 468  
                     }
 469  0
                     copyParentPoms( pomFile, testRepository );
 470  
                 }
 471  
 
 472  0
                 copyArtifact( artifactFile, depArtifact, testRepository );
 473  
             }
 474  
 
 475  
             // install dependencies that were resolved from the reactor
 476  0
             for ( Iterator it = dependencyProjects.iterator(); it.hasNext(); )
 477  
             {
 478  0
                 String projectId = (String) it.next();
 479  
 
 480  0
                 MavenProject dependencyProject = (MavenProject) projects.get( projectId );
 481  
 
 482  0
                 installProjectArtifacts( dependencyProject, testRepository );
 483  0
                 installProjectParents( dependencyProject, testRepository );
 484  
             }
 485  
         }
 486  0
         catch ( Exception e )
 487  
         {
 488  0
             throw new MojoExecutionException( "Failed to install project dependencies: " + mvnProject, e );
 489  0
         }
 490  0
     }
 491  
 
 492  
     /**
 493  
      * Installs all parent POMs of the specified POM file that are available in the local repository.
 494  
      * 
 495  
      * @param pomFile The path to the POM file whose parents should be installed, must not be <code>null</code>.
 496  
      * @param testRepository The local repository to install the POMs to, must not be <code>null</code>.
 497  
      * @throws MojoExecutionException If any (existing) parent POM could not be installed.
 498  
      */
 499  
     private void copyParentPoms( File pomFile, ArtifactRepository testRepository )
 500  
         throws MojoExecutionException
 501  
     {
 502  0
         Model model = PomUtils.loadPom( pomFile );
 503  0
         Parent parent = model.getParent();
 504  0
         if ( parent != null )
 505  
         {
 506  0
             copyParentPoms( parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), testRepository );
 507  
         }
 508  0
     }
 509  
 
 510  
     /**
 511  
      * Installs the specified POM and all its parent POMs to the local repository.
 512  
      * 
 513  
      * @param groupId The group id of the POM which should be installed, must not be <code>null</code>.
 514  
      * @param artifactId The artifact id of the POM which should be installed, must not be <code>null</code>.
 515  
      * @param version The version of the POM which should be installed, must not be <code>null</code>.
 516  
      * @param testRepository The local repository to install the POMs to, must not be <code>null</code>.
 517  
      * @throws MojoExecutionException If any (existing) parent POM could not be installed.
 518  
      */
 519  
     private void copyParentPoms( String groupId, String artifactId, String version, ArtifactRepository testRepository )
 520  
         throws MojoExecutionException
 521  
     {
 522  0
         Artifact pomArtifact = artifactFactory.createProjectArtifact( groupId, artifactId, version );
 523  
 
 524  0
         if ( installedArtifacts.contains( pomArtifact.getId() ) || copiedArtifacts.contains( pomArtifact.getId() ) )
 525  
         {
 526  0
             getLog().debug( "Not re-installing " + pomArtifact );
 527  0
             return;
 528  
         }
 529  
 
 530  0
         File pomFile = new File( localRepository.getBasedir(), localRepository.pathOf( pomArtifact ) );
 531  0
         if ( pomFile.isFile() )
 532  
         {
 533  0
             copyArtifact( pomFile, pomArtifact, testRepository );
 534  0
             copyParentPoms( pomFile, testRepository );
 535  
         }
 536  0
     }
 537  
 
 538  
 }