Skip to content

Commit

Permalink
Incomplete runtime classpath fix
Browse files Browse the repository at this point in the history
Similar fix to m-assembly-p: do not rely on Maven Core to provide
"runtime" resolution scope as it have issues, see:
https://issues.apache.org/jira/browse/MNG-8041

Instead, use Resolver APIs directly to get what is needed.
Contains several minor code improvements across Provisio
maven-plugin module.

Other changes in this PR:
* added support for -X to dump proviso graph
* marked Mojos as thread safe, removed now unneeded ask for resolution
  (as they use Resolver APIs)

Contains IT from jvanzyl#70
Fixes jvanzyl#71
  • Loading branch information
cstamas committed Feb 9, 2024
1 parent b531aca commit 00b2d6c
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,14 @@
import org.eclipse.aether.util.filter.AndDependencyFilter;
import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
import org.eclipse.aether.util.filter.ScopeDependencyFilter;
import org.eclipse.aether.util.graph.visitor.DependencyGraphDumper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.util.stream.Collectors.toSet;

public class MavenProvisioner {
private static final Logger logger = LoggerFactory.getLogger(MavenProvisioner.class);

private final RepositorySystem repositorySystem;
private final RepositorySystemSession repositorySystemSession;
Expand Down Expand Up @@ -379,7 +383,7 @@ else if (getArtifactType(artifact.getExtension()) == null) {
//
// Add an exclude filter if necessary
//
DependencyFilter systemScopeFilter = new ScopeDependencyFilter(JavaScopes.SYSTEM);
DependencyFilter systemScopeFilter = new ScopeDependencyFilter(JavaScopes.SYSTEM, JavaScopes.PROVIDED, JavaScopes.TEST);
DependencyRequest dependencyRequest = new DependencyRequest(request, null);
if (excludes != null) {
List<String> exclusions = new ArrayList<>();
Expand Down Expand Up @@ -443,6 +447,12 @@ private List<Artifact> resolveArtifacts(DependencyRequest request) throws Depend
}
}
DependencyResult result = repositorySystem.resolveDependencies(repositorySystemSession, request);

if (logger.isDebugEnabled() && result.getRoot() != null) {
logger.debug("MavenProvisioner -- Collection result for {}", request.getCollectRequest());
result.getRoot().accept(new DependencyGraphDumper(logger::debug));
}

List<Artifact> artifacts = new ArrayList<Artifact>();
for (ArtifactResult ar : result.getArtifactResults()) {
artifacts.add(ar.getArtifact());
Expand Down
5 changes: 5 additions & 0 deletions provisio-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@
<artifactId>maven-resolver-impl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-util</artifactId>
<!-- NOT provided: to work with 3.8 and 3.9 -->
</dependency>
<!-- Test -->
<dependency>
<groupId>io.takari.maven.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@
import ca.vanzyl.provisio.model.Runtime;
import io.takari.incrementalbuild.Incremental;
import io.takari.incrementalbuild.Incremental.Configuration;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.ArtifactProperties;
import org.eclipse.aether.artifact.ArtifactType;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.artifact.DefaultArtifactType;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.graph.DefaultDependencyNode;
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.artifact.JavaScopes;
import org.eclipse.aether.util.filter.ScopeDependencyFilter;
import org.eclipse.aether.util.graph.visitor.DependencyGraphDumper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -83,20 +83,22 @@ public abstract class BaseMojo
@Parameter(required = true, defaultValue = "${basedir}/src/main/provisio")
protected File descriptorDirectory;

@Parameter(defaultValue = "${session}")
protected MavenSession session;

protected ProvisioArtifact projectArtifact() {
ProvisioArtifact jarArtifact = null;
//
// We also need to definitively know what others types of runtime artifacts have been created. Right now there
// is no real protocol for knowing what something like, say, the JAR plugin did to drop off a file somewhere. We
// need to improve this but for now we'll look.
// ===
// While this above is still true, this check below is better, in a sense it allows JAR plugin to drop off file
// anywhere.
//
File jar = new File(project.getBuild().getDirectory(), project.getArtifactId() + "-" + project.getVersion() + ".jar");
if (jar.exists()) {
Artifact projectArtifact = RepositoryUtils.toArtifact(project.getArtifact());
if (projectArtifact.getFile() != null
&& projectArtifact.getFile().getName().endsWith(".jar")
&& projectArtifact.getFile().exists()) {
jarArtifact = new ProvisioArtifact(project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getVersion());
jarArtifact.setFile(jar);
jarArtifact.setFile(projectArtifact.getFile());
}
return jarArtifact;
}
Expand All @@ -113,39 +115,51 @@ protected ArtifactSet getRuntimeClasspathAsArtifactSet() {
// for this Mojo. I think this will be sufficient for anything related to creating a runtime.
//
ArtifactSet artifactSet = new ArtifactSet();
for (org.apache.maven.artifact.Artifact mavenArtifact : project.getArtifacts()) {
if (!mavenArtifact.getScope().equals("system") && !mavenArtifact.getScope().equals("provided")) {
artifactSet.addArtifact(new ProvisioArtifact(toArtifact(mavenArtifact)));
}
for (Artifact mavenArtifact : resolveRuntimeScopeTransitively()) {
artifactSet.addArtifact(new ProvisioArtifact(mavenArtifact));
}
return artifactSet;
}

private static Artifact toArtifact(org.apache.maven.artifact.Artifact artifact) {
if (artifact == null) {
return null;
}

String version = artifact.getVersion();
if (version == null && artifact.getVersionRange() != null) {
version = artifact.getVersionRange().toString();
}

Map<String, String> props = null;
if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
String localPath = (artifact.getFile() != null) ? artifact.getFile().getPath() : "";
props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, localPath);
/**
* This method is in use instead of project offering mojo asked resolution scope due presence of:
* <a href="https://issues.apache.org/jira/browse/MNG-8041">MNG-8041</a>
*/
private List<Artifact> resolveRuntimeScopeTransitively() {
DependencyFilter runtimeFilter = new ScopeDependencyFilter(JavaScopes.SYSTEM, JavaScopes.PROVIDED, JavaScopes.TEST);
List<org.eclipse.aether.graph.Dependency> dependencies = project.getDependencies().stream()
.map(d -> RepositoryUtils.toDependency(d, repositorySystemSession.getArtifactTypeRegistry()))
.filter(d -> !JavaScopes.TEST.equals(d.getScope()))
.collect(Collectors.toList());
List<org.eclipse.aether.graph.Dependency> managedDependencies = Collections.emptyList();
if (project.getDependencyManagement() != null) {
managedDependencies = project.getDependencyManagement().getDependencies().stream()
.map(d -> RepositoryUtils.toDependency(d, repositorySystemSession.getArtifactTypeRegistry()))
.collect(Collectors.toList());
}

Artifact result = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), artifact.getArtifactHandler().getExtension(), version, props,
newArtifactType(artifact.getType(), artifact.getArtifactHandler()));
result = result.setFile(artifact.getFile());

return result;
}
CollectRequest collectRequest = new CollectRequest();
collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
collectRequest.setRepositories(project.getRemoteProjectRepositories());
collectRequest.setDependencies(dependencies);
collectRequest.setManagedDependencies(managedDependencies);
DependencyRequest request = new DependencyRequest(collectRequest, runtimeFilter);
try {
DependencyResult result = repositorySystem.resolveDependencies(repositorySystemSession, request);

if (logger.isDebugEnabled() && result.getRoot() != null) {
logger.debug("BaseMojo -- Collection result for {}", request.getCollectRequest());
result.getRoot().accept(new DependencyGraphDumper(logger::debug));
}

private static ArtifactType newArtifactType(String id, ArtifactHandler handler) {
return new DefaultArtifactType(id, handler.getExtension(), handler.getClassifier(), handler.getLanguage(), handler.isAddedToClasspath(), handler.isIncludesDependencies());
return result.getArtifactResults().stream()
.map(ArtifactResult::getArtifact)
.collect(Collectors.toList());
} catch (DependencyResolutionException e) {
logger.error("Failed to resolve runtime dependencies", e);
throw new RuntimeException(e);
}
}

protected ProvisioningRequest getRequest(Runtime runtime)
Expand Down Expand Up @@ -173,7 +187,7 @@ protected void checkDuplicates(List<ProvisioArtifact> artifacts)
.filter(strings -> strings.size() > 1)
.map(strings -> String.join(", ", strings))
.collect(Collectors.toList());
if (duplicates.size() != 0) {
if (!duplicates.isEmpty()) {
throw new MojoFailureException("Found different versions of the same dependency: " + String.join(", ", duplicates));
}
}
Expand All @@ -186,10 +200,10 @@ protected List<Dependency> getDependencies(List<ProvisioArtifact> artifacts)
dependency.setGroupId(artifact.getGroupId());
dependency.setArtifactId(artifact.getArtifactId());
dependency.setVersion(artifact.getVersion());
if (artifact.getClassifier() != null && artifact.getClassifier().length() != 0) {
if (artifact.getClassifier() != null && !artifact.getClassifier().isEmpty()) {
dependency.setClassifier(artifact.getClassifier());
}
if (artifact.getExtension() != null && artifact.getExtension().length() != 0 && !artifact.getExtension().equals("jar")) {
if (artifact.getExtension() != null && !artifact.getExtension().isEmpty() && !artifact.getExtension().equals("jar")) {
dependency.setType(artifact.getExtension());
}
dependencies.add(dependency);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
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.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.WriterFactory;

import java.io.File;
Expand All @@ -38,7 +36,7 @@
import java.util.ArrayList;
import java.util.List;

@Mojo(name = "generateDependencies", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
@Mojo(name = "generateDependencies", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true)
public class GeneratorMojo
extends BaseMojo
{
Expand All @@ -48,6 +46,7 @@ public class GeneratorMojo
@Parameter(property = "dependencyExtendedPomLocation", defaultValue = "${project.build.directory}/generated/provisio/dependency-extended-pom.xml")
private File dependencyExtendedPomLocation;

@Override
public void execute()
throws MojoExecutionException, MojoFailureException
{
Expand All @@ -65,7 +64,7 @@ public void execute()
throw new MojoExecutionException("Error resolving artifacts.", e);
}
}
if (artifacts.size() == 0) {
if (artifacts.isEmpty()) {
return;
}
checkDuplicates(artifacts);
Expand All @@ -85,17 +84,11 @@ private void writeModel(Model model)
} catch (IOException e) {
throw new MojoExecutionException("Error creating parent directories for the POM file: " + e.getMessage(), e);
}
Writer writer = null;
try {
writer = WriterFactory.newXmlWriter(dependencyExtendedPomLocation);
try (Writer writer = WriterFactory.newXmlWriter(dependencyExtendedPomLocation)) {
new MavenXpp3Writer().write(writer, model);
writer.close();
}
catch (IOException e) {
throw new MojoExecutionException("Error writing POM file: " + e.getMessage(), e);
}
finally {
IOUtil.close(writer);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,26 +147,24 @@ public List<String> getManagedDependencies(MavenProject project) {
}

public String toCoordinate(Dependency d) {
StringBuffer sb = new StringBuffer().append(d.getGroupId()).append(":").append(d.getArtifactId()).append(":").append(d.getType());
if (d.getClassifier() != null && d.getClassifier().isEmpty() == false) {
StringBuilder sb = new StringBuilder().append(d.getGroupId()).append(":").append(d.getArtifactId()).append(":").append(d.getType());
if (d.getClassifier() != null && !d.getClassifier().isEmpty()) {
sb.append(":").append(d.getClassifier());
}
sb.append(":").append(d.getVersion());
return sb.toString();
}

public String toVersionlessCoordinate(Dependency d) {
StringBuffer sb = new StringBuffer().append(d.getGroupId()).append(":").append(d.getArtifactId()).append(":").append(d.getType());
if (d.getClassifier() != null && d.getClassifier().isEmpty() == false) {
StringBuilder sb = new StringBuilder().append(d.getGroupId()).append(":").append(d.getArtifactId()).append(":").append(d.getType());
if (d.getClassifier() != null && !d.getClassifier().isEmpty()) {
sb.append(":").append(d.getClassifier());
}
return sb.toString();
}

public String toVersionlessCoordinate(MavenProject project) {
String extension = artifactHandlerManager.getArtifactHandler(project.getPackaging()).getExtension();
StringBuffer sb = new StringBuffer().append(project.getGroupId()).append(":").append(project.getArtifactId()).append(":").append(extension);
return sb.toString();
return project.getGroupId() + ":" + project.getArtifactId() + ":" + extension;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@
import ca.vanzyl.provisio.model.ProvisioningResult;
import ca.vanzyl.provisio.model.Runtime;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
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 ca.vanzyl.provisio.MavenProvisioner;

@Mojo(name = "provision", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
@Mojo(name = "provision", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true)
public class ProvisioningMojo extends BaseMojo {

@Parameter(defaultValue = "false", property = "skipProvision")
Expand All @@ -41,6 +39,7 @@ public class ProvisioningMojo extends BaseMojo {
@Parameter(defaultValue = "${project.build.directory}/${project.artifactId}-${project.version}")
private File outputDirectory;

@Override
public void execute() throws MojoExecutionException {
if (skipProvision) {
getLog().info("Skipping provision");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;

import java.io.File;
import java.util.ArrayList;
Expand All @@ -34,7 +33,7 @@
import java.util.Set;
import java.util.stream.Collectors;

@Mojo(name = "validateDependencies", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
@Mojo(name = "validateDependencies", threadSafe = true)
public class ValidatorMojo
extends BaseMojo
{
Expand All @@ -44,6 +43,7 @@ public class ValidatorMojo
@Parameter(required = true, property = "pomFile", defaultValue = "${basedir}/pom.xml")
private File pomFile;

@Override
public void execute()
throws MojoExecutionException, MojoFailureException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
import static org.junit.Assert.assertArrayEquals;

@RunWith(MavenJUnitTestRunner.class)
@MavenVersions({"3.6.3", "3.8.4"})
@MavenVersions({"3.6.3", "3.8.8", "3.9.6"})
@SuppressWarnings({"JUnitTestNG", "PublicField"})
public class GeneratorIntegrationTest
{
Expand Down
Loading

0 comments on commit 00b2d6c

Please sign in to comment.