Skip to content

Commit

Permalink
Allow <includePluginDependencies> to be specified for the exec:exec goal
Browse files Browse the repository at this point in the history
  • Loading branch information
adamretter authored and slawekjaranowski committed Jun 1, 2024
1 parent dced4f5 commit d4a4b30
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 86 deletions.
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

0 comments on commit d4a4b30

Please sign in to comment.