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 }