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 final 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.isEmpty()) {
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 static 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 @Override
229 public void validate() {
230 if (refid == null) {
231 throw new BuildException("You must specify the 'refid' for the path");
232 }
233 }
234
235 @Override
236 public void process(Artifact artifact, RepositorySystemSession session) {
237 if (path == null) {
238 path = new org.apache.tools.ant.types.Path(getProject());
239 getProject().addReference(refid, path);
240 }
241 File file = artifact.getFile();
242 path.add(new FileResource(file.getParentFile(), file.getName()));
243 }
244 }
245
246
247
248 public class Files extends ArtifactConsumer {
249
250 private static final String DEFAULT_LAYOUT = Layout.GID_DIRS + "/" + Layout.AID + "/" + Layout.BVER + "/"
251 + Layout.AID + "-" + Layout.VER + "-" + Layout.CLS + "." + Layout.EXT;
252
253 private String refid;
254
255 private String classifier;
256
257 private File dir;
258
259 private Layout layout;
260
261 private FileSet fileset;
262
263 private Resources resources;
264
265 public void setRefId(String refId) {
266 this.refid = refId;
267 }
268
269 @Override
270 public String getClassifier() {
271 return classifier;
272 }
273
274 public void setAttachments(String attachments) {
275 if ("sources".equals(attachments)) {
276 classifier = "*-sources";
277 } else if ("javadoc".equals(attachments)) {
278 classifier = "*-javadoc";
279 } else {
280 throw new BuildException("The attachment type '" + attachments
281 + "' is not defined, must be one of 'sources' or 'javadoc'");
282 }
283 }
284
285 public void setDir(File dir) {
286 this.dir = dir;
287 if (dir != null && layout == null) {
288 layout = new Layout(DEFAULT_LAYOUT);
289 }
290 }
291
292 public void setLayout(String layout) {
293 this.layout = new Layout(layout);
294 }
295
296 @Override
297 public void validate() {
298 if (refid == null && dir == null) {
299 throw new BuildException("You must either specify the 'refid' for the resource collection"
300 + " or a 'dir' to copy the files to");
301 }
302 if (dir == null && layout != null) {
303 throw new BuildException("You must not specify a 'layout' unless 'dir' is also specified");
304 }
305 }
306
307 @Override
308 public void process(Artifact artifact, RepositorySystemSession session) {
309 if (dir != null) {
310 if (refid != null && fileset == null) {
311 fileset = new FileSet();
312 fileset.setProject(getProject());
313 fileset.setDir(dir);
314 getProject().addReference(refid, fileset);
315 }
316
317 String path = layout.getPath(artifact);
318
319 if (fileset != null) {
320 fileset.createInclude().setName(path);
321 }
322
323 File src = artifact.getFile();
324 File dst = new File(dir, path);
325
326 if (src.lastModified() != dst.lastModified() || src.length() != dst.length()) {
327 try {
328 Resolve.this.log("Copy " + src + " to " + dst, Project.MSG_VERBOSE);
329 FileUtils.getFileUtils().copyFile(src, dst, null, true, true);
330 } catch (IOException e) {
331 throw new BuildException(
332 "Failed to copy artifact file " + src + " to " + dst + ": " + e.getMessage(), e);
333 }
334 } else {
335 Resolve.this.log("Omit to copy " + src + " to " + dst + ", seems unchanged", Project.MSG_VERBOSE);
336 }
337 } else {
338 if (resources == null) {
339 resources = new Resources();
340 resources.setProject(getProject());
341 getProject().addReference(refid, resources);
342 }
343
344 FileResource resource = new FileResource(artifact.getFile());
345 resource.setBaseDir(session.getLocalRepository().getBasedir());
346 resource.setProject(getProject());
347 resources.add(resource);
348 }
349 }
350 }
351
352
353
354 public static class Props extends ArtifactConsumer {
355
356 private String prefix;
357
358 private String classifier;
359
360 public void setPrefix(String prefix) {
361 this.prefix = prefix;
362 }
363
364 @Override
365 public String getClassifier() {
366 return classifier;
367 }
368
369 public void setAttachments(String attachments) {
370 if ("sources".equals(attachments)) {
371 classifier = "*-sources";
372 } else if ("javadoc".equals(attachments)) {
373 classifier = "*-javadoc";
374 } else {
375 throw new BuildException("The attachment type '" + attachments
376 + "' is not defined, must be one of 'sources' or 'javadoc'");
377 }
378 }
379
380 @Override
381 public void process(Artifact artifact, RepositorySystemSession session) {
382 StringBuilder buffer = new StringBuilder(256);
383 if (prefix != null && !prefix.isEmpty()) {
384 buffer.append(prefix);
385 if (!prefix.endsWith(".")) {
386 buffer.append('.');
387 }
388 }
389 buffer.append(artifact.getGroupId());
390 buffer.append(':');
391 buffer.append(artifact.getArtifactId());
392 buffer.append(':');
393 buffer.append(artifact.getExtension());
394 if (!artifact.getClassifier().isEmpty()) {
395 buffer.append(':');
396 buffer.append(artifact.getClassifier());
397 }
398
399 String path = artifact.getFile().getAbsolutePath();
400
401 getProject().setProperty(buffer.toString(), path);
402 }
403 }
404
405 private static class Group {
406
407 private final String classifier;
408
409 private final List<ArtifactConsumer> consumers = new ArrayList<>();
410
411 private final List<ArtifactRequest> requests = new ArrayList<>();
412
413 Group(String classifier) {
414 this.classifier = classifier;
415 }
416
417 public boolean isAttachments() {
418 return classifier != null;
419 }
420
421 public void add(ArtifactConsumer consumer) {
422 consumers.add(consumer);
423 }
424
425 public void createRequests(DependencyNode node) {
426 createRequests(node, new LinkedList<>());
427 }
428
429 private void createRequests(DependencyNode node, LinkedList<DependencyNode> parents) {
430 if (node.getDependency() != null) {
431 for (ArtifactConsumer consumer : consumers) {
432 if (consumer.accept(node, parents)) {
433 ArtifactRequest request = new ArtifactRequest(node);
434 if (classifier != null) {
435 request.setArtifact(new SubArtifact(request.getArtifact(), classifier, "jar"));
436 }
437 requests.add(request);
438 break;
439 }
440 }
441 }
442
443 parents.addFirst(node);
444
445 for (DependencyNode child : node.getChildren()) {
446 createRequests(child, parents);
447 }
448
449 parents.removeFirst();
450 }
451
452 public List<ArtifactRequest> getRequests() {
453 return requests;
454 }
455
456 public void processResults(List<ArtifactResult> results, RepositorySystemSession session) {
457 for (ArtifactResult result : results) {
458 if (!result.isResolved()) {
459 continue;
460 }
461 for (ArtifactConsumer consumer : consumers) {
462 if (consumer.accept(
463 result.getRequest().getDependencyNode(), Collections.<DependencyNode>emptyList())) {
464 consumer.process(result.getArtifact(), session);
465 }
466 }
467 }
468 }
469 }
470 }