1 package org.apache.maven.resolver.internal.ant.tasks;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Map;
32
33 import org.apache.maven.resolver.internal.ant.AntRepoSys;
34 import org.apache.maven.resolver.internal.ant.Names;
35 import org.apache.maven.resolver.internal.ant.types.Dependencies;
36 import org.apache.maven.resolver.internal.ant.types.Pom;
37 import org.apache.tools.ant.BuildException;
38 import org.apache.tools.ant.Project;
39 import org.apache.tools.ant.ProjectComponent;
40 import org.apache.tools.ant.types.FileSet;
41 import org.apache.tools.ant.types.Reference;
42 import org.apache.tools.ant.types.resources.FileResource;
43 import org.apache.tools.ant.types.resources.Resources;
44 import org.apache.tools.ant.util.FileUtils;
45 import org.eclipse.aether.RepositorySystem;
46 import org.eclipse.aether.RepositorySystemSession;
47 import org.eclipse.aether.artifact.Artifact;
48 import org.eclipse.aether.graph.DependencyFilter;
49 import org.eclipse.aether.graph.DependencyNode;
50 import org.eclipse.aether.resolution.ArtifactRequest;
51 import org.eclipse.aether.resolution.ArtifactResolutionException;
52 import org.eclipse.aether.resolution.ArtifactResult;
53 import org.eclipse.aether.util.artifact.SubArtifact;
54 import org.eclipse.aether.util.filter.ScopeDependencyFilter;
55
56
57
58 public class Resolve
59 extends AbstractResolvingTask
60 {
61
62 private List<ArtifactConsumer> consumers = new ArrayList<ArtifactConsumer>();
63
64 private boolean failOnMissingAttachments;
65
66 public void setFailOnMissingAttachments( boolean failOnMissingAttachments )
67 {
68 this.failOnMissingAttachments = failOnMissingAttachments;
69 }
70
71 public Path createPath()
72 {
73 Path path = new Path();
74 consumers.add( path );
75 return path;
76 }
77
78 public Files createFiles()
79 {
80 Files files = new Files();
81 consumers.add( files );
82 return files;
83 }
84
85 public Props createProperties()
86 {
87 Props props = new Props();
88 consumers.add( props );
89 return props;
90 }
91
92 private void validate()
93 {
94 for ( ArtifactConsumer consumer : consumers )
95 {
96 consumer.validate();
97 }
98
99 Pom pom = AntRepoSys.getInstance( getProject() ).getDefaultPom();
100 if ( dependencies == null && pom != null )
101 {
102 log( "Using default pom for dependency resolution (" + pom.toString() + ")", Project.MSG_INFO );
103 dependencies = new Dependencies();
104 dependencies.setProject( getProject() );
105 getProject().addReference( Names.ID_DEFAULT_POM, pom );
106 dependencies.setPomRef( new Reference( getProject(), Names.ID_DEFAULT_POM ) );
107 }
108
109 if ( dependencies != null )
110 {
111 dependencies.validate( this );
112 }
113 else
114 {
115 throw new BuildException( "No <dependencies> set for resolution" );
116 }
117 }
118
119 @Override
120 public void execute()
121 throws BuildException
122 {
123 validate();
124
125
126 AntRepoSys sys = AntRepoSys.getInstance( getProject() );
127
128 RepositorySystemSession session = sys.getSession( this, localRepository );
129 RepositorySystem system = sys.getSystem();
130 log( "Using local repository " + session.getLocalRepository(), Project.MSG_VERBOSE );
131
132 DependencyNode root = collectDependencies().getRoot();
133 root.accept( new DependencyGraphLogger( this ) );
134
135 Map<String, Group> groups = new HashMap<String, Group>();
136 for ( ArtifactConsumer consumer : consumers )
137 {
138 String classifier = consumer.getClassifier();
139 Group group = groups.get( classifier );
140 if ( group == null )
141 {
142 group = new Group( classifier );
143 groups.put( classifier, group );
144 }
145 group.add( consumer );
146 }
147
148 for ( Group group : groups.values() )
149 {
150 group.createRequests( root );
151 }
152
153 log( "Resolving artifacts", Project.MSG_INFO );
154
155 for ( Group group : groups.values() )
156 {
157 List<ArtifactResult> results;
158 try
159 {
160 results = system.resolveArtifacts( session, group.getRequests() );
161 }
162 catch ( ArtifactResolutionException e )
163 {
164 if ( !group.isAttachments() || failOnMissingAttachments )
165 {
166 throw new BuildException( "Could not resolve artifacts: " + e.getMessage(), e );
167 }
168 results = e.getResults();
169 for ( ArtifactResult result : results )
170 {
171 if ( result.isMissing() )
172 {
173 log( "Ignoring missing attachment " + result.getRequest().getArtifact(), Project.MSG_VERBOSE );
174 }
175 else if ( !result.isResolved() )
176 {
177 throw new BuildException( "Could not resolve artifacts: " + e.getMessage(), e );
178 }
179 }
180 }
181
182 group.processResults( results, session );
183 }
184 }
185
186
187
188 public abstract static class ArtifactConsumer
189 extends ProjectComponent
190 {
191
192 private DependencyFilter filter;
193
194 public boolean accept( org.eclipse.aether.graph.DependencyNode node, List<DependencyNode> parents )
195 {
196 return filter == null || filter.accept( node, parents );
197 }
198
199 public String getClassifier()
200 {
201 return null;
202 }
203
204 public void validate()
205 {
206
207 }
208
209 public abstract void process( Artifact artifact, RepositorySystemSession session );
210
211 public void setScopes( String scopes )
212 {
213 if ( filter != null )
214 {
215 throw new BuildException( "You must not specify both 'scopes' and 'classpath'" );
216 }
217
218 Collection<String> included = new HashSet<String>();
219 Collection<String> excluded = new HashSet<String>();
220
221 String[] split = scopes.split( "[, ]" );
222 for ( String scope : split )
223 {
224 scope = scope.trim();
225 Collection<String> dst;
226 if ( scope.startsWith( "-" ) || scope.startsWith( "!" ) )
227 {
228 dst = excluded;
229 scope = scope.substring( 1 );
230 }
231 else
232 {
233 dst = included;
234 }
235 if ( scope.length() > 0 )
236 {
237 dst.add( scope );
238 }
239 }
240
241 filter = new ScopeDependencyFilter( included, excluded );
242 }
243
244 public void setClasspath( String classpath )
245 {
246 if ( "compile".equals( classpath ) )
247 {
248 setScopes( "provided,system,compile" );
249 }
250 else if ( "runtime".equals( classpath ) )
251 {
252 setScopes( "compile,runtime" );
253 }
254 else if ( "test".equals( classpath ) )
255 {
256 setScopes( "provided,system,compile,runtime,test" );
257 }
258 else
259 {
260 throw new BuildException( "The classpath '" + classpath + "' is not defined"
261 + ", must be one of 'compile', 'runtime' or 'test'" );
262 }
263 }
264
265 }
266
267
268
269 public class Path
270 extends ArtifactConsumer
271 {
272
273 private String refid;
274
275 private org.apache.tools.ant.types.Path path;
276
277 public void setRefId( String refId )
278 {
279 this.refid = refId;
280 }
281
282 public void validate()
283 {
284 if ( refid == null )
285 {
286 throw new BuildException( "You must specify the 'refid' for the path" );
287 }
288 }
289
290 public void process( Artifact artifact, RepositorySystemSession session )
291 {
292 if ( path == null )
293 {
294 path = new org.apache.tools.ant.types.Path( getProject() );
295 getProject().addReference( refid, path );
296 }
297 path.setLocation( artifact.getFile() );
298 }
299
300 }
301
302
303
304 public class Files
305 extends ArtifactConsumer
306 {
307
308 private static final String DEFAULT_LAYOUT = Layout.GID_DIRS + "/" + Layout.AID + "/" + Layout.BVER + "/"
309 + Layout.AID + "-" + Layout.VER + "-" + Layout.CLS + "." + Layout.EXT;
310
311 private String refid;
312
313 private String classifier;
314
315 private File dir;
316
317 private Layout layout;
318
319 private FileSet fileset;
320
321 private Resources resources;
322
323 public void setRefId( String refId )
324 {
325 this.refid = refId;
326 }
327
328 public String getClassifier()
329 {
330 return classifier;
331 }
332
333 public void setAttachments( String attachments )
334 {
335 if ( "sources".equals( attachments ) )
336 {
337 classifier = "*-sources";
338 }
339 else if ( "javadoc".equals( attachments ) )
340 {
341 classifier = "*-javadoc";
342 }
343 else
344 {
345 throw new BuildException( "The attachment type '" + attachments
346 + "' is not defined, must be one of 'sources' or 'javadoc'" );
347 }
348 }
349
350 public void setDir( File dir )
351 {
352 this.dir = dir;
353 if ( dir != null && layout == null )
354 {
355 layout = new Layout( DEFAULT_LAYOUT );
356 }
357 }
358
359 public void setLayout( String layout )
360 {
361 this.layout = new Layout( layout );
362 }
363
364 public void validate()
365 {
366 if ( refid == null && dir == null )
367 {
368 throw new BuildException( "You must either specify the 'refid' for the resource collection"
369 + " or a 'dir' to copy the files to" );
370 }
371 if ( dir == null && layout != null )
372 {
373 throw new BuildException( "You must not specify a 'layout' unless 'dir' is also specified" );
374 }
375 }
376
377 public void process( Artifact artifact, RepositorySystemSession session )
378 {
379 if ( dir != null )
380 {
381 if ( refid != null && fileset == null )
382 {
383 fileset = new FileSet();
384 fileset.setProject( getProject() );
385 fileset.setDir( dir );
386 getProject().addReference( refid, fileset );
387 }
388
389 String path = layout.getPath( artifact );
390
391 if ( fileset != null )
392 {
393 fileset.createInclude().setName( path );
394 }
395
396 File src = artifact.getFile();
397 File dst = new File( dir, path );
398
399 if ( src.lastModified() != dst.lastModified() || src.length() != dst.length() )
400 {
401 try
402 {
403 Resolve.this.log( "Copy " + src + " to " + dst, Project.MSG_VERBOSE );
404 FileUtils.getFileUtils().copyFile( src, dst, null, true, true );
405 }
406 catch ( IOException e )
407 {
408 throw new BuildException( "Failed to copy artifact file " + src + " to " + dst + ": "
409 + e.getMessage(), e );
410 }
411 }
412 else
413 {
414 Resolve.this.log( "Omit to copy " + src + " to " + dst + ", seems unchanged", Project.MSG_VERBOSE );
415 }
416 }
417 else
418 {
419 if ( resources == null )
420 {
421 resources = new Resources();
422 resources.setProject( getProject() );
423 getProject().addReference( refid, resources );
424 }
425
426 FileResource resource = new FileResource( artifact.getFile() );
427 resource.setBaseDir( session.getLocalRepository().getBasedir() );
428 resource.setProject( getProject() );
429 resources.add( resource );
430 }
431 }
432
433 }
434
435
436
437 public class Props
438 extends ArtifactConsumer
439 {
440
441 private String prefix;
442
443 private String classifier;
444
445 public void setPrefix( String prefix )
446 {
447 this.prefix = prefix;
448 }
449
450 public String getClassifier()
451 {
452 return classifier;
453 }
454
455 public void setAttachments( String attachments )
456 {
457 if ( "sources".equals( attachments ) )
458 {
459 classifier = "*-sources";
460 }
461 else if ( "javadoc".equals( attachments ) )
462 {
463 classifier = "*-javadoc";
464 }
465 else
466 {
467 throw new BuildException( "The attachment type '" + attachments
468 + "' is not defined, must be one of 'sources' or 'javadoc'" );
469 }
470 }
471
472 public void process( Artifact artifact, RepositorySystemSession session )
473 {
474 StringBuilder buffer = new StringBuilder( 256 );
475 if ( prefix != null && prefix.length() > 0 )
476 {
477 buffer.append( prefix );
478 if ( !prefix.endsWith( "." ) )
479 {
480 buffer.append( '.' );
481 }
482 }
483 buffer.append( artifact.getGroupId() );
484 buffer.append( ':' );
485 buffer.append( artifact.getArtifactId() );
486 buffer.append( ':' );
487 buffer.append( artifact.getExtension() );
488 if ( artifact.getClassifier().length() > 0 )
489 {
490 buffer.append( ':' );
491 buffer.append( artifact.getClassifier() );
492 }
493
494 String path = artifact.getFile().getAbsolutePath();
495
496 getProject().setProperty( buffer.toString(), path );
497 }
498
499 }
500
501 private static class Group
502 {
503
504 private String classifier;
505
506 private List<ArtifactConsumer> consumers = new ArrayList<ArtifactConsumer>();
507
508 private List<ArtifactRequest> requests = new ArrayList<ArtifactRequest>();
509
510 Group( String classifier )
511 {
512 this.classifier = classifier;
513 }
514
515 public boolean isAttachments()
516 {
517 return classifier != null;
518 }
519
520 public void add( ArtifactConsumer consumer )
521 {
522 consumers.add( consumer );
523 }
524
525 public void createRequests( DependencyNode node )
526 {
527 createRequests( node, new LinkedList<DependencyNode>() );
528 }
529
530 private void createRequests( DependencyNode node, LinkedList<DependencyNode> parents )
531 {
532 if ( node.getDependency() != null )
533 {
534 for ( ArtifactConsumer consumer : consumers )
535 {
536 if ( consumer.accept( node, parents ) )
537 {
538 ArtifactRequest request = new ArtifactRequest( node );
539 if ( classifier != null )
540 {
541 request.setArtifact( new SubArtifact( request.getArtifact(), classifier, "jar" ) );
542 }
543 requests.add( request );
544 break;
545 }
546 }
547 }
548
549 parents.addFirst( node );
550
551 for ( DependencyNode child : node.getChildren() )
552 {
553 createRequests( child, parents );
554 }
555
556 parents.removeFirst();
557 }
558
559 public List<ArtifactRequest> getRequests()
560 {
561 return requests;
562 }
563
564 public void processResults( List<ArtifactResult> results, RepositorySystemSession session )
565 {
566 for ( ArtifactResult result : results )
567 {
568 if ( !result.isResolved() )
569 {
570 continue;
571 }
572 for ( ArtifactConsumer consumer : consumers )
573 {
574 if ( consumer.accept( result.getRequest().getDependencyNode(),
575 Collections.<DependencyNode>emptyList() ) )
576 {
577 consumer.process( result.getArtifact(), session );
578 }
579 }
580 }
581 }
582
583 }
584
585 }