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