From 006b3d0b4da35f1d429aa1daba227ece08341ce6 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Wed, 8 Mar 2023 16:02:32 +0100 Subject: [PATCH] Support logging dependency trees to the terminal when generating manifests, new option logTreesFor allowing specify root artifacts for which the trees to be logged, fixed enforcing managed deps on the direct deps --- .../domino/LoggingDependencyTreeVisitor.java | 45 +++++++++++++++++-- .../domino/ProjectDependencyConfig.java | 9 ++++ .../domino/ProjectDependencyConfigImpl.java | 20 +++++++++ .../domino/ProjectDependencyResolver.java | 15 +++---- .../domino/manifest/PncSbomTransformer.java | 2 +- .../domino/cli/BaseDepsToBuildCommand.java | 16 +++++-- .../java/io/quarkus/domino/cli/Report.java | 23 +++++++++- .../maven/DependenciesToBuildMojo.java | 23 +++++++--- 8 files changed, 130 insertions(+), 23 deletions(-) diff --git a/domino/api/src/main/java/io/quarkus/domino/LoggingDependencyTreeVisitor.java b/domino/api/src/main/java/io/quarkus/domino/LoggingDependencyTreeVisitor.java index 1fc780c2..ea74fc1a 100644 --- a/domino/api/src/main/java/io/quarkus/domino/LoggingDependencyTreeVisitor.java +++ b/domino/api/src/main/java/io/quarkus/domino/LoggingDependencyTreeVisitor.java @@ -1,6 +1,7 @@ package io.quarkus.domino; import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.dependency.ArtifactCoords; public class LoggingDependencyTreeVisitor implements DependencyTreeVisitor { @@ -9,10 +10,20 @@ public class LoggingDependencyTreeVisitor implements DependencyTreeVisitor { private final MessageWriter log; private final boolean asComments; private int level; + private boolean loggingEnabled; + private ArtifactSet logTreesFor; - public LoggingDependencyTreeVisitor(MessageWriter log, boolean asComments) { + public LoggingDependencyTreeVisitor(MessageWriter log, boolean asComments, String logTreesFor) { this.log = log; this.asComments = asComments; + if (logTreesFor != null) { + final ArtifactSet.Builder builder = ArtifactSet.builder(); + final String[] arr = logTreesFor.split(","); + for (String s : arr) { + builder.include(s); + } + this.logTreesFor = builder.build(); + } } @Override @@ -25,20 +36,31 @@ public void afterAllRoots() { @Override public void enterRootArtifact(DependencyVisit visit) { + final ArtifactCoords coords = visit.getCoords(); + loggingEnabled = logTreesFor == null || logTreesFor.contains(coords.getGroupId(), coords.getArtifactId(), + coords.getClassifier(), coords.getType(), coords.getVersion()); + if (!loggingEnabled) { + return; + } if (visit.isManaged()) { - logComment(visit.getCoords().toCompactCoords()); + logComment(coords.toCompactCoords()); } else { - logComment(visit.getCoords().toCompactCoords() + NOT_MANAGED); + logComment(coords.toCompactCoords() + NOT_MANAGED); } } @Override public void leaveRootArtifact(DependencyVisit visit) { - logComment(""); + if (loggingEnabled) { + logComment(""); + } } @Override public void enterDependency(DependencyVisit visit) { + if (!loggingEnabled) { + return; + } ++level; final StringBuilder sb = new StringBuilder(); for (int i = 0; i < level; ++i) { @@ -53,11 +75,17 @@ public void enterDependency(DependencyVisit visit) { @Override public void leaveDependency(DependencyVisit visit) { + if (!loggingEnabled) { + return; + } --level; } @Override public void enterParentPom(DependencyVisit visit) { + if (!loggingEnabled) { + return; + } ++level; final StringBuilder sb = new StringBuilder(); for (int i = 0; i < level; ++i) { @@ -69,11 +97,17 @@ public void enterParentPom(DependencyVisit visit) { @Override public void leaveParentPom(DependencyVisit visit) { + if (!loggingEnabled) { + return; + } --level; } @Override public void enterBomImport(DependencyVisit visit) { + if (!loggingEnabled) { + return; + } ++level; final StringBuilder sb = new StringBuilder(); for (int i = 0; i < level; ++i) { @@ -85,6 +119,9 @@ public void enterBomImport(DependencyVisit visit) { @Override public void leaveBomImport(DependencyVisit visit) { + if (!loggingEnabled) { + return; + } --level; } diff --git a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java index 65e8fb8a..c95714fe 100644 --- a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java +++ b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfig.java @@ -87,6 +87,13 @@ public interface ProjectDependencyConfig { */ boolean isLogTrees(); + /** + * Comma-separated list of artifacts to log dependency trees for. + * + * @return comma-separated list of artifacts to log dependency trees for + */ + String getLogTreesFor(); + /** * Whether to log the coordinates of the artifacts below the depth specified. The default is false. * @@ -257,6 +264,8 @@ default Mutable setExcludeKeys(Set artifactKeys) { Mutable setLogTrees(boolean logTrees); + Mutable setLogTreesFor(String logTreesFor); + Mutable setLogRemaining(boolean logRemaining); Mutable setLogSummary(boolean logSummary); diff --git a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java index 77aa14a9..7582986d 100644 --- a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java +++ b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyConfigImpl.java @@ -26,6 +26,7 @@ public class ProjectDependencyConfigImpl implements ProjectDependencyConfig { private final boolean logArtifactsToBuild; private final boolean logModulesToBuild; private final boolean logTrees; + private final String logTreesFor; private final boolean logRemaining; private final boolean logSummary; private final boolean logNonManagedVisited; @@ -55,6 +56,7 @@ private ProjectDependencyConfigImpl(ProjectDependencyConfig other) { logArtifactsToBuild = other.isLogArtifactsToBuild(); logModulesToBuild = other.isLogModulesToBuild(); logTrees = other.isLogTrees(); + logTreesFor = other.getLogTreesFor(); logRemaining = other.isLogRemaining(); logSummary = other.isLogSummary(); logNonManagedVisited = other.isLogNonManagedVisitied(); @@ -136,6 +138,11 @@ public boolean isLogTrees() { return logTrees; } + @Override + public String getLogTreesFor() { + return logTreesFor; + } + @Override public boolean isLogRemaining() { return logRemaining; @@ -225,6 +232,7 @@ static class Builder implements ProjectDependencyConfig.Mutable { private boolean logArtifactsToBuild; private boolean logModulesToBuild; private boolean logTrees; + private String logTreesFor; private boolean logRemaining; private boolean logSummary; private boolean logNonManagedVisited; @@ -257,6 +265,7 @@ static class Builder implements ProjectDependencyConfig.Mutable { logArtifactsToBuild = other.isLogArtifactsToBuild(); logModulesToBuild = other.isLogModulesToBuild(); logTrees = other.isLogTrees(); + logTreesFor = other.getLogTreesFor(); logRemaining = other.isLogRemaining(); logSummary = other.isLogSummary(); logNonManagedVisited = other.isLogNonManagedVisitied(); @@ -342,6 +351,11 @@ public boolean isLogTrees() { return logTrees; } + @Override + public String getLogTreesFor() { + return logTreesFor; + } + @Override public boolean isLogRemaining() { return logRemaining; @@ -503,6 +517,12 @@ public Mutable setLogTrees(boolean logTrees) { return this; } + @Override + public Mutable setLogTreesFor(String logTreesFor) { + this.logTreesFor = logTreesFor; + return this; + } + @Override public Mutable setLogRemaining(boolean logRemaining) { this.logRemaining = logRemaining; diff --git a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java index e3788e54..689950b6 100644 --- a/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java +++ b/domino/api/src/main/java/io/quarkus/domino/ProjectDependencyResolver.java @@ -45,7 +45,6 @@ import org.apache.maven.model.Profile; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.repository.RemoteRepository; @@ -230,10 +229,10 @@ private ProjectDependencyResolver(Builder builder) { includeSet = new ArrayList<>(config.getIncludeArtifacts().size() + config.getIncludePatterns().size()); config.getIncludePatterns().forEach(p -> includeSet.add(toPattern(p))); config.getIncludeArtifacts().forEach(c -> includeSet.add(toPattern(c))); - if (config.isLogTrees()) { + if (config.isLogTrees() || config.getLogTreesFor() != null) { treeVisitors = new ArrayList<>(builder.visitors.size() + 1); treeVisitors.addAll(builder.visitors); - treeVisitors.add(new LoggingDependencyTreeVisitor(getOutput(), true)); + treeVisitors.add(new LoggingDependencyTreeVisitor(getOutput(), true, config.getLogTreesFor())); } else { treeVisitors = builder.visitors; } @@ -488,6 +487,7 @@ protected Iterable getProjectArtifacts() { } private void processRootArtifact(ArtifactCoords rootArtifact, List managedDeps) { + final DependencyNode root = collectDependencies(rootArtifact, managedDeps); if (root == null) { // couldn't be resolved @@ -500,6 +500,7 @@ private void processRootArtifact(ArtifactCoords rootArtifact, List m } catch (Exception e) { throw new RuntimeException("Failed to process " + rootArtifact, e); } + if (resolved != null) { for (DependencyTreeVisitor v : treeVisitors) { v.enterRootArtifact(resolved); @@ -531,13 +532,11 @@ private DependencyNode collectDependencies(ArtifactCoords coords, List { "--log-trees" }, description = "Whether to log the dependency trees walked down to the depth specified. The default is false.") public boolean logTrees; + @CommandLine.Option(names = { + "--log-trees-for" }, description = "Comma-separate list of artifacts to log dependency trees for") + public String logTreesFor; + @CommandLine.Option(names = { "--log-remaining" }, description = "Whether to log the coordinates of the artifacts below the depth specified. The default is false.") public boolean logRemaining; @@ -155,17 +159,20 @@ public Integer call() throws Exception { if (exportTo != null) { config.persist(exportTo.toPath()); } else { - final ProjectDependencyResolver dependencyResolver = ProjectDependencyResolver.builder() + final ProjectDependencyResolver.Builder resolverBuilder = ProjectDependencyResolver.builder() .setLogOutputFile(outputFile == null ? null : outputFile.toPath()) .setAppendOutput(appendOutput) .setDependencyConfig(config) - .setArtifactResolver(getArtifactResolver()) - .build(); - return process(dependencyResolver); + .setArtifactResolver(getArtifactResolver()); + initResolver(resolverBuilder); + return process(resolverBuilder.build()); } return CommandLine.ExitCode.OK; } + protected void initResolver(ProjectDependencyResolver.Builder resolverBuilder) { + } + protected void initConfig(ProjectDependencyConfig.Mutable config) { if (bom != null) { config.setProjectBom(ArtifactCoords.fromString(bom)); @@ -232,6 +239,7 @@ protected void initConfig(ProjectDependencyConfig.Mutable config) { .setIncludeKeys(Set.of()) // TODO .setLevel(level) .setLogArtifactsToBuild(logArtifactsToBuild) + .setLogTreesFor(logTreesFor) .setLogCodeRepoTree(logCodeRepoGraph) .setLogCodeRepos(logCodeRepos) .setLogModulesToBuild(logModulesToBuild) diff --git a/domino/app/src/main/java/io/quarkus/domino/cli/Report.java b/domino/app/src/main/java/io/quarkus/domino/cli/Report.java index 304cd365..a23142eb 100644 --- a/domino/app/src/main/java/io/quarkus/domino/cli/Report.java +++ b/domino/app/src/main/java/io/quarkus/domino/cli/Report.java @@ -3,14 +3,20 @@ import io.quarkus.domino.ProjectDependencyConfig; import io.quarkus.domino.ProjectDependencyResolver; import io.quarkus.domino.manifest.ManifestGenerator; +import io.quarkus.domino.manifest.SbomGeneratingDependencyVisitor; import picocli.CommandLine; @CommandLine.Command(name = "report") public class Report extends BaseDepsToBuildCommand { - @CommandLine.Option(names = { "--manifest" }, description = "Generate an SBOM", defaultValue = "false") + @CommandLine.Option(names = { + "--manifest" }, description = "Generate an SBOM with dependency trees", defaultValue = "false") public boolean manifest; + @CommandLine.Option(names = { + "--flat-manifest" }, description = "Generate an SBOM without dependency tree information", defaultValue = "false") + public boolean flatManifest; + @Override protected void initConfig(ProjectDependencyConfig.Mutable config) { super.initConfig(config); @@ -19,9 +25,24 @@ protected void initConfig(ProjectDependencyConfig.Mutable config) { } } + @Override + protected void initResolver(ProjectDependencyResolver.Builder resolverBuilder) { + super.initResolver(resolverBuilder); + if (manifest || flatManifest) { + resolverBuilder.setLogOutputFile(null); + } + if (manifest) { + resolverBuilder.addDependencyTreeVisitor( + new SbomGeneratingDependencyVisitor(getArtifactResolver(), + outputFile == null ? null : outputFile.toPath())); + } + } + @Override protected Integer process(ProjectDependencyResolver depResolver) { if (manifest) { + depResolver.resolveDependencies(); + } else if (flatManifest) { ManifestGenerator.builder() .setArtifactResolver(getArtifactResolver()) .setOutputFile(outputFile == null ? null : this.outputFile.toPath()) diff --git a/maven-plugin/src/main/java/io/quarkus/bom/decomposer/maven/DependenciesToBuildMojo.java b/maven-plugin/src/main/java/io/quarkus/bom/decomposer/maven/DependenciesToBuildMojo.java index f610b66a..2ba99e8e 100644 --- a/maven-plugin/src/main/java/io/quarkus/bom/decomposer/maven/DependenciesToBuildMojo.java +++ b/maven-plugin/src/main/java/io/quarkus/bom/decomposer/maven/DependenciesToBuildMojo.java @@ -81,7 +81,7 @@ public class DependenciesToBuildMojo extends AbstractMojo { * Whether to exclude dependencies (and their transitive dependencies) that aren't managed in the BOM. The default is true. */ @Parameter(required = false, property = "includeNonManaged") - boolean includeNonManaged; + Boolean includeNonManaged; /** * Whether to log the coordinates of the artifacts captured down to the depth specified. The default is true. @@ -103,6 +103,12 @@ public class DependenciesToBuildMojo extends AbstractMojo { @Parameter(required = false, property = "logTrees") boolean logTrees; + /** + * Comma-separated list of root artifacts to log dependency trees for + */ + @Parameter(required = false, property = "logTreesFor") + String logTreesFor; + /** * Whether to log the coordinates of the artifacts below the depth specified. The default is false. */ @@ -262,13 +268,15 @@ public void execute() throws MojoExecutionException, MojoFailureException { catalogs.add(catalog); for (ArtifactCoords descrCoords : otherDescriptorCoords) { final ExtensionCatalog otherCatalog = resolveCatalog(descrCoords); - catalogs.add(otherCatalog); + if (!isManifestMode()) { + catalogs.add(otherCatalog); + } final ArtifactCoords otherBomCoords = otherCatalog.getBom(); final List otherBomDeps = getBomConstraints(otherBomCoords); final List enforcedConstraints = new ArrayList<>( targetBomManagedDeps.size() + otherBomDeps.size()); - enforcedConstraints.addAll(otherBomDeps); + enforcedConstraints.addAll(targetBomManagedDeps); enforcedConstraints.addAll(otherBomDeps); enforcedConstraintsForBom.put(otherBomCoords, enforcedConstraints); } @@ -330,7 +338,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { }) .setArtifactResolver(resolver) .setMessageWriter(new MojoMessageWriter(getLog())) - .setLogOutputFile(outputFile == null ? null : outputFile.toPath()) + .setLogOutputFile(isManifestMode() ? null : (outputFile == null ? null : outputFile.toPath())) .setAppendOutput(appendOutput) .setDependencyConfig(ProjectDependencyConfig.builder() .setProjectBom(targetBomCoords) @@ -343,7 +351,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { .setExcludeKeys(dependenciesToBuild.getExcludeKeys()) .setExcludeBomImports(excludeBomImports) .setExcludeParentPoms(excludeParentPoms) - .setIncludeNonManaged(includeNonManaged) + .setIncludeNonManaged(includeNonManaged == null ? isManifestMode() : includeNonManaged) .setLevel(level) .setLogArtifactsToBuild(logArtifactsToBuild) .setLogCodeRepoTree(logCodeRepoGraph) @@ -353,6 +361,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { .setLogRemaining(logRemaining) .setLogSummary(logSummary) .setLogTrees(logTrees) + .setLogTreesFor(logTreesFor) .setIncludeAlreadyBuilt(includeAlreadyBuilt) .setValidateCodeRepoTags(validateCodeRepoTags) .setLegacyScmLocator(legacyScmLocator) @@ -373,6 +382,10 @@ public void execute() throws MojoExecutionException, MojoFailureException { } } + private boolean isManifestMode() { + return manifest || flatManifest; + } + private List getConstraintsForExtension(Extension ext) { for (ExtensionOrigin origin : ext.getOrigins()) { if (origin.getBom() == null) {