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