View Javadoc

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.Map;
29  
30  import org.apache.maven.artifact.Artifact;
31  import org.apache.maven.artifact.ArtifactUtils;
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.plugin.AbstractMojo;
37  import org.apache.maven.plugin.MojoExecutionException;
38  import org.apache.maven.project.MavenProject;
39  
40  /**
41   * Installs the project artifacts of the main build into the local repository as a preparation to run the sub projects.
42   * More precisely, all artifacts of the project itself, all its locally reachable parent POMs and all its dependencies
43   * from the reactor will be installed to the local repository.
44   * 
45   * @goal install
46   * @phase pre-integration-test
47   * @requiresDependencyResolution runtime
48   * @since 1.2
49   * @author Paul Gier
50   * @author Benjamin Bentmann
51   * @version $Id: InstallMojo.java 698334 2008-09-23 20:16:00Z bentmann $
52   */
53  public class InstallMojo
54      extends AbstractMojo
55  {
56  
57      /**
58       * Maven artifact install component to copy artifacts to the local repository.
59       * 
60       * @component
61       */
62      private ArtifactInstaller installer;
63  
64      /**
65       * The component used to create artifacts.
66       * 
67       * @component
68       */
69      private ArtifactFactory artifactFactory;
70  
71      /**
72       * The component used to create artifacts.
73       * 
74       * @component
75       */
76      private ArtifactRepositoryFactory repositoryFactory;
77  
78      /**
79       * @parameter expression="${localRepository}"
80       * @required
81       * @readonly
82       */
83      private ArtifactRepository localRepository;
84  
85      /**
86       * The path to the local repository into which the project artifacts should be installed for the integration tests.
87       * If not set, the regular local repository will be used. To prevent soiling of your regular local repository with
88       * possibly broken artifacts, it is strongly recommended to use an isolated repository for the integration tests
89       * (e.g. <code>${project.build.directory}/it-repo</code>).
90       * 
91       * @parameter expression="${invoker.localRepositoryPath}"
92       */
93      private File localRepositoryPath;
94  
95      /**
96       * The current Maven project.
97       * 
98       * @parameter expression="${project}"
99       * @required
100      * @readonly
101      */
102     private MavenProject project;
103 
104     /**
105      * The set of Maven projects in the reactor build.
106      * 
107      * @parameter default-value="${reactorProjects}"
108      * @readonly
109      */
110     private Collection reactorProjects;
111 
112     /**
113      * Performs this mojo's tasks.
114      * 
115      * @throws MojoExecutionException If the artifacts could not be installed.
116      */
117     public void execute()
118         throws MojoExecutionException
119     {
120         ArtifactRepository testRepository = createTestRepository();
121 
122         installProjectArtifacts( project, testRepository );
123         installProjectParents( project, testRepository );
124         installProjectDependencies( project, reactorProjects, testRepository );
125     }
126 
127     /**
128      * Creates the local repository for the integration tests. If the user specified a custom repository location, the
129      * custom repository will have the same identifier, layout and policies as the real local repository. That means
130      * apart from the location, the custom repository will be indistinguishable from the real repository such that its
131      * usage is transparent to the integration tests.
132      * 
133      * @return The local repository for the integration tests, never <code>null</code>.
134      * @throws MojoExecutionException If the repository could not be created.
135      */
136     private ArtifactRepository createTestRepository()
137         throws MojoExecutionException
138     {
139         ArtifactRepository testRepository = localRepository;
140 
141         if ( localRepositoryPath != null )
142         {
143             try
144             {
145                 if ( !localRepositoryPath.exists() && !localRepositoryPath.mkdirs() )
146                 {
147                     throw new IOException( "Failed to create directory: " + localRepositoryPath );
148                 }
149 
150                 testRepository =
151                     repositoryFactory.createArtifactRepository( localRepository.getId(),
152                                                                 localRepositoryPath.toURL().toExternalForm(),
153                                                                 localRepository.getLayout(),
154                                                                 localRepository.getSnapshots(),
155                                                                 localRepository.getReleases() );
156             }
157             catch ( Exception e )
158             {
159                 throw new MojoExecutionException( "Failed to create local repository: " + localRepositoryPath, e );
160             }
161         }
162 
163         return testRepository;
164     }
165 
166     /**
167      * Installs the specified artifact to the local repository.
168      * 
169      * @param file The file associated with the artifact, must not be <code>null</code>. This is in most cases the value
170      *            of <code>artifact.getFile()</code> with the exception of the main artifact from a project with
171      *            packaging "pom". Projects with packaging "pom" have no main artifact file. They have however artifact
172      *            metadata (e.g. site descriptors) which needs to be installed.
173      * @param artifact The artifact to install, must not be <code>null</code>.
174      * @param testRepository The local repository to install the artifact to, must not be <code>null</code>.
175      * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).
176      */
177     private void installArtifact( File file, Artifact artifact, ArtifactRepository testRepository )
178         throws MojoExecutionException
179     {
180         try
181         {
182             if ( file == null )
183             {
184                 throw new IllegalStateException( "Artifact has no associated file: " + file );
185             }
186             if ( !file.isFile() )
187             {
188                 throw new IllegalStateException( "Artifact is not fully assembled: " + file );
189             }
190             installer.install( file, artifact, testRepository );
191         }
192         catch ( Exception e )
193         {
194             throw new MojoExecutionException( "Failed to install artifact: " + artifact, e );
195         }
196     }
197 
198     /**
199      * Installs the main artifact and any attached artifacts of the specified project to the local repository.
200      * 
201      * @param mvnProject The project whose artifacts should be installed, must not be <code>null</code>.
202      * @param testRepository The local repository to install the artifacts to, must not be <code>null</code>.
203      * @throws MojoExecutionException If any artifact could not be installed.
204      */
205     private void installProjectArtifacts( MavenProject mvnProject, ArtifactRepository testRepository )
206         throws MojoExecutionException
207     {
208         try
209         {
210             installProjectPom( mvnProject, testRepository );
211 
212             // Install the main project artifact (if the project has one, e.g. has no "pom" packaging)
213             Artifact mainArtifact = mvnProject.getArtifact();
214             if ( mainArtifact.getFile() != null )
215             {
216                 installArtifact( mainArtifact.getFile(), mainArtifact, testRepository );
217             }
218 
219             // Install any attached project artifacts
220             Collection attachedArtifacts = mvnProject.getAttachedArtifacts();
221             for ( Iterator artifactIter = attachedArtifacts.iterator(); artifactIter.hasNext(); )
222             {
223                 Artifact attachedArtifact = (Artifact) artifactIter.next();
224                 installArtifact( attachedArtifact.getFile(), attachedArtifact, testRepository );
225             }
226         }
227         catch ( Exception e )
228         {
229             throw new MojoExecutionException( "Failed to install project artifacts: " + mvnProject, e );
230         }
231     }
232 
233     /**
234      * Installs the (locally reachable) parent POMs of the specified project to the local repository. The parent POMs
235      * from the reactor must be installed or the forked IT builds will fail when using a clean repository.
236      * 
237      * @param mvnProject The project whose parent POMs should be installed, must not be <code>null</code>.
238      * @param testRepository The local repository to install the POMs to, must not be <code>null</code>.
239      * @throws MojoExecutionException If any POM could not be installed.
240      */
241     private void installProjectParents( MavenProject mvnProject, ArtifactRepository testRepository )
242         throws MojoExecutionException
243     {
244         try
245         {
246             for ( MavenProject parent = mvnProject.getParent(); parent != null; parent = parent.getParent() )
247             {
248                 if ( parent.getFile() == null )
249                 {
250                     break;
251                 }
252                 installProjectPom( parent, testRepository );
253             }
254         }
255         catch ( Exception e )
256         {
257             throw new MojoExecutionException( "Failed to install project parents: " + mvnProject, e );
258         }
259     }
260 
261     /**
262      * Installs the POM of the specified project to the local repository.
263      * 
264      * @param mvnProject The project whose POM should be installed, must not be <code>null</code>.
265      * @param testRepository The local repository to install the POM to, must not be <code>null</code>.
266      * @throws MojoExecutionException If the POM could not be installed.
267      */
268     private void installProjectPom( MavenProject mvnProject, ArtifactRepository testRepository )
269         throws MojoExecutionException
270     {
271         try
272         {
273             Artifact pomArtifact = null;
274             if ( "pom".equals( mvnProject.getPackaging() ) )
275             {
276                 pomArtifact = mvnProject.getArtifact();
277             }
278             if ( pomArtifact == null )
279             {
280                 pomArtifact =
281                     artifactFactory.createProjectArtifact( mvnProject.getGroupId(), mvnProject.getArtifactId(),
282                                                            mvnProject.getVersion() );
283             }
284             installArtifact( mvnProject.getFile(), pomArtifact, testRepository );
285         }
286         catch ( Exception e )
287         {
288             throw new MojoExecutionException( "Failed to install POM: " + mvnProject, e );
289         }
290     }
291 
292     /**
293      * Installs the dependent projects from the reactor to the local repository. The dependencies on other modules from
294      * the reactor must be installed or the forked IT builds will fail when using a clean repository.
295      * 
296      * @param mvnProject The project whose dependent projects should be installed, must not be <code>null</code>.
297      * @param reactorProjects The set of projects in the reactor build, must not be <code>null</code>.
298      * @param testRepository The local repository to install the POMs to, must not be <code>null</code>.
299      * @throws MojoExecutionException If any dependency could not be installed.
300      */
301     private void installProjectDependencies( MavenProject mvnProject, Collection reactorProjects,
302                                              ArtifactRepository testRepository )
303         throws MojoExecutionException
304     {
305         // index available reactor projects
306         Map projects = new HashMap();
307         for ( Iterator it = reactorProjects.iterator(); it.hasNext(); )
308         {
309             MavenProject reactorProject = (MavenProject) it.next();
310             String id = reactorProject.getGroupId() + ':' + reactorProject.getArtifactId();
311             projects.put( id, reactorProject );
312         }
313 
314         // collect transitive dependencies
315         Collection dependencies = new HashSet();
316         for ( Iterator it = mvnProject.getRuntimeArtifacts().iterator(); it.hasNext(); )
317         {
318             Artifact artifact = (Artifact) it.next();
319             String id = ArtifactUtils.versionlessKey( artifact );
320             
321             dependencies.add( id );
322         }
323 
324         // install dependencies
325         try
326         {
327             // install dependencies from reactor
328             for ( Iterator it = dependencies.iterator(); it.hasNext(); )
329             {
330                 String id = (String) it.next();
331                 MavenProject requiredProject = (MavenProject) projects.remove( id );
332                 if ( requiredProject != null )
333                 {
334                     it.remove();
335                     installProjectArtifacts( requiredProject, testRepository );
336                     installProjectParents( requiredProject, testRepository );
337                 }
338             }
339 
340             // install remaining dependencies from local repository
341             for ( Iterator it = mvnProject.getRuntimeArtifacts().iterator(); it.hasNext(); )
342             {
343                 Artifact artifact = (Artifact) it.next();
344                 String id = ArtifactUtils.versionlessKey( artifact );
345 
346                 if ( dependencies.contains( id ) )
347                 {
348                     File artifactFile = artifact.getFile();
349 
350                     installArtifact( artifactFile, artifact, testRepository );
351 
352                     Artifact pomArtifact =
353                         artifactFactory.createArtifact( artifact.getGroupId(), artifact.getArtifactId(),
354                                                         artifact.getVersion(), null, "pom" );
355 
356                     File pomFile = new File( localRepository.getBasedir(), localRepository.pathOf( pomArtifact ) );
357 
358                     if ( pomFile.exists() )
359                     {
360                         installArtifact( pomFile, pomArtifact, testRepository );
361                     }
362                 }
363             }
364         }
365         catch ( Exception e )
366         {
367             throw new MojoExecutionException( "Failed to install project dependencies: " + mvnProject, e );
368         }
369     }
370 
371 }