1 package org.apache.maven.plugin.plugin;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.net.URI;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Set;
29
30 import org.apache.maven.artifact.Artifact;
31 import org.apache.maven.artifact.repository.ArtifactRepository;
32 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
33 import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter;
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
36 import org.apache.maven.plugin.descriptor.PluginDescriptor;
37 import org.apache.maven.plugins.annotations.Component;
38 import org.apache.maven.plugins.annotations.LifecyclePhase;
39 import org.apache.maven.plugins.annotations.Mojo;
40 import org.apache.maven.plugins.annotations.Parameter;
41 import org.apache.maven.plugins.annotations.ResolutionScope;
42 import org.apache.maven.settings.Settings;
43 import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
44 import org.apache.maven.tools.plugin.PluginToolsRequest;
45 import org.apache.maven.tools.plugin.extractor.ExtractionException;
46 import org.apache.maven.tools.plugin.generator.GeneratorException;
47 import org.apache.maven.tools.plugin.generator.GeneratorUtils;
48 import org.apache.maven.tools.plugin.generator.PluginDescriptorFilesGenerator;
49 import org.apache.maven.tools.plugin.scanner.MojoScanner;
50 import org.codehaus.plexus.component.repository.ComponentDependency;
51 import org.codehaus.plexus.util.ReaderFactory;
52 import org.sonatype.plexus.build.incremental.BuildContext;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 @Mojo( name = "descriptor", defaultPhase = LifecyclePhase.PROCESS_CLASSES,
69 requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, threadSafe = true )
70 public class DescriptorGeneratorMojo
71 extends AbstractGeneratorMojo
72 {
73
74
75
76 @Parameter( defaultValue = "${project.build.outputDirectory}/META-INF/maven", readonly = true )
77 private File outputDirectory;
78
79
80
81
82
83
84 @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
85 private String encoding;
86
87
88
89
90
91
92 @Parameter( defaultValue = "false" )
93 private boolean skipDescriptor;
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 @Parameter
120 private Set<String> extractors;
121
122
123
124
125
126
127
128
129 @Parameter( property = "maven.plugin.skipErrorNoDescriptorsFound", defaultValue = "false" )
130 private boolean skipErrorNoDescriptorsFound;
131
132
133
134
135
136
137
138 @Parameter( defaultValue = "true", property = "maven.plugin.checkExpectedProvidedScope" )
139 private boolean checkExpectedProvidedScope = true;
140
141
142
143
144
145
146
147 @Parameter
148 private List<String> expectedProvidedScopeGroupIds = Collections.singletonList( "org.apache.maven" );
149
150
151
152
153
154
155
156 @Parameter
157 private List<String> expectedProvidedScopeExclusions = Arrays.asList(
158 "org.apache.maven:maven-archiver",
159 "org.apache.maven:maven-jxr" );
160
161
162
163
164
165
166
167
168
169 @Parameter
170 private List<String> mojoDependencies = null;
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 @Parameter( property = "externalJavadocBaseUrls", alias = "links" )
190 protected List<URI> externalJavadocBaseUrls;
191
192
193
194
195
196
197
198
199
200
201 @Parameter( property = "internalJavadocBaseUrl" )
202 protected URI internalJavadocBaseUrl;
203
204
205
206
207
208
209
210
211 @Parameter( property = "internalJavadocVersion", defaultValue = "${java.version}" )
212 protected String internalJavadocVersion;
213
214
215
216
217
218
219 @Parameter( defaultValue = "${settings}", readonly = true, required = true )
220 private Settings settings;
221
222
223
224
225
226
227 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true )
228 private List<ArtifactRepository> remoteRepos;
229
230
231
232
233
234
235 @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
236 private ArtifactRepository local;
237
238
239
240
241 @Component
242 private MojoScanner mojoScanner;
243
244 @Component
245 protected BuildContext buildContext;
246
247 public void generate()
248 throws MojoExecutionException
249 {
250
251 if ( !"maven-plugin".equalsIgnoreCase( project.getArtifactId() )
252 && project.getArtifactId().toLowerCase().startsWith( "maven-" )
253 && project.getArtifactId().toLowerCase().endsWith( "-plugin" )
254 && !"org.apache.maven.plugins".equals( project.getGroupId() ) )
255 {
256 getLog().warn( LS + LS + "Artifact Ids of the format maven-___-plugin are reserved for" + LS
257 + "plugins in the Group Id org.apache.maven.plugins" + LS
258 + "Please change your artifactId to the format ___-maven-plugin" + LS
259 + "In the future this error will break the build." + LS + LS );
260 }
261
262 if ( skipDescriptor )
263 {
264 getLog().warn( "Execution skipped" );
265 return;
266 }
267
268 if ( checkExpectedProvidedScope )
269 {
270 Set<Artifact> wrongScopedArtifacts = dependenciesNotInProvidedScope();
271 if ( !wrongScopedArtifacts.isEmpty() )
272 {
273 StringBuilder message = new StringBuilder(
274 LS + LS + "Some dependencies of Maven Plugins are expected to be in provided scope." + LS
275 + "Please make sure that dependencies listed below declared in POM" + LS
276 + "have set '<scope>provided</scope>' as well." + LS + LS
277 + "The following dependencies are in wrong scope:" + LS
278 );
279 for ( Artifact artifact : wrongScopedArtifacts )
280 {
281 message.append( " * " ).append( artifact ).append( LS );
282 }
283 message.append( LS ).append( LS );
284
285 getLog().warn( message.toString() );
286 }
287 }
288
289 mojoScanner.setActiveExtractors( extractors );
290
291
292 PluginDescriptor pluginDescriptor = new PluginDescriptor();
293
294 pluginDescriptor.setGroupId( project.getGroupId() );
295
296 pluginDescriptor.setArtifactId( project.getArtifactId() );
297
298 pluginDescriptor.setVersion( project.getVersion() );
299
300 pluginDescriptor.setGoalPrefix( goalPrefix );
301
302 pluginDescriptor.setName( project.getName() );
303
304 pluginDescriptor.setDescription( project.getDescription() );
305
306 if ( encoding == null || encoding.length() < 1 )
307 {
308 getLog().warn( "Using platform encoding (" + ReaderFactory.FILE_ENCODING
309 + " actually) to read mojo source files, i.e. build is platform dependent!" );
310 }
311 else
312 {
313 getLog().info( "Using '" + encoding + "' encoding to read mojo source files." );
314 }
315
316 if ( internalJavadocBaseUrl != null && !internalJavadocBaseUrl.getPath().endsWith( "/" ) )
317 {
318 throw new MojoExecutionException( "Given parameter 'internalJavadocBaseUrl' must end with a slash but is '"
319 + internalJavadocBaseUrl + "'" );
320 }
321 try
322 {
323 List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getArtifacts() );
324 pluginDescriptor.setDependencies( deps );
325
326 PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor );
327 request.setEncoding( encoding );
328 request.setSkipErrorNoDescriptorsFound( skipErrorNoDescriptorsFound );
329 request.setDependencies( filterMojoDependencies() );
330 request.setLocal( this.local );
331 request.setRemoteRepos( this.remoteRepos );
332 request.setInternalJavadocBaseUrl( internalJavadocBaseUrl );
333 request.setInternalJavadocVersion( internalJavadocVersion );
334 request.setExternalJavadocBaseUrls( externalJavadocBaseUrls );
335 request.setSettings( settings );
336
337 mojoScanner.populatePluginDescriptor( request );
338
339 outputDirectory.mkdirs();
340
341 PluginDescriptorFilesGenerator pluginDescriptorGenerator = new PluginDescriptorFilesGenerator();
342 pluginDescriptorGenerator.execute( outputDirectory, request );
343
344 buildContext.refresh( outputDirectory );
345 }
346 catch ( GeneratorException e )
347 {
348 throw new MojoExecutionException( "Error writing plugin descriptor", e );
349 }
350 catch ( InvalidPluginDescriptorException | ExtractionException e )
351 {
352 throw new MojoExecutionException( "Error extracting plugin descriptor: '" + e.getLocalizedMessage() + "'",
353 e );
354 }
355 catch ( LinkageError e )
356 {
357 throw new MojoExecutionException( "The API of the mojo scanner is not compatible with this plugin version."
358 + " Please check the plugin dependencies configured"
359 + " in the POM and ensure the versions match.",
360 e );
361 }
362 }
363
364
365
366
367 private Set<Artifact> dependenciesNotInProvidedScope()
368 {
369 LinkedHashSet<Artifact> wrongScopedDependencies = new LinkedHashSet<>();
370
371 for ( Artifact dependency : project.getArtifacts() )
372 {
373 String ga = dependency.getGroupId() + ":" + dependency.getArtifactId();
374 if ( expectedProvidedScopeGroupIds.contains( dependency.getGroupId() )
375 && !expectedProvidedScopeExclusions.contains( ga )
376 && !Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ) )
377 {
378 wrongScopedDependencies.add( dependency );
379 }
380 }
381
382 return wrongScopedDependencies;
383 }
384
385
386
387
388
389
390
391
392 private Set<Artifact> filterMojoDependencies()
393 {
394 Set<Artifact> filteredArtifacts;
395 if ( mojoDependencies == null )
396 {
397 filteredArtifacts = new LinkedHashSet<>( project.getArtifacts() );
398 }
399 else if ( mojoDependencies.isEmpty() )
400 {
401 filteredArtifacts = null;
402 }
403 else
404 {
405 filteredArtifacts = new LinkedHashSet<>();
406
407 ArtifactFilter filter = new IncludesArtifactFilter( mojoDependencies );
408
409 for ( Artifact artifact : project.getArtifacts() )
410 {
411 if ( filter.include( artifact ) )
412 {
413 filteredArtifacts.add( artifact );
414 }
415 }
416 }
417
418 return filteredArtifacts;
419 }
420 }