This is an automated email from the ASF dual-hosted git repository. sjaranowski pushed a commit to branch MPLUGIN-408 in repository https://gitbox.apache.org/repos/asf/maven-plugin-tools.git
commit 19cfdfb12b841bf01841d1f057394da6696960fd Author: Slawomir Jaranowski <[email protected]> AuthorDate: Thu Jul 28 18:14:48 2022 +0200 [MPLUGIN-408] helpmojo improvement - use groupId + artifactId for calculating package name - discover mojos only ones by descriptor mojo - simplify in AbstractGeneratorMojo - remove unneeded code --- maven-plugin-plugin/pom.xml | 2 +- .../verify.groovy | 7 +- .../it/annotation-with-inheritance/verify.groovy | 7 +- .../java-basic-annotations-jdk8/invoker.properties | 4 +- .../src/it/java-basic-annotations-jdk8/pom.xml | 2 +- .../it/java-basic-annotations-jdk8/verify.groovy | 5 +- .../verify.groovy | 5 +- .../src/it/java-basic-annotations/verify.groovy | 10 +- .../it/mplugin-363_help-reproducible/verify.groovy | 4 +- .../maven/plugin/plugin/AbstractGeneratorMojo.java | 302 +----------------- .../plugin/plugin/DescriptorGeneratorMojo.java | 288 ++++++++++++++++-- .../maven/plugin/plugin/HelpGeneratorMojo.java | 85 ++++-- .../maven/plugin/plugin/HelpGeneratorMojoTest.java | 63 ++++ .../generator/PluginDescriptorGenerator.java | 28 +- .../plugin/generator/PluginHelpGenerator.java | 336 ++------------------- .../plugin/generator/PluginHelpGeneratorTest.java | 46 --- .../javadoc/JavaMojoDescriptorExtractorTest.java | 2 +- pom.xml | 7 +- 18 files changed, 462 insertions(+), 741 deletions(-) diff --git a/maven-plugin-plugin/pom.xml b/maven-plugin-plugin/pom.xml index 448f6bd9..5642641e 100644 --- a/maven-plugin-plugin/pom.xml +++ b/maven-plugin-plugin/pom.xml @@ -179,7 +179,7 @@ <!-- tests --> <dependency> <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-engine</artifactId> + <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> diff --git a/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy b/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy index 1ef2944d..b941b803 100644 --- a/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy +++ b/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy @@ -20,11 +20,8 @@ File descriptorFile = new File( basedir, "target/classes/META-INF/maven/plugin.xml" ); assert descriptorFile.isFile() -File oldHelpClass = new File( basedir, "target/classes/HelpMojo.class" ); -assert !oldHelpClass.exists() - -File newHelpClass = new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ); -assert newHelpClass.exists() +File helpClass = new File( basedir, "target/classes/org/apache/maven/its/annotation_with_inheritance_from_deps/annotation_with_inheritance_from_deps/HelpMojo.class" ); +assert helpClass.exists() def pluginDescriptor = new XmlParser().parse( descriptorFile ); diff --git a/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy b/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy index d066901a..689e0008 100644 --- a/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy +++ b/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy @@ -23,11 +23,8 @@ assert touchFile.isFile() File descriptorFile = new File( basedir, "target/classes/META-INF/maven/plugin.xml" ); assert descriptorFile.isFile() -File oldHelpClass = new File( basedir, "target/classes/HelpMojo.class" ); -assert !oldHelpClass.exists() - -File newHelpClass = new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ); -assert newHelpClass.exists() +File helpClass = new File( basedir, "target/classes/org/apache/maven/its/annotation_with_inheritance/annotation_with_inheritance/HelpMojo.class" ); +assert helpClass.exists() def pluginDescriptor = new XmlParser().parse( descriptorFile ); diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties index d0a9e140..6760204d 100644 --- a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties +++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties @@ -16,5 +16,5 @@ # under the License. invoker.goals.1 = clean install -invoker.goals.2 = org.apache.maven.its.basic-java-annotations:maven-it-basic-java-annotations:1.0-SNAPSHOT:it0014 -invoker.goals.3 = org.apache.maven.its.basic-java-annotations:maven-it-basic-java-annotations:1.0-SNAPSHOT:help +invoker.goals.2 = org.apache.maven.its.basic-java-annotations:123-maven-it-basic-java-annotations:1.0-SNAPSHOT:it0014 +invoker.goals.3 = org.apache.maven.its.basic-java-annotations:123-maven-it-basic-java-annotations:1.0-SNAPSHOT:help diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml index 124b37cc..dda14a8a 100644 --- a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml +++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml @@ -23,7 +23,7 @@ under the License. <modelVersion>4.0.0</modelVersion> <groupId>org.apache.maven.its.basic-java-annotations</groupId> - <artifactId>maven-it-basic-java-annotations</artifactId> + <artifactId>123-maven-it-basic-java-annotations</artifactId> <version>1.0-SNAPSHOT</version> <packaging>maven-plugin</packaging> diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy index 294f5386..b130e2c5 100644 --- a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy +++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy @@ -224,8 +224,7 @@ requirement = mojo.requirements.requirement.findAll{ it.'field-name'.text() == " assert requirement.role.text() == 'org.apache.maven.project.MavenProjectHelper' // check help mojo source and class -assert new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ).isFile() -assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/plugin/coreit/HelpMojo.java" ).isFile() -assert !new File( basedir, "target/generated-sources/plugin/HelpMojo.java" ).isFile() +assert new File( basedir, "target/classes/org/apache/maven/its/basic_java_annotations/_123_maven_it_basic_java_annotations/HelpMojo.class" ).isFile() +assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/basic_java_annotations/_123_maven_it_basic_java_annotations/HelpMojo.java" ).isFile() return true; diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy b/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy index 294f5386..c498a221 100644 --- a/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy +++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy @@ -224,8 +224,7 @@ requirement = mojo.requirements.requirement.findAll{ it.'field-name'.text() == " assert requirement.role.text() == 'org.apache.maven.project.MavenProjectHelper' // check help mojo source and class -assert new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ).isFile() -assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/plugin/coreit/HelpMojo.java" ).isFile() -assert !new File( basedir, "target/generated-sources/plugin/HelpMojo.java" ).isFile() +assert new File( basedir, "target/classes/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.class" ).isFile() +assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.java" ).isFile() return true; diff --git a/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy b/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy index 0541a8f1..4315bef7 100644 --- a/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy +++ b/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy @@ -224,9 +224,13 @@ requirement = mojo.requirements.requirement.findAll{ it.'field-name'.text() == " assert requirement.role.text() == 'org.apache.maven.project.MavenProjectHelper' // check help mojo source and class -assert new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ).isFile() -assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/plugin/coreit/HelpMojo.java" ).isFile() -assert !new File( basedir, "target/generated-sources/plugin/HelpMojo.java" ).isFile() +assert new File( basedir, "target/classes/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.class" ).isFile() +assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.java" ).isFile() + +mojo = pluginDescriptor.mojos.mojo.findAll{ it.goal.text() == "help"}[0] +assert mojo.goal.text() == 'help' +assert mojo.implementation.text() == 'org.apache.maven.its.basic_java_annotations.maven_it_basic_java_annotations.HelpMojo' +assert mojo.language.text() == 'java' // check values set by deprecated annotation only mojo = pluginDescriptor.mojos.mojo.findAll{ it.goal.text() == "mplugin-396"}[0] diff --git a/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy b/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy index b64de436..b47f8a9d 100644 --- a/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy +++ b/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy @@ -17,7 +17,7 @@ * under the License. */ -firstRun = new File( basedir, "target/generated-sources-run1/plugin/test/HelpMojo.java" ).text; -secondRun = new File( basedir, "target/generated-sources/plugin/test/HelpMojo.java" ).text; +firstRun = new File( basedir, "target/generated-sources-run1/plugin/org/apache/maven/its/plugin/help/HelpMojo.java" ).text; +secondRun = new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/plugin/help/HelpMojo.java" ).text; assert firstRun == secondRun; diff --git a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java index bd1354d5..a62d923f 100644 --- a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java +++ b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java @@ -19,34 +19,14 @@ package org.apache.maven.plugin.plugin; * under the License. */ -import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.repository.ArtifactRepository; -import org.apache.maven.artifact.resolver.filter.ArtifactFilter; -import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter; +import java.util.Collections; +import java.util.List; + import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; import org.apache.maven.plugin.descriptor.PluginDescriptor; -import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; -import org.apache.maven.tools.plugin.DefaultPluginToolsRequest; -import org.apache.maven.tools.plugin.PluginToolsRequest; -import org.apache.maven.tools.plugin.extractor.ExtractionException; -import org.apache.maven.tools.plugin.generator.Generator; -import org.apache.maven.tools.plugin.generator.GeneratorException; -import org.apache.maven.tools.plugin.generator.GeneratorUtils; -import org.apache.maven.tools.plugin.scanner.MojoScanner; -import org.codehaus.plexus.component.repository.ComponentDependency; -import org.codehaus.plexus.util.ReaderFactory; -import org.sonatype.plexus.build.incremental.BuildContext; - -import java.io.File; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; /** * Abstract class for this Plugin. @@ -63,100 +43,19 @@ public abstract class AbstractGeneratorMojo @Parameter( defaultValue = "${project}", readonly = true ) protected MavenProject project; - /** - * The component used for scanning the source tree for mojos. - */ - @Component - protected MojoScanner mojoScanner; - - @Component - protected BuildContext buildContext; - - /** - * The file encoding of the source files. - * - * @since 2.5 - */ - @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" ) - protected String encoding; - /** * The goal prefix that will appear before the ":". */ @Parameter protected String goalPrefix; - /** - * By default an exception is throw if no mojo descriptor is found. As the maven-plugin is defined in core, the - * descriptor generator mojo is bound to generate-resources phase. - * But for annotations, the compiled classes are needed, so skip error - * - * @since 3.0 - */ - @Parameter( property = "maven.plugin.skipErrorNoDescriptorsFound", defaultValue = "false" ) - protected boolean skipErrorNoDescriptorsFound; - - /** - * <p> - * The role names of mojo extractors to use. - * </p> - * <p> - * If not set, all mojo extractors will be used. If set to an empty extractor name, no mojo extractors - * will be used. - * </p> - * Example: - * <pre> - * <!-- Use all mojo extractors --> - * <extractors/> - * - * <!-- Use no mojo extractors --> - * <extractors> - * <extractor/> - * </extractors> - * - * <!-- Use only bsh mojo extractor --> - * <extractors> - * <extractor>bsh</extractor> - * </extractors> - * </pre> - */ - @Parameter - protected Set<String> extractors; - /** * Set this to "true" to skip invoking any goals or reports of the plugin. * * @since 2.8 */ @Parameter( defaultValue = "false", property = "maven.plugin.skip" ) - protected boolean skip; - - /** - * Specify the dependencies as {@code groupId:artifactId} containing (abstract) Mojos, to filter - * dependencies scanned at runtime and focus on dependencies that are really useful to Mojo analysis. - * By default, the value is {@code null} and all dependencies are scanned (as before this parameter was added). - * If specified in the configuration with no children, no dependencies are scanned. - * - * @since 3.5 - */ - @Parameter - private List<String> mojoDependencies = null; - - /** - * List of Remote Repositories used by the resolver - * - * @since 3.0 - */ - @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true ) - protected List<ArtifactRepository> remoteRepos; - - /** - * Location of the local repository. - * - * @since 3.0 - */ - @Parameter( defaultValue = "${localRepository}", required = true, readonly = true ) - protected ArtifactRepository local; + private boolean skip; /** * Maven plugin packaging types. Default is single "maven-plugin". @@ -164,55 +63,15 @@ public abstract class AbstractGeneratorMojo * @since 3.3 */ @Parameter - protected List<String> packagingTypes = Collections.singletonList( "maven-plugin" ); - - /** - * Flag controlling is "expected dependencies in provided scope" check to be performed or not. Default value: - * {@code true}. - * - * @since 3.6.3 - */ - @Parameter( defaultValue = "true", property = "maven.plugin.checkExpectedProvidedScope" ) - private boolean checkExpectedProvidedScope = true; - - /** - * List of {@code groupId} strings of artifact coordinates that are expected to be in "provided" scope. Default - * value: {@code ["org.apache.maven"]}. - * - * @since 3.6.3 - */ - @Parameter - private List<String> expectedProvidedScopeGroupIds = Collections.singletonList( "org.apache.maven" ); - - /** - * List of {@code groupId:artifactId} strings of artifact coordinates that are to be excluded from "expected - * provided scope" check. Default value: {@code ["org.apache.maven:maven-archiver", "org.apache.maven:maven-jxr"]}. - * - * @since 3.6.3 - */ - @Parameter - private List<String> expectedProvidedScopeExclusions = Arrays.asList( - "org.apache.maven:maven-archiver", - "org.apache.maven:maven-jxr" ); - - /** - * @return the output directory where files will be generated. - */ - protected abstract File getOutputDirectory(); - - /** - * @return the wanted <code>Generator</code> implementation. - */ - protected abstract Generator createGenerator(); + private List<String> packagingTypes = Collections.singletonList( "maven-plugin" ); /** * System/OS line separator: used to format console messages. */ - private static final String LS = System.lineSeparator(); + protected static final String LS = System.lineSeparator(); + + protected abstract void generate() throws MojoExecutionException; - /** - * {@inheritDoc} - */ @Override public void execute() throws MojoExecutionException @@ -222,6 +81,7 @@ public abstract class AbstractGeneratorMojo getLog().info( "Unsupported packaging type " + project.getPackaging() + ", execution skipped" ); return; } + if ( skip ) { getLog().warn( "Execution skipped" ); @@ -230,7 +90,7 @@ public abstract class AbstractGeneratorMojo if ( !"maven-plugin".equalsIgnoreCase( project.getArtifactId() ) && project.getArtifactId().toLowerCase().startsWith( "maven-" ) - && project.getArtifactId().toLowerCase().endsWith( "-plugin" ) + && project.getArtifactId().toLowerCase().endsWith( "-plugin" ) && !"org.apache.maven.plugins".equals( project.getGroupId() ) ) { getLog().error( LS + LS + "Artifact Ids of the format maven-___-plugin are reserved for" + LS @@ -239,29 +99,8 @@ public abstract class AbstractGeneratorMojo + "In the future this error will break the build." + LS + LS ); } - if ( checkExpectedProvidedScope ) - { - Set<Artifact> wrongScopedArtifacts = dependenciesNotInProvidedScope(); - if ( !wrongScopedArtifacts.isEmpty() ) - { - StringBuilder errorMessage = new StringBuilder( - LS + LS + "Some dependencies of Maven Plugins are expected to be in provided scope." + LS - + "Please make sure that dependencies listed below declared in POM" + LS - + "have set '<scope>provided</scope>' as well." + LS + LS - + "The following dependencies are in wrong scope:" + LS - ); - for ( Artifact artifact : wrongScopedArtifacts ) - { - errorMessage.append( " * " ).append( artifact ).append( LS ); - } - errorMessage.append( LS ).append( LS ); - - getLog().error( errorMessage.toString() ); - } - } - String defaultGoalPrefix = getDefaultGoalPrefix( project ); - + if ( goalPrefix == null ) { goalPrefix = defaultGoalPrefix; @@ -273,67 +112,7 @@ public abstract class AbstractGeneratorMojo + defaultGoalPrefix + "'." + LS ); } - mojoScanner.setActiveExtractors( extractors ); - - // TODO: could use this more, eg in the writing of the plugin descriptor! - PluginDescriptor pluginDescriptor = new PluginDescriptor(); - - pluginDescriptor.setGroupId( project.getGroupId() ); - - pluginDescriptor.setArtifactId( project.getArtifactId() ); - - pluginDescriptor.setVersion( project.getVersion() ); - - pluginDescriptor.setGoalPrefix( goalPrefix ); - - pluginDescriptor.setName( project.getName() ); - - pluginDescriptor.setDescription( project.getDescription() ); - - if ( encoding == null || encoding.length() < 1 ) - { - getLog().warn( "Using platform encoding (" + ReaderFactory.FILE_ENCODING - + " actually) to read mojo source files, i.e. build is platform dependent!" ); - } - else - { - getLog().info( "Using '" + encoding + "' encoding to read mojo source files." ); - } - - try - { - List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getArtifacts() ); - pluginDescriptor.setDependencies( deps ); - - PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor ); - request.setEncoding( encoding ); - request.setSkipErrorNoDescriptorsFound( skipErrorNoDescriptorsFound ); - request.setDependencies( filterMojoDependencies() ); - request.setLocal( this.local ); - request.setRemoteRepos( this.remoteRepos ); - - mojoScanner.populatePluginDescriptor( request ); - - File outputDirectory = getOutputDirectory(); - outputDirectory.mkdirs(); - - createGenerator().execute( outputDirectory, request ); - buildContext.refresh( outputDirectory ); - } - catch ( GeneratorException e ) - { - throw new MojoExecutionException( "Error writing plugin descriptor", e ); - } - catch ( InvalidPluginDescriptorException | ExtractionException e ) - { - throw new MojoExecutionException( "Error extracting plugin descriptor: '" + e.getLocalizedMessage() + "'", - e ); - } - catch ( LinkageError e ) - { - throw new MojoExecutionException( "The API of the mojo scanner is not compatible with this plugin version." - + " Please check the plugin dependencies configured in the POM and ensure the versions match.", e ); - } + generate(); } static String getDefaultGoalPrefix( MavenProject project ) @@ -349,61 +128,4 @@ public abstract class AbstractGeneratorMojo } return defaultGoalPrefix; } - - /** - * Collects all dependencies expected to be in "provided" scope but are NOT in "provided" scope. - */ - private Set<Artifact> dependenciesNotInProvidedScope() - { - LinkedHashSet<Artifact> wrongScopedDependencies = new LinkedHashSet<>(); - - for ( Artifact dependency : project.getArtifacts() ) - { - String ga = dependency.getGroupId() + ":" + dependency.getArtifactId(); - if ( expectedProvidedScopeGroupIds.contains( dependency.getGroupId() ) - && !expectedProvidedScopeExclusions.contains( ga ) - && !Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ) ) - { - wrongScopedDependencies.add( dependency ); - } - } - - return wrongScopedDependencies; - } - - /** - * Get dependencies filtered with mojoDependencies configuration. - * - * @return eventually filtered dependencies, or even <code>null</code> if configured with empty mojoDependencies - * list - * @see #mojoDependencies - */ - private Set<Artifact> filterMojoDependencies() - { - Set<Artifact> filteredArtifacts; - if ( mojoDependencies == null ) - { - filteredArtifacts = new LinkedHashSet<>( project.getArtifacts() ); - } - else if ( mojoDependencies.size() == 0 ) - { - filteredArtifacts = null; - } - else - { - filteredArtifacts = new LinkedHashSet<>(); - - ArtifactFilter filter = new IncludesArtifactFilter( mojoDependencies ); - - for ( Artifact artifact : project.getArtifacts() ) - { - if ( filter.include( artifact ) ) - { - filteredArtifacts.add( artifact ); - } - } - } - - return filteredArtifacts; - } } diff --git a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java index 9827a77f..1a6f3298 100644 --- a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java +++ b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java @@ -20,13 +20,34 @@ package org.apache.maven.plugin.plugin; */ import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter; import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; +import org.apache.maven.plugin.descriptor.PluginDescriptor; +import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.tools.plugin.generator.Generator; +import org.apache.maven.tools.plugin.DefaultPluginToolsRequest; +import org.apache.maven.tools.plugin.PluginToolsRequest; +import org.apache.maven.tools.plugin.extractor.ExtractionException; +import org.apache.maven.tools.plugin.generator.GeneratorException; +import org.apache.maven.tools.plugin.generator.GeneratorUtils; import org.apache.maven.tools.plugin.generator.PluginDescriptorGenerator; +import org.apache.maven.tools.plugin.scanner.MojoScanner; +import org.codehaus.plexus.component.repository.ComponentDependency; +import org.codehaus.plexus.util.ReaderFactory; +import org.sonatype.plexus.build.incremental.BuildContext; /** * <p> @@ -51,7 +72,15 @@ public class DescriptorGeneratorMojo * The directory where the generated <code>plugin.xml</code> file will be put. */ @Parameter( defaultValue = "${project.build.outputDirectory}/META-INF/maven", readonly = true ) - protected File outputDirectory; + private File outputDirectory; + + /** + * The file encoding of the source files. + * + * @since 2.5 + */ + @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" ) + private String encoding; /** * A flag to disable generation of the <code>plugin.xml</code> in favor of a hand authored plugin descriptor. @@ -62,36 +91,259 @@ public class DescriptorGeneratorMojo private boolean skipDescriptor; /** - * {@inheritDoc} + * <p> + * The role names of mojo extractors to use. + * </p> + * <p> + * If not set, all mojo extractors will be used. If set to an empty extractor name, no mojo extractors + * will be used. + * </p> + * Example: + * <pre> + * <!-- Use all mojo extractors --> + * <extractors/> + * + * <!-- Use no mojo extractors --> + * <extractors> + * <extractor/> + * </extractors> + * + * <!-- Use only bsh mojo extractor --> + * <extractors> + * <extractor>bsh</extractor> + * </extractors> + * </pre> */ - @Override - protected File getOutputDirectory() - { - return outputDirectory; - } + @Parameter + private Set<String> extractors; + /** - * {@inheritDoc} + * By default, an exception is throw if no mojo descriptor is found. As the maven-plugin is defined in core, the + * descriptor generator mojo is bound to generate-resources phase. + * But for annotations, the compiled classes are needed, so skip error + * + * @since 3.0 */ - @Override - protected Generator createGenerator() - { - return new PluginDescriptorGenerator( getLog() ); - } + @Parameter( property = "maven.plugin.skipErrorNoDescriptorsFound", defaultValue = "false" ) + private boolean skipErrorNoDescriptorsFound; + + /** + * Flag controlling is "expected dependencies in provided scope" check to be performed or not. Default value: + * {@code true}. + * + * @since 3.6.3 + */ + @Parameter( defaultValue = "true", property = "maven.plugin.checkExpectedProvidedScope" ) + private boolean checkExpectedProvidedScope = true; + + /** + * List of {@code groupId} strings of artifact coordinates that are expected to be in "provided" scope. Default + * value: {@code ["org.apache.maven"]}. + * + * @since 3.6.3 + */ + @Parameter + private List<String> expectedProvidedScopeGroupIds = Collections.singletonList( "org.apache.maven" ); /** - * {@inheritDoc} + * List of {@code groupId:artifactId} strings of artifact coordinates that are to be excluded from "expected + * provided scope" check. Default value: {@code ["org.apache.maven:maven-archiver", "org.apache.maven:maven-jxr"]}. + * + * @since 3.6.3 */ - @Override - public void execute() + @Parameter + private List<String> expectedProvidedScopeExclusions = Arrays.asList( + "org.apache.maven:maven-archiver", + "org.apache.maven:maven-jxr" ); + + /** + * Specify the dependencies as {@code groupId:artifactId} containing (abstract) Mojos, to filter + * dependencies scanned at runtime and focus on dependencies that are really useful to Mojo analysis. + * By default, the value is {@code null} and all dependencies are scanned (as before this parameter was added). + * If specified in the configuration with no children, no dependencies are scanned. + * + * @since 3.5 + */ + @Parameter + private List<String> mojoDependencies = null; + + /** + * List of Remote Repositories used by the resolver + * + * @since 3.0 + */ + @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true ) + private List<ArtifactRepository> remoteRepos; + + /** + * Location of the local repository. + * + * @since 3.0 + */ + @Parameter( defaultValue = "${localRepository}", required = true, readonly = true ) + private ArtifactRepository local; + + /** + * The component used for scanning the source tree for mojos. + */ + @Component + private MojoScanner mojoScanner; + + @Component + protected BuildContext buildContext; + + public void generate() throws MojoExecutionException { + if ( skipDescriptor ) { + getLog().warn( "Execution skipped" ); return; } - super.execute(); + if ( checkExpectedProvidedScope ) + { + Set<Artifact> wrongScopedArtifacts = dependenciesNotInProvidedScope(); + if ( !wrongScopedArtifacts.isEmpty() ) + { + StringBuilder errorMessage = new StringBuilder( + LS + LS + "Some dependencies of Maven Plugins are expected to be in provided scope." + LS + + "Please make sure that dependencies listed below declared in POM" + LS + + "have set '<scope>provided</scope>' as well." + LS + LS + + "The following dependencies are in wrong scope:" + LS + ); + for ( Artifact artifact : wrongScopedArtifacts ) + { + errorMessage.append( " * " ).append( artifact ).append( LS ); + } + errorMessage.append( LS ).append( LS ); + + getLog().error( errorMessage.toString() ); + } + } + + mojoScanner.setActiveExtractors( extractors ); + + // TODO: could use this more, eg in the writing of the plugin descriptor! + PluginDescriptor pluginDescriptor = new PluginDescriptor(); + + pluginDescriptor.setGroupId( project.getGroupId() ); + + pluginDescriptor.setArtifactId( project.getArtifactId() ); + + pluginDescriptor.setVersion( project.getVersion() ); + + pluginDescriptor.setGoalPrefix( goalPrefix ); + + pluginDescriptor.setName( project.getName() ); + + pluginDescriptor.setDescription( project.getDescription() ); + + if ( encoding == null || encoding.length() < 1 ) + { + getLog().warn( "Using platform encoding (" + ReaderFactory.FILE_ENCODING + + " actually) to read mojo source files, i.e. build is platform dependent!" ); + } + else + { + getLog().info( "Using '" + encoding + "' encoding to read mojo source files." ); + } + + try + { + List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getArtifacts() ); + pluginDescriptor.setDependencies( deps ); + + PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor ); + request.setEncoding( encoding ); + request.setSkipErrorNoDescriptorsFound( skipErrorNoDescriptorsFound ); + request.setDependencies( filterMojoDependencies() ); + request.setLocal( this.local ); + request.setRemoteRepos( this.remoteRepos ); + + mojoScanner.populatePluginDescriptor( request ); + + outputDirectory.mkdirs(); + + PluginDescriptorGenerator pluginDescriptorGenerator = new PluginDescriptorGenerator(); + pluginDescriptorGenerator.execute( outputDirectory, request ); + + buildContext.refresh( outputDirectory ); + } + catch ( GeneratorException e ) + { + throw new MojoExecutionException( "Error writing plugin descriptor", e ); + } + catch ( InvalidPluginDescriptorException | ExtractionException e ) + { + throw new MojoExecutionException( "Error extracting plugin descriptor: '" + e.getLocalizedMessage() + "'", + e ); + } + catch ( LinkageError e ) + { + throw new MojoExecutionException( "The API of the mojo scanner is not compatible with this plugin version." + + " Please check the plugin dependencies configured" + + " in the POM and ensure the versions match.", + e ); + } } + /** + * Collects all dependencies expected to be in "provided" scope but are NOT in "provided" scope. + */ + private Set<Artifact> dependenciesNotInProvidedScope() + { + LinkedHashSet<Artifact> wrongScopedDependencies = new LinkedHashSet<>(); + + for ( Artifact dependency : project.getArtifacts() ) + { + String ga = dependency.getGroupId() + ":" + dependency.getArtifactId(); + if ( expectedProvidedScopeGroupIds.contains( dependency.getGroupId() ) + && !expectedProvidedScopeExclusions.contains( ga ) + && !Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ) ) + { + wrongScopedDependencies.add( dependency ); + } + } + + return wrongScopedDependencies; + } + + /** + * Get dependencies filtered with mojoDependencies configuration. + * + * @return eventually filtered dependencies, or even <code>null</code> if configured with empty mojoDependencies + * list + * @see #mojoDependencies + */ + private Set<Artifact> filterMojoDependencies() + { + Set<Artifact> filteredArtifacts; + if ( mojoDependencies == null ) + { + filteredArtifacts = new LinkedHashSet<>( project.getArtifacts() ); + } + else if ( mojoDependencies.isEmpty() ) + { + filteredArtifacts = null; + } + else + { + filteredArtifacts = new LinkedHashSet<>(); + + ArtifactFilter filter = new IncludesArtifactFilter( mojoDependencies ); + + for ( Artifact artifact : project.getArtifacts() ) + { + if ( filter.include( artifact ) ) + { + filteredArtifacts.add( artifact ); + } + } + } + + return filteredArtifacts; + } } diff --git a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java index 7cc472e5..2d8a2913 100644 --- a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java +++ b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java @@ -19,7 +19,11 @@ package org.apache.maven.plugin.plugin; * under the License. */ +import javax.lang.model.SourceVersion; + import java.io.File; +import java.util.Arrays; +import java.util.stream.Collectors; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; @@ -27,19 +31,19 @@ import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.tools.plugin.generator.Generator; +import org.apache.maven.tools.plugin.generator.GeneratorException; import org.apache.maven.tools.plugin.generator.PluginHelpGenerator; +import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.velocity.VelocityComponent; /** * Generates a <code>HelpMojo</code> class. - * - * @author <a href="mailto:[email protected]">Vincent Siveton</a> * + * @author <a href="mailto:[email protected]">Vincent Siveton</a> * @since 2.4 */ @Mojo( name = "helpmojo", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true, - requiresDependencyResolution = ResolutionScope.COMPILE ) + requiresDependencyResolution = ResolutionScope.COMPILE ) public class HelpGeneratorMojo extends AbstractGeneratorMojo { @@ -50,9 +54,14 @@ public class HelpGeneratorMojo protected File outputDirectory; /** - * The name of the package for the generated <code>HelpMojo</code>. By default, the package will be calculated based - * on the packages of the other plugin goals. - * + * The name of the package for the generated <code>HelpMojo</code>. + * <p> + * By default, the package name will be calculated as <code>groupId + "." + artifactId</code> with additional + * <ul> + * <li><code>-</code> (dashes) will be replaced by <code>_</code> (underscores)</li> + * <li><code>_</code> (underscore) will be added before each number or Java keyword at the beginning of name</li> + * </ul> + * * @since 2.6 */ @Parameter @@ -64,41 +73,59 @@ public class HelpGeneratorMojo @Component private VelocityComponent velocity; - /** - * {@inheritDoc} - */ - @Override - protected File getOutputDirectory() + String getHelpPackageName() { - return outputDirectory; + String packageName = null; + if ( StringUtils.isNotBlank( helpPackageName ) ) + { + packageName = helpPackageName; + } + + if ( packageName == null ) + { + packageName = project.getGroupId() + "." + project.getArtifactId(); + packageName = packageName.replace( "-", "_" ); + + String[] packageItems = packageName.split( "\\." ); + packageName = Arrays.stream( packageItems ) + .map( this::prefixSpecialCase ) + .collect( Collectors.joining( "." ) ); + } + + return packageName; } - /** - * {@inheritDoc} - */ - @Override - protected Generator createGenerator() + private String prefixSpecialCase( String name ) { - return new PluginHelpGenerator().setHelpPackageName( helpPackageName ).setVelocityComponent( this.velocity ); + if ( SourceVersion.isKeyword( name ) || !Character.isJavaIdentifierStart( name.charAt( 0 ) ) ) + { + name = "_" + name; + } + return name; } - /** - * {@inheritDoc} - */ @Override - public void execute() - throws MojoExecutionException + protected void generate() throws MojoExecutionException { - // force value for this plugin - skipErrorNoDescriptorsFound = true; + PluginHelpGenerator pluginHelpGenerator = new PluginHelpGenerator() + .setMavenProject( project ) + .setHelpPackageName( getHelpPackageName() ) + .setGoalPrefix( goalPrefix ) + .setVelocityComponent( velocity ); - super.execute(); + try + { + pluginHelpGenerator.execute( outputDirectory ); + } + catch ( GeneratorException e ) + { + throw new MojoExecutionException( e.getMessage(), e ); + } - if ( !project.getCompileSourceRoots().contains( outputDirectory.getAbsolutePath() ) && !skip ) + if ( !project.getCompileSourceRoots().contains( outputDirectory.getAbsolutePath() ) ) { project.addCompileSourceRoot( outputDirectory.getAbsolutePath() ); } - } } diff --git a/maven-plugin-plugin/src/test/java/org/apache/maven/plugin/plugin/HelpGeneratorMojoTest.java b/maven-plugin-plugin/src/test/java/org/apache/maven/plugin/plugin/HelpGeneratorMojoTest.java new file mode 100644 index 00000000..5d657091 --- /dev/null +++ b/maven-plugin-plugin/src/test/java/org/apache/maven/plugin/plugin/HelpGeneratorMojoTest.java @@ -0,0 +1,63 @@ +package org.apache.maven.plugin.plugin; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.stream.Stream; + +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HelpGeneratorMojoTest +{ + + public static Stream<Arguments> packageNameShouldBeCorrect() + { + return Stream.of( + Arguments.of( aProject( "groupId", "artifactId" ), "groupId.artifactId" ), + Arguments.of( aProject( "groupId", "123-artifactId" ), "groupId._123_artifactId" ), + Arguments.of( aProject( "group-Id", "artifact-Id" ), "group_Id.artifact_Id" ), + Arguments.of( aProject( "group-Id", "int" ), "group_Id._int" ) + ); + } + + @ParameterizedTest + @MethodSource + void packageNameShouldBeCorrect( MavenProject project, String expectedPackageName ) + { + HelpGeneratorMojo mojo = new HelpGeneratorMojo(); + mojo.project = project; + + String packageName = mojo.getHelpPackageName(); + assertEquals( expectedPackageName, packageName ); + } + + private static MavenProject aProject( String groupId, String artifactId ) + { + + MavenProject mavenProject = new MavenProject(); + mavenProject.setGroupId( groupId ); + mavenProject.setArtifactId( artifactId ); + return mavenProject; + } +} diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java index 6e777c08..70581131 100644 --- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java +++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java @@ -19,8 +19,6 @@ package org.apache.maven.tools.plugin.generator; * under the License. */ -import static java.nio.charset.StandardCharsets.UTF_8; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -31,12 +29,11 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.maven.plugin.descriptor.DuplicateMojoDescriptorException; + import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.Parameter; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.descriptor.Requirement; -import org.apache.maven.plugin.logging.Log; import org.apache.maven.project.MavenProject; import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; import org.apache.maven.tools.plugin.PluginToolsRequest; @@ -45,6 +42,8 @@ import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; import org.codehaus.plexus.util.xml.XMLWriter; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Generate a <a href="/ref/current/maven-plugin-api/plugin.html">Maven Plugin Descriptor XML file</a> and * corresponding <code>plugin-help.xml</code> help content for {@link PluginHelpGenerator}. @@ -54,20 +53,10 @@ public class PluginDescriptorGenerator implements Generator { - private final Log log; - - public PluginDescriptorGenerator( Log log ) - { - this.log = log; - } - @Override public void execute( File destinationDirectory, PluginToolsRequest request ) throws GeneratorException { - // eventually rewrite help mojo class to match actual package name - PluginHelpGenerator.rewriteHelpMojo( request, log ); - try { // write complete plugin.xml descriptor @@ -86,10 +75,6 @@ public class PluginDescriptorGenerator { throw new GeneratorException( e.getMessage(), e ); } - catch ( DuplicateMojoDescriptorException e ) - { - throw new GeneratorException( e.getMessage(), e ); - } } private String getVersion() @@ -100,7 +85,7 @@ public class PluginDescriptorGenerator } public void writeDescriptor( File destinationFile, PluginToolsRequest request, boolean helpDescriptor ) - throws IOException, DuplicateMojoDescriptorException + throws IOException { PluginDescriptor pluginDescriptor = request.getPluginDescriptor(); @@ -169,11 +154,6 @@ public class PluginDescriptorGenerator } } - protected void processMojoDescriptor( MojoDescriptor mojoDescriptor, XMLWriter w ) - { - processMojoDescriptor( mojoDescriptor, w, false ); - } - /** * @param mojoDescriptor not null * @param w not null diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java index d430e5a0..9149712c 100644 --- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java +++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java @@ -19,79 +19,42 @@ package org.apache.maven.tools.plugin.generator; * under the License. */ -import static java.nio.charset.StandardCharsets.UTF_8; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; -import org.apache.maven.plugin.descriptor.MojoDescriptor; -import org.apache.maven.plugin.descriptor.PluginDescriptor; -import org.apache.maven.plugin.logging.Log; import org.apache.maven.project.MavenProject; -import org.apache.maven.tools.plugin.PluginToolsRequest; import org.apache.velocity.VelocityContext; import org.codehaus.plexus.logging.AbstractLogEnabled; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.console.ConsoleLogger; import org.codehaus.plexus.util.FileUtils; -import org.codehaus.plexus.util.IOUtil; -import org.codehaus.plexus.util.PropertyUtils; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.velocity.VelocityComponent; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.commons.ClassRemapper; -import org.objectweb.asm.commons.Remapper; -import org.objectweb.asm.commons.SimpleRemapper; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.nio.charset.Charset; -import java.util.List; -import java.util.Properties; +import static java.nio.charset.StandardCharsets.UTF_8; /** * Generates an <code>HelpMojo</code> class from <code>help-class-source.vm</code> template. * The generated mojo reads help content from <code>META-INF/maven/${groupId}/${artifactId}/plugin-help.xml</code> * resource, which is generated by this {@link PluginDescriptorGenerator}. - * <p>Notice that the help mojo source needs to be generated before compilation, but when Java annotations are used, - * plugin descriptor content is available only after compilation (detecting annotations in .class files): - * help mojo source can be generated with empty package only (and no plugin descriptor available yet), then needs - * to be updated after compilation - through {@link #rewriteHelpMojo(PluginToolsRequest, Log)} which is called from - * plugin descriptor XML generation.</p> * * @author <a href="mailto:[email protected]">Vincent Siveton</a> * @since 2.4 */ public class PluginHelpGenerator extends AbstractLogEnabled - implements Generator { /** * Default generated class name */ private static final String HELP_MOJO_CLASS_NAME = "HelpMojo"; - /** - * Help properties file, to store data about generated source. - */ - private static final String HELP_PROPERTIES_FILENAME = "maven-plugin-help.properties"; - - /** - * Default goal - */ - private static final String HELP_GOAL = "help"; - private String helpPackageName; - - private boolean useAnnotations; - + private String goalPrefix; + private MavenProject mavenProject; private VelocityComponent velocityComponent; /** @@ -106,41 +69,10 @@ public class PluginHelpGenerator // Public methods // ---------------------------------------------------------------------- - /** - * {@inheritDoc} - */ - @Override - public void execute( File destinationDirectory, PluginToolsRequest request ) + public void execute( File destinationDirectory ) throws GeneratorException { - PluginDescriptor pluginDescriptor = request.getPluginDescriptor(); - - String helpImplementation = getImplementation( pluginDescriptor ); - - List<MojoDescriptor> mojoDescriptors = pluginDescriptor.getMojos(); - - if ( mojoDescriptors != null ) - { - // Verify that no help goal already exists - MojoDescriptor descriptor = pluginDescriptor.getMojo( HELP_GOAL ); - - if ( ( descriptor != null ) && !descriptor.getImplementation().equals( helpImplementation ) ) - { - if ( getLogger().isWarnEnabled() ) - { - getLogger().warn( "\n\nA help goal (" + descriptor.getImplementation() - + ") already exists in this plugin. SKIPPED THE " + helpImplementation - + " GENERATION.\n" ); - } - - return; - } - } - - writeHelpPropertiesFile( request, destinationDirectory ); - - useAnnotations = request.getProject().getArtifactMap().containsKey( - "org.apache.maven.plugin-tools:maven-plugin-annotations" ); + String helpImplementation = getImplementation(); try { @@ -150,9 +82,9 @@ public class PluginHelpGenerator helpClass.getParentFile().mkdirs(); String helpClassSources = - getHelpClassSources( getPluginHelpPath( request.getProject() ), pluginDescriptor ); + getHelpClassSources( getPluginHelpPath( mavenProject ) ); - FileUtils.fileWrite( helpClass, request.getEncoding(), helpClassSources ); + FileUtils.fileWrite( helpClass, UTF_8.name(), helpClassSources ); } catch ( IOException e ) { @@ -166,14 +98,21 @@ public class PluginHelpGenerator return this; } - public VelocityComponent getVelocityComponent() + public PluginHelpGenerator setVelocityComponent( VelocityComponent velocityComponent ) { - return velocityComponent; + this.velocityComponent = velocityComponent; + return this; } - public PluginHelpGenerator setVelocityComponent( VelocityComponent velocityComponent ) + public PluginHelpGenerator setGoalPrefix( String goalPrefix ) { - this.velocityComponent = velocityComponent; + this.goalPrefix = goalPrefix; + return this; + } + + public PluginHelpGenerator setMavenProject( MavenProject mavenProject ) + { + this.mavenProject = mavenProject; return this; } @@ -181,21 +120,17 @@ public class PluginHelpGenerator // Private methods // ---------------------------------------------------------------------- - private String getHelpClassSources( String pluginHelpPath, PluginDescriptor pluginDescriptor ) + private String getHelpClassSources( String pluginHelpPath ) throws IOException { VelocityContext context = new VelocityContext(); - if ( this.helpPackageName != null ) - { - context.put( "helpPackageName", this.helpPackageName ); - } - else - { - context.put( "helpPackageName", "" ); - } + boolean useAnnotations = mavenProject.getArtifactMap().containsKey( + "org.apache.maven.plugin-tools:maven-plugin-annotations" ); + + context.put( "helpPackageName", helpPackageName ); context.put( "pluginHelpPath", pluginHelpPath ); - context.put( "artifactId", pluginDescriptor.getArtifactId() ); - context.put( "goalPrefix", pluginDescriptor.getGoalPrefix() ); + context.put( "artifactId", mavenProject.getArtifactId() ); + context.put( "goalPrefix", goalPrefix ); context.put( "useAnnotations", useAnnotations ); StringWriter stringWriter = new StringWriter(); @@ -214,226 +149,17 @@ public class PluginHelpGenerator } /** - * @param pluginDescriptor The descriptor of the plugin for which to generate a help goal, must not be - * <code>null</code>. * @return The implementation. */ - private String getImplementation( PluginDescriptor pluginDescriptor ) + private String getImplementation( ) { - if ( StringUtils.isEmpty( helpPackageName ) ) - { - helpPackageName = GeneratorUtils.discoverPackageName( pluginDescriptor ); - } - return StringUtils.isEmpty( helpPackageName ) ? HELP_MOJO_CLASS_NAME : helpPackageName + '.' + HELP_MOJO_CLASS_NAME; } - /** - * Write help properties files for later use to eventually rewrite Help Mojo. - * - * @param request - * @throws GeneratorException - * @see {@link #rewriteHelpMojo(PluginToolsRequest, Log)} - */ - private void writeHelpPropertiesFile( PluginToolsRequest request, File destinationDirectory ) - throws GeneratorException - { - Properties properties = new Properties(); - properties.put( "helpPackageName", helpPackageName == null ? "" : helpPackageName ); - properties.put( "destinationDirectory", destinationDirectory.getAbsolutePath() ); - - File tmpPropertiesFile = new File( request.getProject().getBuild().getDirectory(), HELP_PROPERTIES_FILENAME ); - - if ( tmpPropertiesFile.exists() ) - { - tmpPropertiesFile.delete(); - } - else if ( !tmpPropertiesFile.getParentFile().exists() ) - { - tmpPropertiesFile.getParentFile().mkdirs(); - } - - try ( FileOutputStream fos = new FileOutputStream( tmpPropertiesFile ) ) - { - properties.store( fos, "maven plugin help mojo generation informations" ); - } - catch ( IOException e ) - { - throw new GeneratorException( e.getMessage(), e ); - } - } - static String getPluginHelpPath( MavenProject mavenProject ) { return mavenProject.getGroupId() + "/" + mavenProject.getArtifactId() + "/plugin-help.xml"; } - - /** - * Rewrite Help Mojo to match actual Mojos package name if it was not available at source generation - * time. This is used at descriptor generation time. - * - * @param request - * @throws GeneratorException - */ - static void rewriteHelpMojo( PluginToolsRequest request, Log log ) - throws GeneratorException - { - File tmpPropertiesFile = new File( request.getProject().getBuild().getDirectory(), HELP_PROPERTIES_FILENAME ); - - if ( !tmpPropertiesFile.exists() ) - { - return; - } - - Properties properties; - try - { - properties = PropertyUtils.loadProperties( tmpPropertiesFile ); - } - catch ( IOException e ) - { - throw new GeneratorException( e.getMessage(), e ); - } - - String helpPackageName = properties.getProperty( "helpPackageName" ); - - // if helpPackageName property is empty, we have to rewrite the class with a better package name than empty - if ( StringUtils.isEmpty( helpPackageName ) ) - { - String destDir = properties.getProperty( "destinationDirectory" ); - File destinationDirectory; - if ( StringUtils.isEmpty( destDir ) ) - { - // writeHelpPropertiesFile() creates 2 properties: find one without the other should not be possible - log.warn( "\n\nUnexpected situation: destinationDirectory not defined in " + HELP_PROPERTIES_FILENAME - + " during help mojo source generation but expected during XML descriptor generation." ); - log.warn( "Please check helpmojo goal version used in previous build phase." ); - log.warn( "If you just upgraded to plugin-tools >= 3.2 you must run a clean build at least once." ); - destinationDirectory = new File( "target/generated-sources/plugin" ); - log.warn( "Trying default location: " + destinationDirectory ); - } - else - { - destinationDirectory = new File( destDir ); - } - String helpMojoImplementation = rewriteHelpClassToMojoPackage( request, destinationDirectory, log ); - - if ( helpMojoImplementation != null ) - { - // rewrite plugin descriptor with new HelpMojo implementation class - updateHelpMojoDescriptor( request.getPluginDescriptor(), helpMojoImplementation ); - } - } - } - - private static String rewriteHelpClassToMojoPackage( PluginToolsRequest request, File destinationDirectory, - Log log ) - throws GeneratorException - { - String destinationPackage = GeneratorUtils.discoverPackageName( request.getPluginDescriptor() ); - if ( StringUtils.isEmpty( destinationPackage ) ) - { - return null; - } - String packageAsDirectory = StringUtils.replace( destinationPackage, '.', '/' ); - - String outputDirectory = request.getProject().getBuild().getOutputDirectory(); - File helpClassFile = new File( outputDirectory, HELP_MOJO_CLASS_NAME + ".class" ); - if ( !helpClassFile.exists() ) - { - return null; - } - - // rewrite help mojo source - File helpSourceFile = new File( destinationDirectory, HELP_MOJO_CLASS_NAME + ".java" ); - if ( !helpSourceFile.exists() ) - { - log.warn( "HelpMojo.java not found in default location: " + helpSourceFile.getAbsolutePath() ); - log.warn( "Help goal source won't be moved to package: " + destinationPackage ); - } - else - { - File helpSourceFileNew = - new File( destinationDirectory, packageAsDirectory + '/' + HELP_MOJO_CLASS_NAME + ".java" ); - if ( !helpSourceFileNew.getParentFile().exists() ) - { - helpSourceFileNew.getParentFile().mkdirs(); - } - Charset encoding = Charset.forName( request.getEncoding() ); - try ( Reader sourceReader = new InputStreamReader( new FileInputStream( helpSourceFile ), // - encoding ); // - PrintWriter sourceWriter = new PrintWriter( - new OutputStreamWriter( new FileOutputStream( helpSourceFileNew ), // - encoding ) ) ) - { - sourceWriter.println( "package " + destinationPackage + ";" ); - IOUtil.copy( sourceReader, sourceWriter ); - } - catch ( IOException e ) - { - throw new GeneratorException( e.getMessage(), e ); - } - helpSourceFileNew.setLastModified( helpSourceFile.lastModified() ); - helpSourceFile.delete(); - } - - // rewrite help mojo .class - File rewriteHelpClassFile = - new File( outputDirectory + '/' + packageAsDirectory, HELP_MOJO_CLASS_NAME + ".class" ); - if ( !rewriteHelpClassFile.getParentFile().exists() ) - { - rewriteHelpClassFile.getParentFile().mkdirs(); - } - - ClassReader cr; - try ( FileInputStream fileInputStream = new FileInputStream( helpClassFile ) ) - { - cr = new ClassReader( fileInputStream ); - } - catch ( IOException e ) - { - throw new GeneratorException( e.getMessage(), e ); - } - - ClassWriter cw = new ClassWriter( 0 ); - - Remapper packageRemapper = - new SimpleRemapper( HELP_MOJO_CLASS_NAME, packageAsDirectory + '/' + HELP_MOJO_CLASS_NAME ); - ClassVisitor cv = new ClassRemapper( cw, packageRemapper ); - - try - { - cr.accept( cv, ClassReader.EXPAND_FRAMES ); - } - catch ( Throwable e ) - { - throw new GeneratorException( "ASM issue processing class-file " + helpClassFile.getPath(), e ); - } - - byte[] renamedClass = cw.toByteArray(); - try ( FileOutputStream fos = new FileOutputStream( rewriteHelpClassFile ) ) - { - fos.write( renamedClass ); - } - catch ( IOException e ) - { - throw new GeneratorException( "Error rewriting help class: " + e.getMessage(), e ); - } - - helpClassFile.delete(); - - return destinationPackage + ".HelpMojo"; - } - - private static void updateHelpMojoDescriptor( PluginDescriptor pluginDescriptor, String helpMojoImplementation ) - { - MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( HELP_GOAL ); - - if ( mojoDescriptor != null ) - { - mojoDescriptor.setImplementation( helpMojoImplementation ); - } - } } diff --git a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginHelpGeneratorTest.java b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginHelpGeneratorTest.java deleted file mode 100644 index e82453d0..00000000 --- a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginHelpGeneratorTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.apache.maven.tools.plugin.generator; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import javax.inject.Inject; - -import org.codehaus.plexus.testing.PlexusTest; -import org.codehaus.plexus.velocity.VelocityComponent; - -/** - * @author <a href="mailto:[email protected]">Vincent Siveton</a> - */ -@PlexusTest -public class PluginHelpGeneratorTest - extends AbstractGeneratorTestCase -{ - - @Inject - VelocityComponent velocityComponent; - - // inherits tests from base class - @Override - protected void setupGenerator() - throws Exception - { - generator = new PluginHelpGenerator().setVelocityComponent( velocityComponent ); - - } -} diff --git a/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java b/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java index b804d2f8..e734dc7f 100644 --- a/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java +++ b/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java @@ -128,7 +128,7 @@ public class JavaMojoDescriptorExtractorTest request.getPluginDescriptor().addMojo( mojoDescriptor ); } - Generator descriptorGenerator = new PluginDescriptorGenerator( new SystemStreamLog() ); + Generator descriptorGenerator = new PluginDescriptorGenerator(); descriptorGenerator.execute( new File( root, directory ), request ); diff --git a/pom.xml b/pom.xml index c1ea31da..0395708f 100644 --- a/pom.xml +++ b/pom.xml @@ -247,10 +247,11 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-engine</artifactId> + <groupId>org.junit</groupId> + <artifactId>junit-bom</artifactId> <version>5.8.2</version> - <scope>test</scope> + <type>pom</type> + <scope>import</scope> </dependency> <dependency> <groupId>org.codehaus.plexus</groupId>
