Skip to content

Commit

Permalink
Added an option to record all direct dependencies of each component when
Browse files Browse the repository at this point in the history
generating a manifest
  • Loading branch information
aloubyansky committed Nov 7, 2023
1 parent 7f47d13 commit 3fd3494
Show file tree
Hide file tree
Showing 13 changed files with 380 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ interface DependencyVisit {

void enterDependency(DependencyVisit visit);

/**
* In case the Maven artifact resolver was configured to return verbose dependency graphs,
* this method will be called to indicate the current dependency graph node has a dependency
* on another node with the passed in coordinates whose dependencies will be walked over
* in a different branch of the graph.
*
* @param coords artifact coordinates of a dependency
*/
default void linkDependency(ArtifactCoords coords) {
}

void leaveDependency(DependencyVisit visit);

void enterParentPom(DependencyVisit visit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ public void enterDependency(DependencyVisit visit) {
logComment(sb.toString());
}

@Override
public void linkDependency(ArtifactCoords coords) {
if (!loggingEnabled) {
return;
}
final StringBuilder sb = new StringBuilder();
for (int i = 0; i <= level; ++i) {
sb.append(" ");
}
sb.append(coords.toCompactCoords());
sb.append(" [linked]");
logComment(sb.toString());
}

@Override
public void leaveDependency(DependencyVisit visit) {
if (!loggingEnabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ public interface ProjectDependencyConfig {
*/
int getLevel();

/**
* Whether verbose dependency graphs should be enabled in the underlying dependency resolver.
* This means exposing information about winning nodes during conflict resolution.
*
* @return whether verbose dependency graphs are enabled in the resolver
*/
boolean isVerboseGraphs();

/**
* Whether to log the coordinates of the artifacts captured down to the depth specified. The default is true.
*
Expand Down Expand Up @@ -306,6 +314,8 @@ default Mutable setExcludeKeys(Collection<ArtifactKey> artifactKeys) {

Mutable setLevel(int level);

Mutable setVerboseGraphs(boolean verboseGraphs);

Mutable setLogArtifactsToBuild(boolean logArtifactsToBuild);

Mutable setLogModulesToBuild(boolean logModulesToBuild);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.eclipse.aether.util.artifact.JavaScopes;

@JsonInclude(JsonInclude.Include.NON_DEFAULT)
public class ProjectDependencyConfigImpl implements ProjectDependencyConfig {
Expand All @@ -27,6 +29,7 @@ public class ProjectDependencyConfigImpl implements ProjectDependencyConfig {
private final boolean excludeParentPoms;
private final boolean excludeBomImports;
private final int level;
private final boolean verboseGraphs;
private final boolean logArtifactsToBuild;
private final boolean logModulesToBuild;
private final boolean logTrees;
Expand Down Expand Up @@ -65,6 +68,7 @@ private ProjectDependencyConfigImpl(ProjectDependencyConfig other) {
excludeParentPoms = other.isExcludeParentPoms();
excludeBomImports = other.isExcludeBomImports();
level = other.getLevel();
verboseGraphs = other.isVerboseGraphs();
logArtifactsToBuild = other.isLogArtifactsToBuild();
logModulesToBuild = other.isLogModulesToBuild();
logTrees = other.isLogTrees();
Expand Down Expand Up @@ -159,6 +163,11 @@ public int getLevel() {
return level;
}

@Override
public boolean isVerboseGraphs() {
return verboseGraphs;
}

@Override
public boolean isLogArtifactsToBuild() {
return logArtifactsToBuild;
Expand Down Expand Up @@ -263,11 +272,12 @@ static class Builder implements ProjectDependencyConfig.Mutable {
private Collection<ArtifactCoords> includeArtifacts = new ArrayList<>();
private Collection<ArtifactCoords> includePatterns = new ArrayList<>();
private Collection<ArtifactCoords> excludePatterns = new ArrayList<>();
private Collection<String> excludeScopes = List.of("provided", "test");
private Collection<String> excludeScopes = Set.of(JavaScopes.PROVIDED, JavaScopes.TEST);
private boolean includeNonManaged = true;
private boolean excludeParentPoms;
private boolean excludeBomImports;
private int level = -1;
private boolean verboseGraphs;
private boolean logArtifactsToBuild;
private boolean logModulesToBuild;
private boolean logTrees;
Expand Down Expand Up @@ -304,6 +314,7 @@ static class Builder implements ProjectDependencyConfig.Mutable {
excludeParentPoms = other.isExcludeParentPoms();
excludeBomImports = other.isExcludeBomImports();
level = other.getLevel();
verboseGraphs = other.isVerboseGraphs();
logArtifactsToBuild = other.isLogArtifactsToBuild();
logModulesToBuild = other.isLogModulesToBuild();
logTrees = other.isLogTrees();
Expand Down Expand Up @@ -394,6 +405,11 @@ public int getLevel() {
return level;
}

@Override
public boolean isVerboseGraphs() {
return verboseGraphs;
}

@Override
public boolean isLogArtifactsToBuild() {
return logArtifactsToBuild;
Expand Down Expand Up @@ -581,6 +597,12 @@ public Mutable setLevel(int level) {
return this;
}

@Override
public Mutable setVerboseGraphs(boolean verboseGraphs) {
this.verboseGraphs = verboseGraphs;
return this;
}

@Override
public Mutable setLogArtifactsToBuild(boolean logArtifactsToBuild) {
this.logArtifactsToBuild = logArtifactsToBuild;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.quarkus.bom.decomposer.ReleaseIdDetector;
import io.quarkus.bom.decomposer.ReleaseIdFactory;
import io.quarkus.bom.decomposer.ScmRevisionResolver;
import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext;
import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException;
import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver;
import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils;
Expand All @@ -18,6 +19,7 @@
import io.quarkus.domino.scm.ScmRepository;
import io.quarkus.domino.scm.ScmRevision;
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.maven.dependency.ArtifactKey;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
Expand Down Expand Up @@ -49,12 +51,15 @@
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Profile;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactDescriptorResult;
import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;

Expand Down Expand Up @@ -155,14 +160,55 @@ public ProjectDependencyResolver build() {
private MavenArtifactResolver getInitializedResolver() {
if (resolver == null) {
try {
var mvnConfig = BootstrapMavenContext.config();
if (depConfig == null || depConfig.getProjectDir() == null) {
return MavenArtifactResolver.builder().setWorkspaceDiscovery(false).build();
mvnConfig.setWorkspaceDiscovery(false);
} else {
mvnConfig.setCurrentProject(depConfig.getProjectDir().toString())
.setEffectiveModelBuilder(true)
.setPreferPomsFromWorkspace(true);
}
return MavenArtifactResolver.builder()
.setCurrentProject(depConfig.getProjectDir().toString())
.setEffectiveModelBuilder(true)
.setPreferPomsFromWorkspace(true)
.build();
var mvnCtx = new BootstrapMavenContext(mvnConfig);

if (depConfig.isVerboseGraphs()) {
var session = new DefaultRepositorySystemSession(mvnCtx.getRepositorySystemSession());
session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);

mvnConfig.setRepositorySystemSession(session)
.setRepositorySystem(mvnCtx.getRepositorySystem())
.setRemoteRepositoryManager(mvnCtx.getRemoteRepositoryManager())
.setRemoteRepositories(mvnCtx.getRemoteRepositories())
.setCurrentProject(mvnCtx.getCurrentProject());

mvnCtx = new BootstrapMavenContext(mvnConfig);
}

return new MavenArtifactResolver(mvnCtx);
} catch (BootstrapMavenException e) {
throw new IllegalStateException("Failed to initialize the Maven artifact resolver", e);
}
} else if (depConfig != null
&& depConfig.isVerboseGraphs()
&& (Boolean.FALSE.equals(
resolver.getSession().getConfigProperties()
.getOrDefault(ConflictResolver.CONFIG_PROP_VERBOSE, false))
|| Boolean.FALSE.equals(resolver.getSession().getConfigProperties()
.getOrDefault(DependencyManagerUtils.CONFIG_PROP_VERBOSE, false)))) {
var mvnCtx = resolver.getMavenContext();
try {
var session = new DefaultRepositorySystemSession(mvnCtx.getRepositorySystemSession());
session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);

mvnCtx = new BootstrapMavenContext(
BootstrapMavenContext.config().setRepositorySystemSession(session)
.setRepositorySystem(mvnCtx.getRepositorySystem())
.setRemoteRepositoryManager(mvnCtx.getRemoteRepositoryManager())
.setRemoteRepositories(mvnCtx.getRemoteRepositories())
.setCurrentProject(mvnCtx.getCurrentProject()));

return new MavenArtifactResolver(mvnCtx);
} catch (BootstrapMavenException e) {
throw new IllegalStateException("Failed to initialize the Maven artifact resolver", e);
}
Expand Down Expand Up @@ -682,9 +728,39 @@ private DependencyNode collectDependencies(ArtifactCoords coords, List<Dependenc

try {
final Artifact a = toAetherArtifact(coords);
var descr = resolver.resolveDescriptor(a);
final List<Dependency> constraints;
if (descr.getManagedDependencies().isEmpty()) {
constraints = managedDeps;
} else {
final Map<ArtifactKey, Dependency> map = new LinkedHashMap<>();
constraints = new ArrayList<>(managedDeps.size());
for (var d : managedDeps) {
var art = d.getArtifact();
map.put(ArtifactKey.of(art.getGroupId(), art.getArtifactId(), art.getClassifier(), art.getExtension()), d);
constraints.add(d);
}
for (var d : descr.getManagedDependencies()) {
var art = d.getArtifact();
if (!map.containsKey(
ArtifactKey.of(art.getGroupId(), art.getArtifactId(), art.getClassifier(), art.getExtension()))) {
constraints.add(d);
}
}
}
final List<Dependency> directDeps = new ArrayList<>(descr.getDependencies().size());
for (var d : descr.getDependencies()) {
if (excludeScopes.contains(d.getScope())
|| d.isOptional() && !config.isIncludeOptionalDeps()) {
continue;
}
directDeps.add(d);
}
var aggregatedRepos = resolver.aggregateRepositories(resolver.getRepositories(),
resolver.newResolutionRepositories(descr.getRepositories()));

root = resolver.getSystem().collectDependencies(resolver.getSession(),
resolver.newCollectManagedRequest(a, List.of(), managedDeps, List.of(), List.of(),
excludeScopes))
MavenArtifactResolver.newCollectRequest(a, directDeps, managedDeps, List.of(), aggregatedRepos))
.getRoot();
// if the dependencies are not found, make sure the artifact actually exists
if (root.getChildren().isEmpty()) {
Expand Down Expand Up @@ -1068,6 +1144,17 @@ private void log(String msg) {
}

private void processNodes(DependencyNode node, int level, boolean remaining) {

// in case the resolver was configured to return verbose trees, check whether this node survived conflict resolution
final DependencyNode winner = (DependencyNode) node.getData().get(ConflictResolver.NODE_DATA_WINNER);
if (winner != null) {
final ArtifactCoords coords = toCoords(winner.getArtifact());
for (DependencyTreeVisitor v : treeVisitors) {
v.linkDependency(coords);
}
return;
}

final ArtifactCoords coords = toCoords(node.getArtifact());
if (isExcluded(coords)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ static boolean resolveLicenseInfo(LicenseChoice licenseChoice, LicenseChoice lic
}

static Version schemaVersion() {
return Version.VERSION_14;
return Version.VERSION_15;
}

private static boolean doesComponentHaveExternalReference(final Component component, final ExternalReference.Type type) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.quarkus.domino.manifest;

import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext;
import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver;
import io.quarkus.domino.ProjectDependencyConfig;
import io.quarkus.domino.ProjectDependencyResolver;
import io.quarkus.maven.dependency.ArtifactCoords;
import java.util.List;
import java.util.Set;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;

public class Playground {

public static void main(String[] args) throws Exception {

var mvnCtx = new BootstrapMavenContext(BootstrapMavenContext.config().setWorkspaceDiscovery(false));
var session = new DefaultRepositorySystemSession(mvnCtx.getRepositorySystemSession());
if (true) {
session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
}

mvnCtx = new BootstrapMavenContext(BootstrapMavenContext.config()
.setRepositorySystem(mvnCtx.getRepositorySystem())
.setRepositorySystemSession(session)
.setRemoteRepositoryManager(mvnCtx.getRemoteRepositoryManager())
.setRemoteRepositories(mvnCtx.getRemoteRepositories()));

var resolver = new MavenArtifactResolver(mvnCtx);

ProjectDependencyResolver.builder()
.setArtifactResolver(resolver)
.setDependencyConfig(ProjectDependencyConfig.builder()
/* @formatter:off
.setProjectArtifacts(List.of(
ArtifactCoords.jar("org.acme", "acme-lib-b", "1.0.0-SNAPSHOT"),
ArtifactCoords.jar("org.acme", "acme-lib-a", "1.0.0-SNAPSHOT")))
@formatter:on */
.setProjectArtifacts(List.of(
ArtifactCoords.jar("io.quarkus", "quarkus-core-deployment", "3.2.6.Final"),
ArtifactCoords.jar("io.quarkus", "quarkus-core", "3.2.6.Final")))
//.setIncludeOptionalDeps(true)
.setLegacyScmLocator(true)
.setExcludeScopes(Set.of("test"))
.build())
//.addDependencyTreeVisitor(new LoggingDependencyTreeVisitor(MessageWriter.info(), false, null))
.addDependencyTreeVisitor(new SbomGeneratingDependencyVisitor(
SbomGenerator.builder()
.setArtifactResolver(resolver)))
.build()
.resolveDependencies();
}
}
Loading

0 comments on commit 3fd3494

Please sign in to comment.