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<>( results.getSkippedDependencies() );
170 sb.append( buildArtifactListOutput( skippedDependencies, outputAbsoluteArtifactFilename, theOutputScope,
171 theSort ) );
172 }
173
174 if ( results.getUnResolvedDependencies() != null && !results.getUnResolvedDependencies().isEmpty() )
175 {
176 sb.append( System.lineSeparator() );
177 sb.append( "The following files have NOT been resolved:" );
178 sb.append( System.lineSeparator() );
179 Set<Artifact> unResolvedDependencies = new LinkedHashSet<>( results.getUnResolvedDependencies() );
180 sb.append( buildArtifactListOutput( unResolvedDependencies, outputAbsoluteArtifactFilename, theOutputScope,
181 theSort ) );
182 }
183 sb.append( System.lineSeparator() );
184
185 return sb.toString();
186 }
187
188 private StringBuilder buildArtifactListOutput( Set<Artifact> artifacts, boolean outputAbsoluteArtifactFilename,
189 boolean theOutputScope, boolean theSort )
190 {
191 StringBuilder sb = new StringBuilder();
192 List<String> artifactStringList = new ArrayList<>();
193 for ( Artifact artifact : artifacts )
194 {
195 MessageBuilder messageBuilder = MessageUtils.buffer();
196
197 messageBuilder.a( " " );
198
199 if ( theOutputScope )
200 {
201 messageBuilder.a( artifact.toString() );
202 }
203 else
204 {
205 messageBuilder.a( artifact.getId() );
206 }
207
208 if ( outputAbsoluteArtifactFilename )
209 {
210 try
211 {
212
213 String artifactFilename = artifact.getFile().getAbsoluteFile().getPath();
214
215 messageBuilder.a( ':' ).a( artifactFilename );
216 }
217 catch ( NullPointerException e )
218 {
219
220 }
221 }
222
223 if ( theOutputScope && artifact.isOptional() )
224 {
225 messageBuilder.a( " (optional)" );
226 }
227
228
229 if ( artifact.getFile() != null )
230 {
231 ModuleDescriptor moduleDescriptor = getModuleDescriptor( artifact.getFile() );
232 if ( moduleDescriptor != null )
233 {
234 messageBuilder.project( " -- module " + moduleDescriptor.name );
235
236 if ( moduleDescriptor.automatic )
237 {
238 if ( "MANIFEST".equals( moduleDescriptor.moduleNameSource ) )
239 {
240 messageBuilder.strong( " [auto]" );
241 }
242 else
243 {
244 messageBuilder.warning( " (auto)" );
245 }
246 }
247 }
248 }
249 artifactStringList.add( messageBuilder + System.lineSeparator() );
250 }
251 if ( theSort )
252 {
253 Collections.sort( artifactStringList );
254 }
255 for ( String artifactString : artifactStringList )
256 {
257 sb.append( artifactString );
258 }
259 return sb;
260 }
261
262 private ModuleDescriptor getModuleDescriptor( File artifactFile )
263 {
264 ModuleDescriptor moduleDescriptor = null;
265 try
266 {
267
268 Class<?> moduleFinderClass = Class.forName( "java.lang.module.ModuleFinder" );
269
270 java.nio.file.Path path = artifactFile.toPath();
271
272 Method ofMethod = moduleFinderClass.getMethod( "of", java.nio.file.Path[].class );
273 Object moduleFinderInstance = ofMethod.invoke( null, new Object[] { new java.nio.file.Path[] { path } } );
274
275 Method findAllMethod = moduleFinderClass.getMethod( "findAll" );
276 Set<Object> moduleReferences = (Set<Object>) findAllMethod.invoke( moduleFinderInstance );
277
278
279 if ( !moduleReferences.isEmpty() )
280 {
281 Object moduleReference = moduleReferences.iterator().next();
282 Method descriptorMethod = moduleReference.getClass().getMethod( "descriptor" );
283 Object moduleDescriptorInstance = descriptorMethod.invoke( moduleReference );
284
285 Method nameMethod = moduleDescriptorInstance.getClass().getMethod( "name" );
286 String name = (String) nameMethod.invoke( moduleDescriptorInstance );
287
288 moduleDescriptor = new ModuleDescriptor();
289 moduleDescriptor.name = name;
290
291 Method isAutomaticMethod = moduleDescriptorInstance.getClass().getMethod( "isAutomatic" );
292 moduleDescriptor.automatic = (Boolean) isAutomaticMethod.invoke( moduleDescriptorInstance );
293
294 if ( moduleDescriptor.automatic )
295 {
296 if ( artifactFile.isFile() )
297 {
298 try ( JarFile jarFile = new JarFile( artifactFile ) )
299 {
300 Manifest manifest = jarFile.getManifest();
301
302 if ( manifest != null
303 && manifest.getMainAttributes().getValue( "Automatic-Module-Name" ) != null )
304 {
305 moduleDescriptor.moduleNameSource = "MANIFEST";
306 }
307 else
308 {
309 moduleDescriptor.moduleNameSource = "FILENAME";
310 }
311 }
312 catch ( IOException e )
313 {
314
315 }
316 }
317 }
318 }
319 }
320 catch ( ClassNotFoundException | SecurityException | IllegalAccessException | IllegalArgumentException e )
321 {
322
323 }
324 catch ( NoSuchMethodException e )
325 {
326 e.printStackTrace();
327 }
328 catch ( InvocationTargetException e )
329 {
330 Throwable cause = e.getCause();
331 while ( cause.getCause() != null )
332 {
333 cause = cause.getCause();
334 }
335 getLog().info( "Can't extract module name from " + artifactFile.getName() + ": " + cause.getMessage() );
336 }
337 return moduleDescriptor;
338 }
339
340 private class ModuleDescriptor
341 {
342 String name;
343
344 boolean automatic = true;
345
346 String moduleNameSource;
347 }
348 }