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 File file = artifact.getFile();
298 path.add( new FileResource( file.getParentFile(), file.getName() ) );
299 }
300
301 }
302
303
304
305 public class Files
306 extends ArtifactConsumer
307 {
308
309 private static final String DEFAULT_LAYOUT = Layout.GID_DIRS + "/" + Layout.AID + "/" + Layout.BVER + "/"
310 + Layout.AID + "-" + Layout.VER + "-" + Layout.CLS + "." + Layout.EXT;
311
312 private String refid;
313
314 private String classifier;
315
316 private File dir;
317
318 private Layout layout;
319
320 private FileSet fileset;
321
322 private Resources resources;
323
324 public void setRefId( String refId )
325 {
326 this.refid = refId;
327 }
328
329 public String getClassifier()
330 {
331 return classifier;
332 }
333
334 public void setAttachments( String attachments )
335 {
336 if ( "sources".equals( attachments ) )
337 {
338 classifier = "*-sources";
339 }
340 else if ( "javadoc".equals( attachments ) )
341 {
342 classifier = "*-javadoc";
343 }
344 else
345 {
346 throw new BuildException( "The attachment type '" + attachments
347 + "' is not defined, must be one of 'sources' or 'javadoc'" );
348 }
349 }
350
351 public void setDir( File dir )
352 {
353 this.dir = dir;
354 if ( dir != null && layout == null )
355 {
356 layout = new Layout( DEFAULT_LAYOUT );
357 }
358 }
359
360 public void setLayout( String layout )
361 {
362 this.layout = new Layout( layout );
363 }
364
365 public void validate()
366 {
367 if ( refid == null && dir == null )
368 {
369 throw new BuildException( "You must either specify the 'refid' for the resource collection"
370 + " or a 'dir' to copy the files to" );
371 }
372 if ( dir == null && layout != null )
373 {
374 throw new BuildException( "You must not specify a 'layout' unless 'dir' is also specified" );
375 }
376 }
377
378 public void process( Artifact artifact, RepositorySystemSession session )
379 {
380 if ( dir != null )
381 {
382 if ( refid != null && fileset == null )
383 {
384 fileset = new FileSet();
385 fileset.setProject( getProject() );
386 fileset.setDir( dir );
387 getProject().addReference( refid, fileset );
388 }
389
390 String path = layout.getPath( artifact );
391
392 if ( fileset != null )
393 {
394 fileset.createInclude().setName( path );
395 }
396
397 File src = artifact.getFile();
398 File dst = new File( dir, path );
399
400 if ( src.lastModified() != dst.lastModified() || src.length() != dst.length() )
401 {
402 try
403 {
404 Resolve.this.log( "Copy " + src + " to " + dst, Project.MSG_VERBOSE );
405 FileUtils.getFileUtils().copyFile( src, dst, null, true, true );
406 }
407 catch ( IOException e )
408 {
409 throw new BuildException( "Failed to copy artifact file " + src + " to " + dst + ": "
410 + e.getMessage(), e );
411 }
412 }
413 else
414 {
415 Resolve.this.log( "Omit to copy " + src + " to " + dst + ", seems unchanged", Project.MSG_VERBOSE );
416 }
417 }
418 else
419 {
420 if ( resources == null )
421 {
422 resources = new Resources();
423 resources.setProject( getProject() );
424 getProject().addReference( refid, resources );
425 }
426
427 FileResource resource = new FileResource( artifact.getFile() );
428 resource.setBaseDir( session.getLocalRepository().getBasedir() );
429 resource.setProject( getProject() );
430 resources.add( resource );
431 }
432 }
433
434 }
435
436
437
438 public class Props
439 extends ArtifactConsumer
440 {
441
442 private String prefix;
443
444 private String classifier;
445
446 public void setPrefix( String prefix )
447 {
448 this.prefix = prefix;
449 }
450
451 public String getClassifier()
452 {
453 return classifier;
454 }
455
456 public void setAttachments( String attachments )
457 {
458 if ( "sources".equals( attachments ) )
459 {
460 classifier = "*-sources";
461 }
462 else if ( "javadoc".equals( attachments ) )
463 {
464 classifier = "*-javadoc";
465 }
466 else
467 {
468 throw new BuildException( "The attachment type '" + attachments
469 + "' is not defined, must be one of 'sources' or 'javadoc'" );
470 }
471 }
472
473 public void process( Artifact artifact, RepositorySystemSession session )
474 {
475 StringBuilder buffer = new StringBuilder( 256 );
476 if ( prefix != null && prefix.length() > 0 )
477 {
478 buffer.append( prefix );
479 if ( !prefix.endsWith( "." ) )
480 {
481 buffer.append( '.' );
482 }
483 }
484 buffer.append( artifact.getGroupId() );
485 buffer.append( ':' );
486 buffer.append( artifact.getArtifactId() );
487 buffer.append( ':' );
488 buffer.append( artifact.getExtension() );
489 if ( artifact.getClassifier().length() > 0 )
490 {
491 buffer.append( ':' );
492 buffer.append( artifact.getClassifier() );
493 }
494
495 String path = artifact.getFile().getAbsolutePath();
496
497 getProject().setProperty( buffer.toString(), path );
498 }
499
500 }
501
502 private static class Group
503 {
504
505 private String classifier;
506
507 private List<ArtifactConsumer> consumers = new ArrayList<ArtifactConsumer>();
508
509 private List<ArtifactRequest> requests = new ArrayList<ArtifactRequest>();
510
511 Group( String classifier )
512 {
513 this.classifier = classifier;
514 }
515
516 public boolean isAttachments()
517 {
518 return classifier != null;
519 }
520
521 public void add( ArtifactConsumer consumer )
522 {
523 consumers.add( consumer );
524 }
525
526 public void createRequests( DependencyNode node )
527 {
528 createRequests( node, new LinkedList<DependencyNode>() );
529 }
530
531 private void createRequests( DependencyNode node, LinkedList<DependencyNode> parents )
532 {
533 if ( node.getDependency() != null )
534 {
535 for ( ArtifactConsumer consumer : consumers )
536 {
537 if ( consumer.accept( node, parents ) )
538 {
539 ArtifactRequest request = new ArtifactRequest( node );
540 if ( classifier != null )
541 {
542 request.setArtifact( new SubArtifact( request.getArtifact(), classifier, "jar" ) );
543 }
544 requests.add( request );
545 break;
546 }
547 }
548 }
549
550 parents.addFirst( node );
551
552 for ( DependencyNode child : node.getChildren() )
553 {
554 createRequests( child, parents );
555 }
556
557 parents.removeFirst();
558 }
559
560 public List<ArtifactRequest> getRequests()
561 {
562 return requests;
563 }
564
565 public void processResults( List<ArtifactResult> results, RepositorySystemSession session )
566 {
567 for ( ArtifactResult result : results )
568 {
569 if ( !result.isResolved() )
570 {
571 continue;
572 }
573 for ( ArtifactConsumer consumer : consumers )
574 {
575 if ( consumer.accept( result.getRequest().getDependencyNode(),
576 Collections.<DependencyNode>emptyList() ) )
577 {
578 consumer.process( result.getArtifact(), session );
579 }
580 }
581 }
582 }
583
584 }
585
586 }