1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.dependency.resolvers;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.LinkedHashSet;
28 import java.util.List;
29 import java.util.Objects;
30 import java.util.Set;
31 import java.util.jar.JarFile;
32 import java.util.jar.Manifest;
33
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugins.annotations.LifecyclePhase;
37 import org.apache.maven.plugins.annotations.Mojo;
38 import org.apache.maven.plugins.annotations.Parameter;
39 import org.apache.maven.plugins.annotations.ResolutionScope;
40 import org.apache.maven.plugins.dependency.utils.DependencyStatusSets;
41 import org.apache.maven.plugins.dependency.utils.DependencyUtil;
42 import org.apache.maven.plugins.dependency.utils.filters.ResolveFileFilter;
43 import org.apache.maven.plugins.dependency.utils.markers.SourcesFileMarkerHandler;
44 import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
45 import org.apache.maven.shared.utils.logging.MessageBuilder;
46 import org.apache.maven.shared.utils.logging.MessageUtils;
47
48
49
50
51
52
53
54
55 @Mojo(
56 name = "resolve",
57 requiresDependencyResolution = ResolutionScope.TEST,
58 defaultPhase = LifecyclePhase.GENERATE_SOURCES,
59 threadSafe = true)
60 public class ResolveDependenciesMojo extends AbstractResolveMojo {
61
62 @Parameter(property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}")
63 private String outputEncoding;
64
65
66
67
68
69
70 @Parameter(property = "mdep.outputScope", defaultValue = "true")
71 protected boolean outputScope;
72
73
74
75
76
77
78 @Parameter(property = "outputAbsoluteArtifactFilename", defaultValue = "false")
79 private boolean outputAbsoluteArtifactFilename;
80
81
82
83
84 DependencyStatusSets results;
85
86
87
88
89
90
91 @Parameter(property = "sort", defaultValue = "false")
92 boolean sort;
93
94
95
96
97
98
99 @Parameter(property = "includeParents", defaultValue = "false")
100 boolean includeParents;
101
102
103
104
105
106
107 @Override
108 protected void doExecute() throws MojoExecutionException {
109
110 results = this.getDependencySets(false, includeParents);
111
112 String output = getOutput(outputAbsoluteArtifactFilename, outputScope, sort);
113 try {
114 if (outputFile == null) {
115 DependencyUtil.log(output, getLog());
116 } else {
117 String encoding = Objects.toString(outputEncoding, "UTF-8");
118 DependencyUtil.write(output, outputFile, appendOutput, encoding);
119 }
120 } catch (IOException e) {
121 throw new MojoExecutionException(e.getMessage(), e);
122 }
123 }
124
125
126
127
128 public DependencyStatusSets getResults() {
129 return this.results;
130 }
131
132 @Override
133 protected ArtifactsFilter getMarkedArtifactFilter() {
134 return new ResolveFileFilter(new SourcesFileMarkerHandler(this.markersDirectory));
135 }
136
137
138
139
140
141
142
143 public String getOutput(boolean outputAbsoluteArtifactFilename, boolean theOutputScope, boolean theSort) {
144 StringBuilder sb = new StringBuilder();
145 sb.append(System.lineSeparator());
146 sb.append("The following files have been resolved:");
147 sb.append(System.lineSeparator());
148 if (results.getResolvedDependencies() == null
149 || results.getResolvedDependencies().isEmpty()) {
150 sb.append(" none");
151 sb.append(System.lineSeparator());
152 } else {
153 sb.append(buildArtifactListOutput(
154 results.getResolvedDependencies(), outputAbsoluteArtifactFilename, theOutputScope, theSort));
155 }
156
157 if (results.getSkippedDependencies() != null
158 && !results.getSkippedDependencies().isEmpty()) {
159 sb.append(System.lineSeparator());
160 sb.append("The following files were skipped:");
161 sb.append(System.lineSeparator());
162 Set<Artifact> skippedDependencies = new LinkedHashSet<>(results.getSkippedDependencies());
163 sb.append(buildArtifactListOutput(
164 skippedDependencies, outputAbsoluteArtifactFilename, theOutputScope, theSort));
165 }
166
167 if (results.getUnResolvedDependencies() != null
168 && !results.getUnResolvedDependencies().isEmpty()) {
169 sb.append(System.lineSeparator());
170 sb.append("The following files have NOT been resolved:");
171 sb.append(System.lineSeparator());
172 Set<Artifact> unResolvedDependencies = new LinkedHashSet<>(results.getUnResolvedDependencies());
173 sb.append(buildArtifactListOutput(
174 unResolvedDependencies, outputAbsoluteArtifactFilename, theOutputScope, theSort));
175 }
176 sb.append(System.lineSeparator());
177
178 return sb.toString();
179 }
180
181 private StringBuilder buildArtifactListOutput(
182 Set<Artifact> artifacts, boolean outputAbsoluteArtifactFilename, boolean theOutputScope, boolean theSort) {
183 StringBuilder sb = new StringBuilder();
184 List<String> artifactStringList = new ArrayList<>();
185 for (Artifact artifact : artifacts) {
186 MessageBuilder messageBuilder = MessageUtils.buffer();
187
188 messageBuilder.a(" ");
189
190 if (theOutputScope) {
191 messageBuilder.a(artifact.toString());
192 } else {
193 messageBuilder.a(artifact.getId());
194 }
195
196 if (outputAbsoluteArtifactFilename) {
197 try {
198
199 String artifactFilename =
200 artifact.getFile().getAbsoluteFile().getPath();
201
202 messageBuilder.a(':').a(artifactFilename);
203 } catch (NullPointerException e) {
204
205 }
206 }
207
208 if (theOutputScope && artifact.isOptional()) {
209 messageBuilder.a(" (optional)");
210 }
211
212
213 if (artifact.getFile() != null) {
214 ModuleDescriptor moduleDescriptor = getModuleDescriptor(artifact.getFile());
215 if (moduleDescriptor != null) {
216 messageBuilder.project(" -- module " + moduleDescriptor.name);
217
218 if (moduleDescriptor.automatic) {
219 if ("MANIFEST".equals(moduleDescriptor.moduleNameSource)) {
220 messageBuilder.strong(" [auto]");
221 } else {
222 messageBuilder.warning(" (auto)");
223 }
224 }
225 }
226 }
227 artifactStringList.add(messageBuilder + System.lineSeparator());
228 }
229 if (theSort) {
230 Collections.sort(artifactStringList);
231 }
232 for (String artifactString : artifactStringList) {
233 sb.append(artifactString);
234 }
235 return sb;
236 }
237
238 private ModuleDescriptor getModuleDescriptor(File artifactFile) {
239 ModuleDescriptor moduleDescriptor = null;
240 try {
241
242 Class<?> moduleFinderClass = Class.forName("java.lang.module.ModuleFinder");
243
244 java.nio.file.Path path = artifactFile.toPath();
245
246 Method ofMethod = moduleFinderClass.getMethod("of", java.nio.file.Path[].class);
247 Object moduleFinderInstance = ofMethod.invoke(null, new Object[] {new java.nio.file.Path[] {path}});
248
249 Method findAllMethod = moduleFinderClass.getMethod("findAll");
250 Set<Object> moduleReferences = (Set<Object>) findAllMethod.invoke(moduleFinderInstance);
251
252
253 if (!moduleReferences.isEmpty()) {
254 Object moduleReference = moduleReferences.iterator().next();
255 Method descriptorMethod = moduleReference.getClass().getMethod("descriptor");
256 Object moduleDescriptorInstance = descriptorMethod.invoke(moduleReference);
257
258 Method nameMethod = moduleDescriptorInstance.getClass().getMethod("name");
259 String name = (String) nameMethod.invoke(moduleDescriptorInstance);
260
261 moduleDescriptor = new ModuleDescriptor();
262 moduleDescriptor.name = name;
263
264 Method isAutomaticMethod = moduleDescriptorInstance.getClass().getMethod("isAutomatic");
265 moduleDescriptor.automatic = (Boolean) isAutomaticMethod.invoke(moduleDescriptorInstance);
266
267 if (moduleDescriptor.automatic) {
268 if (artifactFile.isFile()) {
269 try (JarFile jarFile = new JarFile(artifactFile)) {
270 Manifest manifest = jarFile.getManifest();
271
272 if (manifest != null
273 && manifest.getMainAttributes().getValue("Automatic-Module-Name") != null) {
274 moduleDescriptor.moduleNameSource = "MANIFEST";
275 } else {
276 moduleDescriptor.moduleNameSource = "FILENAME";
277 }
278 } catch (IOException e) {
279
280 }
281 }
282 }
283 }
284 } catch (ClassNotFoundException | SecurityException | IllegalAccessException | IllegalArgumentException e) {
285
286 } catch (NoSuchMethodException e) {
287 getLog().warn(e);
288 } catch (InvocationTargetException e) {
289 Throwable cause = e.getCause();
290 while (cause.getCause() != null) {
291 cause = cause.getCause();
292 }
293 getLog().info("Can't extract module name from " + artifactFile.getName() + ": " + cause.getMessage());
294 }
295 return moduleDescriptor;
296 }
297
298 private static class ModuleDescriptor {
299 String name;
300
301 boolean automatic = true;
302
303 String moduleNameSource;
304 }
305 }