1 package org.apache.maven.plugin.dependency.fromConfiguration;
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.util.Collections;
24 import java.util.List;
25 import java.util.Set;
26
27 import org.apache.maven.artifact.Artifact;
28 import org.apache.maven.artifact.ArtifactUtils;
29 import org.apache.maven.artifact.repository.ArtifactRepository;
30 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
31 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
32 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
33 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
34 import org.apache.maven.artifact.versioning.VersionRange;
35 import org.apache.maven.model.Dependency;
36 import org.apache.maven.plugin.MojoExecutionException;
37 import org.apache.maven.plugin.dependency.AbstractDependencyMojo;
38 import org.apache.maven.plugin.dependency.utils.DependencyUtil;
39 import org.apache.maven.plugin.dependency.utils.filters.ArtifactItemFilter;
40 import org.apache.maven.project.MavenProject;
41 import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
42 import org.codehaus.plexus.util.FileUtils;
43 import org.codehaus.plexus.util.StringUtils;
44
45 /**
46 * Abstract Parent class used by mojos that get Artifact information from the plugin configuration as an ArrayList of
47 * ArtifactItems
48 *
49 * @see ArtifactItem
50 * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
51 * @version $Id: AbstractFromConfigurationMojo.java 1143035 2011-07-05 12:54:20Z stephenc $
52 */
53 public abstract class AbstractFromConfigurationMojo
54 extends AbstractDependencyMojo
55 {
56 /**
57 * Skip the execution
58 *
59 * @optional
60 * @since 2.2
61 * @parameter expression="${mdep.skip}" default-value="false"
62 */
63 private boolean skip;
64
65 /**
66 * Default location used for mojo unless overridden in ArtifactItem
67 *
68 * @parameter expression="${outputDirectory}" default-value="${project.build.directory}/dependency"
69 * @optional
70 * @since 1.0
71 */
72 private File outputDirectory;
73
74 /**
75 * Overwrite release artifacts
76 *
77 * @optional
78 * @since 1.0
79 * @parameter expression="${mdep.overWriteReleases}" default-value="false"
80 */
81 private boolean overWriteReleases;
82
83 /**
84 * Overwrite snapshot artifacts
85 *
86 * @optional
87 * @since 1.0
88 * @parameter expression="${mdep.overWriteSnapshots}" default-value="false"
89 */
90 private boolean overWriteSnapshots;
91
92 /**
93 * Overwrite if newer
94 *
95 * @optional
96 * @since 2.0
97 * @parameter expression="${mdep.overIfNewer}" default-value="true"
98 */
99 private boolean overWriteIfNewer;
100
101 /**
102 * To search for artifacts within the reactor and ensure consistent behaviour between Maven 2 and Maven 3.
103 *
104 * @parameter expression="${reactorProjects}"
105 * @required
106 * @readonly
107 */
108 protected List<MavenProject> reactorProjects;
109
110 /**
111 * Collection of ArtifactItems to work on. (ArtifactItem contains groupId, artifactId, version, type, classifier,
112 * location, destFileName, markerFile and overwrite.) See <a href="./usage.html">Usage</a> for details.
113 *
114 * @parameter
115 * @required
116 * @since 1.0
117 */
118 private List<ArtifactItem> artifactItems;
119
120 /**
121 * To look up ArtifactRepository implementation
122 *
123 * @component
124 * @readonly
125 */
126 private ArtifactRepositoryFactory artifactRepositoryManager;
127
128 /**
129 * Path to override default local repository during plugin's execution. To remove all downloaded artifacts as part
130 * of the build, set this value to a location under your project's target directory
131 *
132 * @parameter
133 * @since 2.2
134 */
135 private File localRepositoryDirectory;
136
137 /**
138 * To host and cache localRepositoryDirectory
139 */
140 private ArtifactRepository overrideLocalRepository;
141
142 abstract ArtifactItemFilter getMarkedArtifactFilter( ArtifactItem item );
143
144 /**
145 * Preprocesses the list of ArtifactItems. This method defaults the outputDirectory if not set and creates the
146 * output Directory if it doesn't exist.
147 *
148 * @param removeVersion remove the version from the filename.
149 * @return An ArrayList of preprocessed ArtifactItems
150 * @throws MojoExecutionException with a message if an error occurs.
151 * @see ArtifactItem
152 */
153 protected List<ArtifactItem> getProcessedArtifactItems( boolean removeVersion )
154 throws MojoExecutionException
155 {
156 if ( artifactItems == null || artifactItems.size() < 1 )
157 {
158 throw new MojoExecutionException( "There are no artifactItems configured." );
159 }
160
161 for ( ArtifactItem artifactItem : artifactItems )
162 {
163 this.getLog().info( "Configured Artifact: " + artifactItem.toString() );
164
165 if ( artifactItem.getOutputDirectory() == null )
166 {
167 artifactItem.setOutputDirectory( this.outputDirectory );
168 }
169 artifactItem.getOutputDirectory().mkdirs();
170
171 // make sure we have a version.
172 if ( StringUtils.isEmpty( artifactItem.getVersion() ) )
173 {
174 fillMissingArtifactVersion( artifactItem );
175 }
176
177 artifactItem.setArtifact( this.getArtifact( artifactItem ) );
178
179 if ( StringUtils.isEmpty( artifactItem.getDestFileName() ) )
180 {
181 artifactItem.setDestFileName( DependencyUtil.getFormattedFileName( artifactItem.getArtifact(),
182 removeVersion ) );
183 }
184
185 try
186 {
187 artifactItem.setNeedsProcessing( checkIfProcessingNeeded( artifactItem ) );
188 }
189 catch ( ArtifactFilterException e )
190 {
191 throw new MojoExecutionException( e.getMessage(), e );
192 }
193 }
194 return artifactItems;
195 }
196
197 private boolean checkIfProcessingNeeded( ArtifactItem item )
198 throws MojoExecutionException, ArtifactFilterException
199 {
200 boolean result = false;
201 if ( StringUtils.equalsIgnoreCase( item.getOverWrite(), "true" ) )
202 {
203 result = true;
204 }
205 else
206 {
207 ArtifactItemFilter filter = getMarkedArtifactFilter( item );
208 result = filter.isArtifactIncluded( item );
209 }
210 return result;
211 }
212
213 /**
214 * Resolves the Artifact from the remote repository if necessary. If no version is specified, it will be retrieved
215 * from the dependency list or from the DependencyManagement section of the pom.
216 *
217 * @param artifactItem containing information about artifact from plugin configuration.
218 * @return Artifact object representing the specified file.
219 * @throws MojoExecutionException with a message if the version can't be found in DependencyManagement.
220 */
221 protected Artifact getArtifact( ArtifactItem artifactItem )
222 throws MojoExecutionException
223 {
224 Artifact artifact;
225
226 // Map managedVersions = createManagedVersionMap( factory,
227 // project.getId(), project.getDependencyManagement() );
228 VersionRange vr;
229 try
230 {
231 vr = VersionRange.createFromVersionSpec( artifactItem.getVersion() );
232 }
233 catch ( InvalidVersionSpecificationException e1 )
234 {
235 // TODO Auto-generated catch block
236 e1.printStackTrace();
237 vr = VersionRange.createFromVersion( artifactItem.getVersion() );
238 }
239
240 if ( StringUtils.isEmpty( artifactItem.getClassifier() ) )
241 {
242 artifact =
243 factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
244 artifactItem.getType(), null, Artifact.SCOPE_COMPILE );
245 }
246 else
247 {
248 artifact =
249 factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
250 artifactItem.getType(), artifactItem.getClassifier(),
251 Artifact.SCOPE_COMPILE );
252 }
253
254 // Maven 3 will search the reactor for the artifact but Maven 2 does not
255 // to keep consistent behaviour, we search the reactor ourselves.
256 Artifact result = getArtifactFomReactor( artifact );
257 if ( result != null )
258 {
259 return result;
260 }
261 try
262 {
263 // mdep-50 - rolledback for now because it's breaking some functionality.
264 /*
265 * List listeners = new ArrayList(); Set theSet = new HashSet(); theSet.add( artifact );
266 * ArtifactResolutionResult artifactResolutionResult = artifactCollector.collect( theSet, project
267 * .getArtifact(), managedVersions, this.local, project.getRemoteArtifactRepositories(),
268 * artifactMetadataSource, null, listeners ); Iterator iter =
269 * artifactResolutionResult.getArtifactResolutionNodes().iterator(); while ( iter.hasNext() ) {
270 * ResolutionNode node = (ResolutionNode) iter.next(); artifact = node.getArtifact(); }
271 */
272
273 resolver.resolve( artifact, remoteRepos, getLocal() );
274 }
275 catch ( ArtifactResolutionException e )
276 {
277 throw new MojoExecutionException( "Unable to resolve artifact.", e );
278 }
279 catch ( ArtifactNotFoundException e )
280 {
281 throw new MojoExecutionException( "Unable to find artifact.", e );
282 }
283
284 return artifact;
285 }
286
287 /**
288 * Checks to see if the specified artifact is available from the reactor.
289 * @param artifact The artifact we are looking for.
290 * @return The resolved artifact that is the same as the one we were looking for or <code>null</code> if one could
291 * not be found.
292 */
293 private Artifact getArtifactFomReactor( Artifact artifact )
294 {
295 // check project dependencies first off
296 for ( Artifact a : (Set<Artifact>) project.getArtifacts() )
297 {
298 if ( equals( artifact, a ) && hasFile( a ) )
299 {
300 return a;
301 }
302 }
303 // check reactor projects
304 for ( MavenProject p : reactorProjects == null ? Collections.<MavenProject>emptyList() : reactorProjects )
305 {
306 // check the main artifact
307 if ( equals( artifact, p.getArtifact() ) && hasFile( p.getArtifact() ) )
308 {
309 return p.getArtifact();
310 }
311 // check any side artifacts
312 for ( Artifact a : (List<Artifact>) p.getAttachedArtifacts() )
313 {
314 if ( equals( artifact, a ) && hasFile( a ) )
315 {
316 return a;
317 }
318 }
319 }
320 // not available
321 return null;
322 }
323
324 /**
325 * Returns <code>true</code> if the artifact has a file.
326 * @param artifact the artifact (may be null)
327 * @return <code>true</code> if and only if the artifact is non-null and has a file.
328 */
329 private static boolean hasFile( Artifact artifact )
330 {
331 return artifact != null && artifact.getFile() != null && artifact.getFile().isFile();
332 }
333
334 /**
335 * Null-safe compare of two artifacts based on groupId, artifactId, version, type and classifier.
336 * @param a the first artifact.
337 * @param b the second artifact.
338 * @return <code>true</code> if and only if the two artifacts have the same groupId, artifactId, version,
339 * type and classifier.
340 */
341 private static boolean equals( Artifact a, Artifact b )
342 {
343 return a == b
344 || !( a == null || b == null )
345 && StringUtils.equals( a.getGroupId(), b.getGroupId() )
346 && StringUtils.equals( a.getArtifactId(), b.getArtifactId() )
347 && StringUtils.equals( a.getVersion(), b.getVersion() )
348 && StringUtils.equals( a.getType(), b.getType() )
349 && StringUtils.equals( a.getClassifier(), b.getClassifier() );
350 }
351
352 /**
353 * Tries to find missing version from dependency list and dependency management. If found, the artifact is updated
354 * with the correct version. It will first look for an exact match on artifactId/groupId/classifier/type and if it
355 * doesn't find a match, it will try again looking for artifactId and groupId only.
356 *
357 * @param artifact representing configured file.
358 * @throws MojoExecutionException
359 */
360 private void fillMissingArtifactVersion( ArtifactItem artifact )
361 throws MojoExecutionException
362 {
363 List<Dependency> deps = project.getDependencies();
364 List<Dependency> depMngt = project.getDependencyManagement() == null
365 ? Collections.<Dependency>emptyList()
366 : project.getDependencyManagement().getDependencies();
367
368 if ( !findDependencyVersion( artifact, deps, false )
369 && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, false ) )
370 && !findDependencyVersion( artifact, deps, true )
371 && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, true ) ) )
372 {
373 throw new MojoExecutionException( "Unable to find artifact version of " + artifact.getGroupId() + ":"
374 + artifact.getArtifactId() + " in either dependency list or in project's dependency management." );
375 }
376 }
377
378 /**
379 * Tries to find missing version from a list of dependencies. If found, the artifact is updated with the correct
380 * version.
381 *
382 * @param artifact representing configured file.
383 * @param dependencies list of dependencies to search.
384 * @param looseMatch only look at artifactId and groupId
385 * @return the found dependency
386 */
387 private boolean findDependencyVersion( ArtifactItem artifact, List<Dependency> dependencies, boolean looseMatch )
388 {
389 for ( Dependency dependency : dependencies )
390 {
391 if ( StringUtils.equals( dependency.getArtifactId(), artifact.getArtifactId() )
392 && StringUtils.equals( dependency.getGroupId(), artifact.getGroupId() )
393 && ( looseMatch || StringUtils.equals( dependency.getClassifier(), artifact.getClassifier() ) )
394 && ( looseMatch || StringUtils.equals( dependency.getType(), artifact.getType() ) ) )
395 {
396 artifact.setVersion( dependency.getVersion() );
397
398 return true;
399 }
400 }
401
402 return false;
403 }
404
405 /*
406 * private Map createManagedVersionMap( ArtifactFactory artifactFactory, String projectId, DependencyManagement
407 * dependencyManagement ) throws MojoExecutionException { Map map; if ( dependencyManagement != null &&
408 * dependencyManagement.getDependencies() != null ) { map = new HashMap(); for ( Iterator i =
409 * dependencyManagement.getDependencies().iterator(); i.hasNext(); ) { Dependency d = (Dependency) i.next(); try {
410 * VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() ); Artifact artifact =
411 * artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(), d
412 * .getClassifier(), d.getScope(), d .isOptional() ); map.put( d.getManagementKey(), artifact ); } catch (
413 * InvalidVersionSpecificationException e ) { throw new MojoExecutionException( "Unable to parse version", e ); } }
414 * } else { map = Collections.EMPTY_MAP; } return map; }
415 */
416
417 /**
418 * Override the base to
419 *
420 * @return Returns the local.
421 */
422 protected ArtifactRepository getLocal()
423 {
424 if ( this.overrideLocalRepository != null )
425 {
426 return this.overrideLocalRepository;
427 }
428
429 ArtifactRepository local = super.getLocal();
430
431 if ( this.localRepositoryDirectory != null )
432 {
433 // create a new local repo using existing layout, snapshots, and releases policy
434 String url = "file://" + this.localRepositoryDirectory.getAbsolutePath();
435 this.overrideLocalRepository =
436 artifactRepositoryManager.createArtifactRepository( local.getId(), url, local.getLayout(),
437 local.getSnapshots(), local.getReleases() );
438
439 this.getLog().debug( "Execution local repository is at: " + this.overrideLocalRepository.getBasedir() );
440 }
441 else
442 {
443 this.overrideLocalRepository = local;
444 }
445
446 return this.overrideLocalRepository;
447 }
448
449 /**
450 * @return Returns the artifactItems.
451 */
452 public List<ArtifactItem> getArtifactItems()
453 {
454 return this.artifactItems;
455 }
456
457 /**
458 * @param theArtifactItems The artifactItems to set.
459 */
460 public void setArtifactItems( List<ArtifactItem> theArtifactItems )
461 {
462 this.artifactItems = theArtifactItems;
463 }
464
465 /**
466 * @return Returns the outputDirectory.
467 */
468 public File getOutputDirectory()
469 {
470 return this.outputDirectory;
471 }
472
473 /**
474 * @param theOutputDirectory The outputDirectory to set.
475 */
476 public void setOutputDirectory( File theOutputDirectory )
477 {
478 this.outputDirectory = theOutputDirectory;
479 }
480
481 /**
482 * @return Returns the overWriteIfNewer.
483 */
484 public boolean isOverWriteIfNewer()
485 {
486 return this.overWriteIfNewer;
487 }
488
489 /**
490 * @param theOverWriteIfNewer The overWriteIfNewer to set.
491 */
492 public void setOverWriteIfNewer( boolean theOverWriteIfNewer )
493 {
494 this.overWriteIfNewer = theOverWriteIfNewer;
495 }
496
497 /**
498 * @return Returns the overWriteReleases.
499 */
500 public boolean isOverWriteReleases()
501 {
502 return this.overWriteReleases;
503 }
504
505 /**
506 * @param theOverWriteReleases The overWriteReleases to set.
507 */
508 public void setOverWriteReleases( boolean theOverWriteReleases )
509 {
510 this.overWriteReleases = theOverWriteReleases;
511 }
512
513 /**
514 * @return Returns the overWriteSnapshots.
515 */
516 public boolean isOverWriteSnapshots()
517 {
518 return this.overWriteSnapshots;
519 }
520
521 /**
522 * @param theOverWriteSnapshots The overWriteSnapshots to set.
523 */
524 public void setOverWriteSnapshots( boolean theOverWriteSnapshots )
525 {
526 this.overWriteSnapshots = theOverWriteSnapshots;
527 }
528
529 public void setLocalRepositoryDirectory( File localRepositoryDirectory )
530 {
531 this.localRepositoryDirectory = localRepositoryDirectory;
532 }
533
534 public boolean isSkip()
535 {
536 return skip;
537 }
538
539 public void setSkip( boolean skip )
540 {
541 this.skip = skip;
542 }
543 }