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