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