1 package org.apache.maven.artifact.ant;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.ant.util.AntBuildWriter;
24 import org.apache.maven.artifact.ant.util.AntTaskModified;
25 import org.apache.maven.artifact.ant.util.AntUtil;
26 import org.apache.maven.artifact.factory.ArtifactFactory;
27 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
28 import org.apache.maven.artifact.repository.ArtifactRepository;
29 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
30 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
31 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
32 import org.apache.maven.artifact.resolver.ArtifactResolver;
33 import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
34 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
35 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
36 import org.apache.maven.model.Dependency;
37 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
38 import org.apache.maven.project.artifact.MavenMetadataSource;
39 import org.apache.tools.ant.BuildException;
40 import org.apache.tools.ant.Project;
41 import org.apache.tools.ant.types.FileSet;
42 import org.apache.tools.ant.types.Path;
43 import org.codehaus.plexus.util.FileUtils;
44 import org.codehaus.plexus.util.StringUtils;
45
46 import java.io.File;
47 import java.io.IOException;
48 import java.util.Arrays;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.HashSet;
52 import java.util.Iterator;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Set;
56
57
58
59
60
61
62
63
64 public class DependenciesTask
65 extends AbstractArtifactWithRepositoryTask
66 {
67 private static final String[] SCOPES = { Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME,
68 Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM };
69
70 private static final Set<String> SCOPES_SET;
71 static
72 {
73 SCOPES_SET = new HashSet<String>( Arrays.asList( SCOPES ) );
74 }
75
76 public static final String DEFAULT_ANT_BUILD_FILE = "target/build-dependencies.xml";
77
78 private List<Dependency> dependencies = new ArrayList<Dependency>();
79
80
81
82
83 private String pathId;
84
85
86
87
88 private String filesetId;
89
90
91
92
93 private String sourcesFilesetId;
94
95
96
97
98 private String javadocFilesetId;
99
100
101
102
103
104 private String versionsId;
105
106
107
108
109
110 private String useScope;
111
112
113
114
115 private String scopes;
116
117
118
119
120 private String type;
121
122
123
124
125 private String pathType;
126
127
128
129
130 private String dependencyRefsBuildFile;
131
132
133
134
135 private boolean cacheDependencyRefs;
136
137
138
139
140 protected void doExecute()
141 {
142
143 if ( useScope != null && scopes != null )
144 {
145 throw new BuildException( "You cannot specify both useScope and scopes in the dependencies task." );
146 }
147
148 if ( getPom() != null && !this.dependencies.isEmpty() )
149 {
150 throw new BuildException( "You cannot specify both dependencies and a pom in the dependencies task" );
151 }
152
153
154 if ( isCacheDependencyRefs() )
155 {
156 if ( getDependencyRefsBuildFile() == null )
157 {
158 setDependencyRefsBuildFile( DEFAULT_ANT_BUILD_FILE );
159 }
160
161 if ( checkCachedDependencies() )
162 {
163 log( "Dependency refs loaded from file: " + getDependencyRefsBuildFile(), Project.MSG_VERBOSE );
164 return;
165 }
166 }
167
168 doExecuteResolution();
169 }
170
171 protected ArtifactResolutionResult doExecuteResolution()
172 {
173 ArtifactRepository localRepo = createLocalArtifactRepository();
174 log( "Using local repository: " + localRepo.getBasedir(), Project.MSG_VERBOSE );
175
176
177 ArtifactResolver resolver = (ArtifactResolver) lookup( ArtifactResolver.ROLE );
178 ArtifactFactory artifactFactory = (ArtifactFactory) lookup( ArtifactFactory.ROLE );
179 MavenMetadataSource metadataSource = (MavenMetadataSource) lookup( ArtifactMetadataSource.ROLE );
180
181 Pom pom = initializePom( localRepo );
182 if ( pom != null )
183 {
184 dependencies = pom.getDependencies();
185 }
186 else
187 {
188
189
190 pom = createDummyPom( localRepo );
191 }
192
193 if ( dependencies.isEmpty() )
194 {
195 log( "There were no dependencies specified", Project.MSG_WARN );
196 }
197 else
198 {
199
200 for ( Dependency dependency : dependencies )
201 {
202 String scope = dependency.getScope();
203
204 if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
205 {
206 if ( StringUtils.isBlank( dependency.getSystemPath() ) )
207 {
208 throw new BuildException( dependency.toString()
209 + " is defined with scope='system': systemPath attribute is required." );
210 }
211 }
212 else if ( ( scope != null ) && !SCOPES_SET.contains( scope ) )
213 {
214
215 log( "Unknown scope='" + scope + "' for " + dependency + ", supported scopes are: " + SCOPES_SET,
216 Project.MSG_WARN );
217 }
218 }
219 }
220
221 log( "Resolving dependencies...", Project.MSG_VERBOSE );
222
223 ArtifactResolutionResult result;
224
225 List<ArtifactRepository> remoteArtifactRepositories = createRemoteArtifactRepositories( pom.getRepositories() );
226
227 try
228 {
229 Set<Artifact> artifacts = MavenMetadataSource.createArtifacts( artifactFactory, dependencies, null, null, null );
230
231 Artifact pomArtifact = artifactFactory.createBuildArtifact( pom.getGroupId(), pom.getArtifactId(),
232 pom.getVersion(), pom.getPackaging() );
233
234 List<AntResolutionListener> listeners = Collections.singletonList( new AntResolutionListener( getProject() ) );
235
236 Map<String,Artifact> managedDependencies = pom.getMavenProject().getManagedVersionMap();
237
238 ArtifactFilter filter = null;
239 if ( useScope != null )
240 {
241 filter = new ScopeArtifactFilter( useScope );
242 }
243 if ( scopes != null )
244 {
245 filter = new SpecificScopesArtifactFilter( scopes );
246 }
247 if ( type != null )
248 {
249 ArtifactFilter typeArtifactFilter = new TypesArtifactFilter( type );
250 if ( filter != null )
251 {
252 AndArtifactFilter andFilter = new AndArtifactFilter();
253 andFilter.add( filter );
254 andFilter.add( typeArtifactFilter );
255 filter = andFilter;
256 }
257 else
258 {
259 filter = typeArtifactFilter;
260 }
261 }
262
263 result = resolver.resolveTransitively( artifacts, pomArtifact, managedDependencies, localRepo,
264 remoteArtifactRepositories, metadataSource, filter, listeners );
265 }
266 catch ( ArtifactResolutionException e )
267 {
268 throw new BuildException( "Unable to resolve artifact: " + e.getMessage(), e );
269 }
270 catch ( ArtifactNotFoundException e )
271 {
272 throw new BuildException( "Dependency not found: " + e.getMessage(), e );
273 }
274 catch ( InvalidDependencyVersionException e )
275 {
276 throw new BuildException( "Invalid dependency version: " + e.getMessage(), e );
277 }
278
279 FileSet dependencyFileSet = createFileSet();
280
281 FileSet sourcesFileSet = createFileSet();
282
283 FileSet javadocsFileSet = createFileSet();
284
285 Path dependencyPath = new Path( getProject() );
286
287 Set<String> versions = new HashSet<String>();
288
289 ArtifactFilter pathFilter;
290
291 if ( pathType != null )
292 {
293 pathFilter = new TypesArtifactFilter( pathType );
294 }
295 else
296 {
297 pathFilter = null;
298 }
299
300 for ( Iterator<Artifact> i = result.getArtifacts().iterator(); i.hasNext(); )
301 {
302 Artifact artifact = i.next();
303
304 addArtifactToResult( localRepo, artifact, dependencyFileSet, dependencyPath, pathFilter );
305
306 versions.add( artifact.getVersion() );
307
308 if ( sourcesFilesetId != null )
309 {
310 resolveSource( artifactFactory, resolver, remoteArtifactRepositories, localRepo,
311 artifact, "sources", sourcesFileSet );
312 }
313
314 if ( javadocFilesetId != null )
315 {
316 resolveSource( artifactFactory, resolver, remoteArtifactRepositories, localRepo,
317 artifact, "javadoc", javadocsFileSet );
318 }
319
320 }
321
322 defineFilesetReference( filesetId, dependencyFileSet );
323
324 defineFilesetReference( sourcesFilesetId, sourcesFileSet );
325
326 defineFilesetReference( javadocFilesetId, javadocsFileSet );
327
328 if ( pathId != null )
329 {
330 getProject().addReference( pathId, dependencyPath );
331 }
332
333 if ( versionsId != null )
334 {
335 String versionsValue = StringUtils.join( versions.iterator(), File.pathSeparator );
336 getProject().setNewProperty( versionsId, versionsValue );
337 }
338
339
340 if ( getDependencyRefsBuildFile() != null || this.isCacheDependencyRefs() )
341 {
342 if ( getDependencyRefsBuildFile() == null || getDependencyRefsBuildFile().equals( "default" ) )
343 {
344 setDependencyRefsBuildFile( DEFAULT_ANT_BUILD_FILE );
345 }
346 log( "Building ant file: " + getDependencyRefsBuildFile() );
347 AntBuildWriter antBuildWriter = new AntBuildWriter();
348 File antBuildFile = FileUtils.resolveFile( getProject().getBaseDir(), getDependencyRefsBuildFile() );
349 try
350 {
351 antBuildWriter.openAntBuild( antBuildFile, "maven-dependencies", "init-dependencies" );
352 antBuildWriter.openTarget( "init-dependencies" );
353 antBuildWriter.writeEcho( "Loading dependency paths from file: " + antBuildFile.getAbsolutePath() );
354
355 for ( Iterator<Artifact> i = result.getArtifacts().iterator(); i.hasNext(); )
356 {
357 Artifact artifact = i.next();
358 String conflictId = artifact.getDependencyConflictId();
359 antBuildWriter.writeProperty( conflictId, artifact.getFile().getAbsolutePath() );
360 FileSet singleArtifactFileSet = (FileSet) getProject().getReference( conflictId );
361 antBuildWriter.writeFileSet( singleArtifactFileSet, conflictId );
362 }
363
364 if ( pathId != null )
365 {
366 Path thePath = (Path) getProject().getReference( pathId );
367 antBuildWriter.writePath( thePath, pathId );
368 }
369
370 if ( filesetId != null )
371 {
372 antBuildWriter.writeFileSet( dependencyFileSet, filesetId );
373 }
374 if ( sourcesFilesetId != null )
375 {
376 antBuildWriter.writeFileSet( sourcesFileSet, sourcesFilesetId );
377 }
378 if ( javadocFilesetId != null )
379 {
380 antBuildWriter.writeFileSet( sourcesFileSet, javadocFilesetId );
381 }
382
383 String versionsList = getProject().getProperty( versionsId );
384 if ( versionsList != null )
385 {
386 antBuildWriter.writeProperty( versionsId, versionsList );
387 }
388
389 antBuildWriter.closeTarget();
390 antBuildWriter.closeAntBuild();
391 }
392 catch ( IOException e )
393 {
394 throw new BuildException ( "Unable to write ant build: " + e);
395 }
396 }
397
398 return result;
399 }
400
401
402
403
404
405
406 private boolean checkCachedDependencies()
407 {
408 File cacheBuildFile = FileUtils.resolveFile( getProject().getBaseDir(), getDependencyRefsBuildFile() );
409 if ( ! cacheBuildFile.exists() )
410 {
411 return false;
412 }
413
414 File antBuildFile = new File( getProject().getProperty( "ant.file" ) );
415 if ( antBuildFile.lastModified() > cacheBuildFile.lastModified() )
416 {
417 return false;
418 }
419
420 Pom pom = getPom();
421 if ( pom != null )
422 {
423 File pomFile = pom.getFile();
424 if ( pomFile != null && ( pomFile.lastModified() > cacheBuildFile.lastModified() ) )
425 {
426 return false;
427 }
428 }
429
430 return loadDependenciesFromAntBuildFile();
431 }
432
433
434
435
436
437
438 private boolean loadDependenciesFromAntBuildFile()
439 {
440 Project currentAntProject = getProject();
441
442
443 AntTaskModified dependenciesAntBuild = new AntTaskModified();
444 dependenciesAntBuild.setAntfile( getDependencyRefsBuildFile() );
445 dependenciesAntBuild.setProject( currentAntProject );
446 dependenciesAntBuild.execute();
447
448
449 Project cachedDepsProject = dependenciesAntBuild.getSavedNewProject();
450 AntUtil.copyProperties( cachedDepsProject, currentAntProject );
451 AntUtil.copyReferences( cachedDepsProject, currentAntProject );
452
453 return true;
454 }
455
456 private FileSet createFileSet()
457 {
458 FileSet fileSet = new FileSet();
459 fileSet.setProject( getProject() );
460 fileSet.setDir( getLocalRepository().getPath() );
461 return fileSet;
462 }
463
464 private void defineFilesetReference( String id, FileSet fileSet )
465 {
466 if ( id != null )
467 {
468 if ( !fileSet.hasPatterns() )
469 {
470 fileSet.createExclude().setName( "**/**" );
471 }
472 getProject().addReference( id, fileSet );
473 }
474 }
475
476 private void addArtifactToResult( ArtifactRepository localRepo, Artifact artifact,
477 FileSet toFileSet )
478 {
479 addArtifactToResult( localRepo, artifact, toFileSet, null, null );
480 }
481
482 private void addArtifactToResult( ArtifactRepository localRepo, Artifact artifact,
483 FileSet toFileSet, Path path, ArtifactFilter filter )
484 {
485 String filename = localRepo.pathOf( artifact );
486
487 toFileSet.createInclude().setName( filename );
488
489 getProject().setProperty( artifact.getDependencyConflictId(), artifact.getFile().getAbsolutePath() );
490
491 FileSet artifactFileSet = new FileSet();
492 artifactFileSet.setProject( getProject() );
493 artifactFileSet.setFile( artifact.getFile() );
494 getProject().addReference( artifact.getDependencyConflictId(), artifactFileSet );
495
496 if ( path != null && ( filter == null || filter.include( artifact ) ) )
497 {
498 path.addFileset( artifactFileSet );
499 }
500 }
501
502 private void resolveSource( ArtifactFactory artifactFactory, ArtifactResolver resolver,
503 List<ArtifactRepository> remoteArtifactRepositories, ArtifactRepository localRepo,
504 Artifact artifact, String classifier, FileSet sourcesFileSet )
505 {
506 Artifact sourceArtifact =
507 artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
508 artifact.getVersion(), "java-source", classifier );
509 try
510 {
511 resolver.resolve( sourceArtifact, remoteArtifactRepositories, localRepo );
512
513 addArtifactToResult( localRepo, sourceArtifact, sourcesFileSet );
514 }
515 catch ( ArtifactResolutionException e )
516 {
517 throw new BuildException( "Unable to resolve artifact: " + e.getMessage(), e );
518 }
519 catch ( ArtifactNotFoundException e )
520 {
521
522 }
523 }
524
525 public List<Dependency> getDependencies()
526 {
527 return dependencies;
528 }
529
530 public void addDependency( Dependency dependency )
531 {
532 dependencies.add( dependency );
533 }
534
535 public String getPathId()
536 {
537 return pathId;
538 }
539
540 public void setPathId( String pathId )
541 {
542 this.pathId = pathId;
543 }
544
545 public String getFilesetId()
546 {
547 return filesetId;
548 }
549
550 public void setSourcesFilesetId( String filesetId )
551 {
552 this.sourcesFilesetId = filesetId;
553 }
554
555 public String getSourcesFilesetId()
556 {
557 return sourcesFilesetId;
558 }
559
560 public void setJavadocFilesetId( String filesetId )
561 {
562 this.javadocFilesetId = filesetId;
563 }
564
565 public String getJavadocFilesetId()
566 {
567 return javadocFilesetId;
568 }
569
570 public void setFilesetId( String filesetId )
571 {
572 this.filesetId = filesetId;
573 }
574
575 public String getVersionsId()
576 {
577 return versionsId;
578 }
579
580 public void setVersionsId( String versionsId )
581 {
582 this.versionsId = versionsId;
583 }
584
585 public void setVerbose( boolean verbose )
586 {
587 getProject().log( "Option \"verbose\" is deprecated. Please use the standard Ant -v option.",
588 Project.MSG_WARN );
589 }
590
591
592
593
594
595
596
597 public void setUseScope( String useScope )
598 {
599 this.useScope = useScope;
600 }
601
602 public void setType( String type )
603 {
604 this.type = type;
605 }
606
607 public void setPathType( String pathType )
608 {
609 this.pathType = pathType;
610 }
611
612 public String getScopes()
613 {
614 return scopes;
615 }
616
617
618
619
620
621
622 public void setScopes( String scopes )
623 {
624 this.scopes = scopes;
625 }
626
627
628
629
630
631 public void setAddArtifactFileSetRefs( boolean addArtifactFileSetRefs )
632 {
633 this.log( "Parameter addArtifactFileSetRefs is deprecated. A fileset ref is always created " +
634 "for each dependency.", Project.MSG_WARN );
635 }
636
637 public String getDependencyRefsBuildFile()
638 {
639 return dependencyRefsBuildFile;
640 }
641
642 public void setDependencyRefsBuildFile( String dependencyRefsBuildFile )
643 {
644 this.dependencyRefsBuildFile = dependencyRefsBuildFile;
645 }
646
647 public boolean isCacheDependencyRefs()
648 {
649 return cacheDependencyRefs;
650 }
651
652 public void setCacheDependencyRefs( boolean cacheDependencyRefs )
653 {
654 this.cacheDependencyRefs = cacheDependencyRefs;
655 }
656 }