diff --git a/pom.xml b/pom.xml index 4214270e..062a6249 100644 --- a/pom.xml +++ b/pom.xml @@ -108,6 +108,16 @@ Feature Contributor + + Adam Retter + adam@evolvedbinary.com + Evolved Binary + https://www.evolvedbinary.com + + Patch Contributor + + Europe/London + diff --git a/src/it/projects/exec-plugin-dependencies/invoker.properties b/src/it/projects/exec-plugin-dependencies/invoker.properties new file mode 100644 index 00000000..e7cc4a85 --- /dev/null +++ b/src/it/projects/exec-plugin-dependencies/invoker.properties @@ -0,0 +1 @@ +invoker.goals = exec:exec diff --git a/src/it/projects/exec-plugin-dependencies/pom.xml b/src/it/projects/exec-plugin-dependencies/pom.xml new file mode 100644 index 00000000..f2aa2cdb --- /dev/null +++ b/src/it/projects/exec-plugin-dependencies/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + + org.codehaus.mojo.exec.it + parent + 0.1 + + + exec-plugin-dependencies + 0.0.1-SNAPSHOT + + + + + org.codehaus.mojo + exec-maven-plugin + @project.version@ + + + generate-resources + + exec + + + + + true + ${JAVA_HOME}/bin/java + + -classpath + + com.sun.tools.xjc.XJCFacade + -version + + + 255 + -1 + + + + + com.sun.xml.bind + jaxb-xjc + 3.0.2 + + + + + + + diff --git a/src/main/java/org/codehaus/mojo/exec/AbstractExecMojo.java b/src/main/java/org/codehaus/mojo/exec/AbstractExecMojo.java index d859776a..5b32bc5c 100644 --- a/src/main/java/org/codehaus/mojo/exec/AbstractExecMojo.java +++ b/src/main/java/org/codehaus/mojo/exec/AbstractExecMojo.java @@ -22,18 +22,31 @@ import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.cli.CommandLineUtils; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyFilter; +import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.DependencyResolutionException; +import org.eclipse.aether.resolution.DependencyResult; +import org.eclipse.aether.util.filter.DependencyFilterUtils; /** * This class is used for unifying functionality between the 2 mojo exec plugins ('java' and 'exec'). It handles parsing @@ -43,12 +56,19 @@ * @author Jerome Lacoste */ public abstract class AbstractExecMojo extends AbstractMojo { + + @Component + protected RepositorySystem repositorySystem; + /** * The enclosing project. */ @Parameter(defaultValue = "${project}", readonly = true) protected MavenProject project; + /** + * The current build session instance. This is used for toolchain manager API calls. + */ @Parameter(defaultValue = "${session}", readonly = true, required = true) private MavenSession session; @@ -134,6 +154,19 @@ public abstract class AbstractExecMojo extends AbstractMojo { @Parameter(property = "addOutputToClasspath", defaultValue = "true") private boolean addOutputToClasspath; + /** + * Indicates if this plugin's dependencies should be used when executing the main class. + *

+ * This is useful when project dependencies are not appropriate. Using only the plugin dependencies can be + * particularly useful when the project is not a java project. For example a mvn project using the csharp plugins + * only expects to see dotnet libraries as dependencies. + *

+ * + * @since 3.4.0 + */ + @Parameter(property = "exec.includePluginsDependencies", defaultValue = "false") + protected boolean includePluginDependencies; + /** * Collects the project artifacts in the specified List and the project specific classpath (build output and build * test output) Files in the specified List, depending on the plugin classpathScope value. @@ -266,4 +299,61 @@ protected Artifact findExecutableArtifact() throws MojoExecutionException { return executableTool; } + + /** + * Determine all plugin dependencies relevant to the executable. Takes includePlugins, and the executableDependency + * into consideration. + * + * @return a set of Artifact objects. (Empty set is returned if there are no relevant plugin dependencies.) + * @throws MojoExecutionException if a problem happens resolving the plufin dependencies + */ + protected Set determineRelevantPluginDependencies() throws MojoExecutionException { + Set relevantDependencies; + if (this.includePluginDependencies) { + if (this.executableDependency == null) { + getLog().debug("All Plugin Dependencies will be included."); + relevantDependencies = new HashSet<>(this.getPluginDependencies()); + } else { + getLog().debug("Selected plugin Dependencies will be included."); + Artifact executableArtifact = this.findExecutableArtifact(); + relevantDependencies = this.resolveExecutableDependencies(executableArtifact); + } + } else { + relevantDependencies = Collections.emptySet(); + getLog().debug("Plugin Dependencies will be excluded."); + } + return relevantDependencies; + } + + /** + * Resolve the executable dependencies for the specified project + * + * @param executableArtifact the executable plugin dependency + * @return a set of Artifacts + * @throws MojoExecutionException if a failure happens + */ + private Set resolveExecutableDependencies(Artifact executableArtifact) throws MojoExecutionException { + try { + CollectRequest collectRequest = new CollectRequest(); + collectRequest.setRoot(new Dependency(RepositoryUtils.toArtifact(executableArtifact), classpathScope)); + collectRequest.setRepositories(project.getRemotePluginRepositories()); + + DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(classpathScope); + + DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, classpathFilter); + + DependencyResult dependencyResult = + repositorySystem.resolveDependencies(getSession().getRepositorySession(), dependencyRequest); + + return dependencyResult.getArtifactResults().stream() + .map(ArtifactResult::getArtifact) + .map(RepositoryUtils::toArtifact) + .collect(Collectors.toSet()); + } catch (DependencyResolutionException ex) { + throw new MojoExecutionException( + "Encountered problems resolving dependencies of the executable " + + "in preparation for its execution.", + ex); + } + } } diff --git a/src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java b/src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java index 3aeeadc7..903c80c8 100644 --- a/src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java +++ b/src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java @@ -12,7 +12,6 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -23,10 +22,8 @@ import java.util.concurrent.ForkJoinPool; import java.util.function.BiConsumer; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -36,19 +33,10 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.collection.CollectRequest; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyFilter; -import org.eclipse.aether.resolution.ArtifactResult; -import org.eclipse.aether.resolution.DependencyRequest; -import org.eclipse.aether.resolution.DependencyResolutionException; -import org.eclipse.aether.resolution.DependencyResult; import org.eclipse.aether.resolution.VersionRangeRequest; import org.eclipse.aether.resolution.VersionRangeResolutionException; import org.eclipse.aether.resolution.VersionRangeResult; -import org.eclipse.aether.util.filter.DependencyFilterUtils; import static java.util.stream.Collectors.toList; @@ -64,9 +52,6 @@ public class ExecJavaMojo extends AbstractExecMojo { private static final String THREAD_STOP_UNAVAILABLE = "Thread.stop() is unavailable in this JRE version, cannot force-stop any threads"; - @Component - private RepositorySystem repositorySystem; - /** * The main class to execute.
* With Java 9 and above you can prefix it with the modulename, e.g. com.greetings/com.greetings.Main @@ -139,18 +124,6 @@ public class ExecJavaMojo extends AbstractExecMojo { @Parameter(property = "exec.includeProjectDependencies", defaultValue = "true") private boolean includeProjectDependencies; - /** - * Indicates if this plugin's dependencies should be used when executing the main class. - *

- * This is useful when project dependencies are not appropriate. Using only the plugin dependencies can be - * particularly useful when the project is not a java project. For example a mvn project using the csharp plugins - * only expects to see dotnet libraries as dependencies. - * - * @since 1.1-beta-1 - */ - @Parameter(property = "exec.includePluginsDependencies", defaultValue = "false") - private boolean includePluginDependencies; - /** * Whether to interrupt/join and possibly stop the daemon threads upon quitting.
* If this is false, maven does nothing about the daemon threads. When maven has no more work to do, @@ -780,63 +753,6 @@ private void addRelevantProjectDependenciesToClasspath(List path) { } } - /** - * Determine all plugin dependencies relevant to the executable. Takes includePlugins, and the executableDependency - * into consideration. - * - * @return a set of Artifact objects. (Empty set is returned if there are no relevant plugin dependencies.) - * @throws MojoExecutionException if a problem happens resolving the plufin dependencies - */ - private Set determineRelevantPluginDependencies() throws MojoExecutionException { - Set relevantDependencies; - if (this.includePluginDependencies) { - if (this.executableDependency == null) { - getLog().debug("All Plugin Dependencies will be included."); - relevantDependencies = new HashSet<>(this.getPluginDependencies()); - } else { - getLog().debug("Selected plugin Dependencies will be included."); - Artifact executableArtifact = this.findExecutableArtifact(); - relevantDependencies = this.resolveExecutableDependencies(executableArtifact); - } - } else { - relevantDependencies = Collections.emptySet(); - getLog().debug("Plugin Dependencies will be excluded."); - } - return relevantDependencies; - } - - /** - * Resolve the executable dependencies for the specified project - * - * @param executableArtifact the executable plugin dependency - * @return a set of Artifacts - * @throws MojoExecutionException if a failure happens - */ - private Set resolveExecutableDependencies(Artifact executableArtifact) throws MojoExecutionException { - try { - CollectRequest collectRequest = new CollectRequest(); - collectRequest.setRoot(new Dependency(RepositoryUtils.toArtifact(executableArtifact), classpathScope)); - collectRequest.setRepositories(project.getRemotePluginRepositories()); - - DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(classpathScope); - - DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, classpathFilter); - - DependencyResult dependencyResult = - repositorySystem.resolveDependencies(getSession().getRepositorySession(), dependencyRequest); - - return dependencyResult.getArtifactResults().stream() - .map(ArtifactResult::getArtifact) - .map(RepositoryUtils::toArtifact) - .collect(Collectors.toSet()); - } catch (DependencyResolutionException ex) { - throw new MojoExecutionException( - "Encountered problems resolving dependencies of the executable " - + "in preparation for its execution.", - ex); - } - } - /** * Stop program execution for nn millis. * diff --git a/src/main/java/org/codehaus/mojo/exec/ExecMojo.java b/src/main/java/org/codehaus/mojo/exec/ExecMojo.java index 797551e4..18321408 100644 --- a/src/main/java/org/codehaus/mojo/exec/ExecMojo.java +++ b/src/main/java/org/codehaus/mojo/exec/ExecMojo.java @@ -675,7 +675,7 @@ private boolean isJavaExec() { * default classpath will be used) * @return a platform specific String representation of the classpath */ - private String computeClasspathString(AbstractPath specifiedClasspath) { + private String computeClasspathString(AbstractPath specifiedClasspath) throws MojoExecutionException { List resultList = computePath(specifiedClasspath); StringBuffer theClasspath = new StringBuffer(); @@ -695,13 +695,18 @@ private String computeClasspathString(AbstractPath specifiedClasspath) { * default classpath will be used) * @return a list of class path elements */ - private List computePath(AbstractPath specifiedClasspath) { + private List computePath(AbstractPath specifiedClasspath) throws MojoExecutionException { List artifacts = new ArrayList<>(); List theClasspathFiles = new ArrayList<>(); List resultList = new ArrayList<>(); collectProjectArtifactsAndClasspath(artifacts, theClasspathFiles); + Set pluginDependencies = determineRelevantPluginDependencies(); + if (pluginDependencies != null) { + artifacts.addAll(pluginDependencies); + } + if ((specifiedClasspath != null) && (specifiedClasspath.getDependencies() != null)) { artifacts = filterArtifacts(artifacts, specifiedClasspath.getDependencies()); }