Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow <includePluginDependencies> to be specified for the exec:exec goal #432

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@
<role>Feature Contributor</role>
</roles>
</contributor>
<contributor>
<name>Adam Retter</name>
<email>adam@evolvedbinary.com</email>
<organization>Evolved Binary</organization>
<organizationUrl>https://www.evolvedbinary.com</organizationUrl>
<roles>
<role>Patch Contributor</role>
</roles>
<timezone>Europe/London</timezone>
</contributor>
</contributors>

<prerequisites>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invoker.goals = exec:exec
54 changes: 54 additions & 0 deletions src/it/projects/exec-plugin-dependencies/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.codehaus.mojo.exec.it</groupId>
<artifactId>parent</artifactId>
<version>0.1</version>
</parent>

<artifactId>exec-plugin-dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<includePluginDependencies>true</includePluginDependencies>
<executable>${JAVA_HOME}/bin/java</executable>
<arguments>
<argument>-classpath</argument>
<classpath/>
<argument>com.sun.tools.xjc.XJCFacade</argument>
<argument>-version</argument>
</arguments>
<successCodes>
<code>255</code> <!-- nix -->
<code>-1</code> <!-- Windows -->
</successCodes>
</configuration>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

</project>
90 changes: 90 additions & 0 deletions src/main/java/org/codehaus/mojo/exec/AbstractExecMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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.
* <p>
* 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.
* </p>
*
* @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.
Expand Down Expand Up @@ -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<Artifact> determineRelevantPluginDependencies() throws MojoExecutionException {
Set<Artifact> 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<Artifact> 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);
}
}
}
84 changes: 0 additions & 84 deletions src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;

Expand All @@ -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.<br>
* With Java 9 and above you can prefix it with the modulename, e.g. <code>com.greetings/com.greetings.Main</code>
Expand Down Expand Up @@ -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.
* <p/>
* 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. <br/>
* If this is <code>false</code>, maven does nothing about the daemon threads. When maven has no more work to do,
Expand Down Expand Up @@ -780,63 +753,6 @@ private void addRelevantProjectDependenciesToClasspath(List<Path> 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<Artifact> determineRelevantPluginDependencies() throws MojoExecutionException {
Set<Artifact> 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<Artifact> 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.
*
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/codehaus/mojo/exec/ExecMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> resultList = computePath(specifiedClasspath);
StringBuffer theClasspath = new StringBuffer();

Expand All @@ -695,13 +695,18 @@ private String computeClasspathString(AbstractPath specifiedClasspath) {
* default classpath will be used)
* @return a list of class path elements
*/
private List<String> computePath(AbstractPath specifiedClasspath) {
private List<String> computePath(AbstractPath specifiedClasspath) throws MojoExecutionException {
List<Artifact> artifacts = new ArrayList<>();
List<Path> theClasspathFiles = new ArrayList<>();
List<String> resultList = new ArrayList<>();

collectProjectArtifactsAndClasspath(artifacts, theClasspathFiles);

Set<Artifact> pluginDependencies = determineRelevantPluginDependencies();
if (pluginDependencies != null) {
artifacts.addAll(pluginDependencies);
}

if ((specifiedClasspath != null) && (specifiedClasspath.getDependencies() != null)) {
artifacts = filterArtifacts(artifacts, specifiedClasspath.getDependencies());
}
Expand Down