From 9427fc552dbc4a3977d9b4c96949e63aac98cb13 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Wed, 22 Nov 2023 16:35:03 +0100 Subject: [PATCH] Switch to manifesting dependency graphs instead of trees --- .../PurgingDependencyTreeVisitor.java | 99 +++--- .../manifest/CyclicDependencyGraphTest.java | 114 +------ .../domino/manifest/ManifestingTestBase.java | 132 ++++++++ .../manifest/SiblingConvergenceTest.java | 304 ++++++++++++++++++ .../java/io/quarkus/domino/cli/Report.java | 2 +- .../maven/DependenciesToBuildMojo.java | 20 +- 6 files changed, 515 insertions(+), 156 deletions(-) create mode 100644 domino/api/src/test/java/io/quarkus/domino/manifest/ManifestingTestBase.java create mode 100644 domino/api/src/test/java/io/quarkus/domino/manifest/SiblingConvergenceTest.java diff --git a/domino/api/src/main/java/io/quarkus/domino/manifest/PurgingDependencyTreeVisitor.java b/domino/api/src/main/java/io/quarkus/domino/manifest/PurgingDependencyTreeVisitor.java index 6f07988f..0679b43d 100644 --- a/domino/api/src/main/java/io/quarkus/domino/manifest/PurgingDependencyTreeVisitor.java +++ b/domino/api/src/main/java/io/quarkus/domino/manifest/PurgingDependencyTreeVisitor.java @@ -15,7 +15,10 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import org.eclipse.aether.repository.RemoteRepository; import org.jboss.logging.Logger; @@ -28,7 +31,7 @@ public class PurgingDependencyTreeVisitor implements DependencyTreeVisitor { private final AtomicLong uniqueNodesTotal = new AtomicLong(); private List roots; private ArrayDeque branch; - private Map> nodeVariations; + private Map nodeVariations; private Map treeComponents; @Override @@ -37,7 +40,7 @@ public void beforeAllRoots() { uniqueNodesTotal.set(0); roots = new ArrayList<>(); branch = new ArrayDeque<>(); - nodeVariations = new HashMap<>(); + nodeVariations = new ConcurrentHashMap<>(); } @Override @@ -53,9 +56,9 @@ private void purge() { //log.infof("Roots total: %s", roots.size()); //log.infof("Nodes total: %s", nodesTotal); + var treeProcessor = newTreeProcessor(); for (VisitedComponentImpl root : roots) { // we want to process each tree separately due to possible variations across different trees - var treeProcessor = newTreeProcessor(); treeProcessor.addRoot(root); var results = treeProcessor.schedule().join(); boolean failures = false; @@ -78,7 +81,7 @@ private void purge() { var i = roots.iterator(); while (i.hasNext()) { var current = i.next(); - VisitedComponent previous = ids.put(current.getBomRef(), current); + var previous = ids.put(current.getBomRef(), current); if (previous != null) { i.remove(); } @@ -103,31 +106,8 @@ public Iterable getChildren(VisitedComponentImpl node) { @Override public Function, TaskResult> createFunction() { return ctx -> { - VisitedComponentImpl currentNode = ctx.getNode(); - final List variations = nodeVariations.get(currentNode.getArtifactCoords()); - long processedVariations = 0; - if (variations.size() > 1) { - for (VisitedComponentImpl variation : variations) { - if (!variation.hasBomRefsSet()) { - continue; - } - processedVariations++; - if (variation.hasMatchingDirectDeps(currentNode)) { - if (currentNode.isRoot()) { - currentNode.setBomRef(variation.getBomRef()); - } else { - currentNode.swap(variation); - currentNode = variation; - } - break; - } - } - } - if (currentNode.getBomRef() == null) { - uniqueNodesTotal.incrementAndGet(); - currentNode.initializeBomRef(processedVariations); - } - return ctx.success(currentNode); + final VisitedComponentImpl currentNode = ctx.getNode(); + return ctx.success(nodeVariations.get(currentNode.getArtifactCoords()).setBomRef(currentNode)); }; } }); @@ -185,7 +165,7 @@ public void leaveBomImport(DependencyVisit visit) { private VisitedComponentImpl enterNode(DependencyVisit visit) { var parent = branch.peek(); var current = new VisitedComponentImpl(nodesTotal.getAndIncrement(), parent, visit); - nodeVariations.computeIfAbsent(visit.getCoords(), k -> new ArrayList<>()).add(current); + nodeVariations.computeIfAbsent(visit.getCoords(), k -> new ComponentVariations()).add(current); if (parent != null) { parent.addChild(current); } @@ -204,11 +184,12 @@ private class VisitedComponentImpl implements VisitedComponent { private final ScmRevision revision; private final ArtifactCoords coords; private final List repos; - private final Map children = new HashMap<>(); + private final Map children = new ConcurrentHashMap<>(); private List linkedDeps; private List linkedParents; private String bomRef; private PackageURL purl; + private boolean purged; private VisitedComponentImpl(long index, VisitedComponentImpl parent, DependencyVisit visit) { this.index = index; @@ -284,6 +265,7 @@ private void swap(VisitedComponentImpl other) { p.addChild(other); } } + purged = true; } private boolean hasMatchingDirectDeps(VisitedComponentImpl other) { @@ -348,18 +330,6 @@ private void setBomRef(String bomRef) { this.bomRef = bomRef; } - private boolean hasBomRefsSet() { - if (bomRef == null) { - return false; - } - for (var c : children.values()) { - if (c.bomRef == null) { - return false; - } - } - return true; - } - private void initializeBomRef(long processedVariations) { if (processedVariations == 0) { bomRef = getPurl().toString(); @@ -388,6 +358,49 @@ public String toString() { } } + private class ComponentVariations { + private final List variations = new ArrayList<>(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + private void add(VisitedComponentImpl variation) { + variations.add(variation); + } + + private VisitedComponentImpl setBomRef(VisitedComponentImpl currentNode) { + if (currentNode.bomRef != null) { + return currentNode; + } + lock.readLock().lock(); + try { + int processedVariations = 0; + if (variations.size() > 1) { + for (var variation : variations) { + if (variation.purged || variation.bomRef == null) { + continue; + } + processedVariations++; + if (variation.hasMatchingDirectDeps(currentNode)) { + if (currentNode.isRoot()) { + currentNode.setBomRef(variation.getBomRef()); + } else { + currentNode.swap(variation); + currentNode = variation; + } + break; + } + } + } + if (currentNode.bomRef == null) { + uniqueNodesTotal.incrementAndGet(); + currentNode.initializeBomRef(processedVariations); + } + } finally { + lock.readLock().unlock(); + } + return currentNode; + } + } + private static boolean isSameGav(ArtifactCoords c1, ArtifactCoords c2) { return c1.getArtifactId().equals(c2.getArtifactId()) && c1.getVersion().equals(c2.getVersion()) diff --git a/domino/api/src/test/java/io/quarkus/domino/manifest/CyclicDependencyGraphTest.java b/domino/api/src/test/java/io/quarkus/domino/manifest/CyclicDependencyGraphTest.java index 3a0fe25e..f10ceeb3 100644 --- a/domino/api/src/test/java/io/quarkus/domino/manifest/CyclicDependencyGraphTest.java +++ b/domino/api/src/test/java/io/quarkus/domino/manifest/CyclicDependencyGraphTest.java @@ -1,40 +1,16 @@ package io.quarkus.domino.manifest; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.domino.ProjectDependencyConfig; -import io.quarkus.domino.ProjectDependencyResolver; import io.quarkus.domino.test.repo.TestArtifactRepo; import io.quarkus.domino.test.repo.TestProject; import io.quarkus.maven.dependency.ArtifactCoords; -import java.io.BufferedReader; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashSet; import java.util.List; -import org.cyclonedx.exception.ParseException; import org.cyclonedx.model.Bom; -import org.cyclonedx.model.Component; -import org.cyclonedx.model.Dependency; -import org.cyclonedx.parsers.JsonParser; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -public class CyclicDependencyGraphTest { - - @TempDir - static Path testRepoDir; - static MavenArtifactResolver artifactResolver; - @BeforeAll - static void prepareRepo() { - var testRepo = TestArtifactRepo.of(testRepoDir); - artifactResolver = testRepo.getArtifactResolver(); +public class CyclicDependencyGraphTest extends ManifestingTestBase { + @Override + protected void initRepo(TestArtifactRepo repo) { var tcnativeProject = TestProject.of("io.netty", "1.0") .setRepoUrl("https://netty.io/tcnative") .setTag("1.0"); @@ -49,57 +25,23 @@ static void prepareRepo() { .addDependency(ArtifactCoords.jar("io.netty", "netty-tcnative-boringssl-static", "osx-x86_64", " 1.0")) .addClassifier("windows-x86_64") .addDependency(ArtifactCoords.jar("io.netty", "netty-tcnative-boringssl-static", "windows-x86_64", " 1.0")); - testRepo.install(tcnativeProject); + repo.install(tcnativeProject); var appProject = TestProject.of("org.acme", "1.0") .setRepoUrl("https://acme.org/app") .setTag("1.0"); appProject.createMainModule("acme-app") .addDependency(ArtifactCoords.jar("io.netty", "netty-tcnative-boringssl-static", "linux-x86_64", "1.0")); - testRepo.install(appProject); + repo.install(appProject); } - private static ProjectDependencyConfig.Mutable newDependencyConfig() { - return ProjectDependencyConfig.builder() - .setWarnOnMissingScm(true) - .setLegacyScmLocator(true); + @Override + protected ProjectDependencyConfig initConfig(ProjectDependencyConfig.Mutable config) { + return config.setProjectArtifacts(List.of(ArtifactCoords.jar("org.acme", "acme-app", "1.0"))); } - @Test - public void dependencyGraph() { - var config = newDependencyConfig() - .setProjectArtifacts(List.of(ArtifactCoords.jar("org.acme", "acme-app", "1.0"))); - - final Bom bom; - Path output = null; - try { - output = Files.createTempFile("domino-test", "sbom"); - - ProjectDependencyResolver.builder() - .setArtifactResolver(artifactResolver) - .setDependencyConfig(config) - .addDependencyTreeVisitor(new SbomGeneratingDependencyVisitor( - SbomGenerator.builder() - .setArtifactResolver(artifactResolver) - .setOutputFile(output) - .setEnableTransformers(false), - config)) - .build() - .resolveDependencies(); - - try (BufferedReader reader = Files.newBufferedReader(output)) { - bom = new JsonParser().parse(reader); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - if (output != null) { - output.toFile().deleteOnExit(); - } - } - + @Override + protected void assertBom(Bom bom) { assertDependencies(bom, ArtifactCoords.jar("org.acme", "acme-app", "1.0"), ArtifactCoords.jar("io.netty", "netty-tcnative-boringssl-static", "linux-x86_64", "1.0")); @@ -114,40 +56,4 @@ public void dependencyGraph() { assertDependencies(bom, ArtifactCoords.jar("io.netty", "netty-tcnative-boringssl-static", "osx-x86_64", "1.0")); assertDependencies(bom, ArtifactCoords.jar("io.netty", "netty-tcnative-boringssl-static", "windows-x86_64", "1.0")); } - - private static void assertDependencies(Bom bom, ArtifactCoords compCoords, ArtifactCoords... expectedDeps) { - var purl = PurgingDependencyTreeVisitor.getPurl(compCoords).toString(); - Component comp = null; - for (var c : bom.getComponents()) { - if (c.getPurl().equals(purl)) { - comp = c; - break; - } - } - if (comp == null) { - fail("Failed to locate " + purl); - return; - } - Dependency dep = null; - for (var d : bom.getDependencies()) { - if (d.getRef().equals(comp.getBomRef())) { - dep = d; - break; - } - } - if (dep == null && expectedDeps.length > 0) { - fail(comp.getBomRef() + " has no dependencies manifested while expected " + expectedDeps.length); - return; - } - final List recordedDeps = dep == null ? List.of() : dep.getDependencies(); - var recordedDepPurls = new HashSet(recordedDeps.size()); - for (var d : recordedDeps) { - recordedDepPurls.add(d.getRef()); - } - var expectedDepPurls = new HashSet(expectedDeps.length); - for (var c : expectedDeps) { - expectedDepPurls.add(PurgingDependencyTreeVisitor.getPurl(c).toString()); - } - assertThat(recordedDepPurls).isEqualTo(expectedDepPurls); - } } diff --git a/domino/api/src/test/java/io/quarkus/domino/manifest/ManifestingTestBase.java b/domino/api/src/test/java/io/quarkus/domino/manifest/ManifestingTestBase.java new file mode 100644 index 00000000..f690b4c4 --- /dev/null +++ b/domino/api/src/test/java/io/quarkus/domino/manifest/ManifestingTestBase.java @@ -0,0 +1,132 @@ +package io.quarkus.domino.manifest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.domino.ProjectDependencyConfig; +import io.quarkus.domino.ProjectDependencyResolver; +import io.quarkus.domino.test.repo.TestArtifactRepo; +import io.quarkus.maven.dependency.ArtifactCoords; +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.cyclonedx.exception.ParseException; +import org.cyclonedx.model.Bom; +import org.cyclonedx.model.Component; +import org.cyclonedx.model.Dependency; +import org.cyclonedx.parsers.JsonParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +public abstract class ManifestingTestBase { + + @TempDir + static Path testRepoDir; + static MavenArtifactResolver artifactResolver; + + static void assertDependencies(Bom bom, ArtifactCoords component, ArtifactCoords... expectedDeps) { + var purl = PurgingDependencyTreeVisitor.getPurl(component).toString(); + Component comp = null; + for (var c : bom.getComponents()) { + if (c.getPurl().equals(purl)) { + comp = c; + break; + } + } + if (comp == null) { + fail("Failed to locate " + purl); + return; + } + Dependency dep = null; + if (bom.getDependencies() != null) { + for (var d : bom.getDependencies()) { + if (d.getRef().equals(comp.getBomRef())) { + dep = d; + break; + } + } + } + if (dep == null && expectedDeps.length > 0) { + fail(comp.getBomRef() + " has no dependencies manifested while expected " + expectedDeps.length); + return; + } + final List recordedDeps = dep == null ? List.of() : dep.getDependencies(); + var recordedDepPurls = new ArrayList(recordedDeps.size()); + for (var d : recordedDeps) { + recordedDepPurls.add(d.getRef()); + } + var expectedDepPurls = new ArrayList(expectedDeps.length); + for (var c : expectedDeps) { + expectedDepPurls.add(PurgingDependencyTreeVisitor.getPurl(c).toString()); + } + Collections.sort(recordedDepPurls); + Collections.sort(expectedDepPurls); + assertThat(recordedDepPurls).isEqualTo(expectedDepPurls); + } + + @BeforeEach + protected void prepareRepo() { + var testRepo = TestArtifactRepo.of(testRepoDir); + artifactResolver = testRepo.getArtifactResolver(); + initRepo(testRepo); + } + + protected ProjectDependencyConfig.Mutable newConfig() { + return ProjectDependencyConfig.builder() + .setWarnOnMissingScm(true) + .setLegacyScmLocator(true) + .setVerboseGraphs(true); + } + + @Test + public void testManifest() { + var config = initConfig(newConfig()); + final Bom bom; + Path output = null; + try { + output = Files.createTempFile("domino-test", "sbom"); + ProjectDependencyResolver.builder() + .setArtifactResolver(artifactResolver) + .setDependencyConfig(config) + .addDependencyTreeVisitor(new SbomGeneratingDependencyVisitor( + SbomGenerator.builder() + .setArtifactResolver(artifactResolver) + .setOutputFile(output) + .setEnableTransformers(false), + config)) + .build() + .resolveDependencies(); + if (isLogManifest()) { + System.out.println(Files.readString(output)); + } + try (BufferedReader reader = Files.newBufferedReader(output)) { + bom = new JsonParser().parse(reader); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + if (output != null) { + output.toFile().deleteOnExit(); + } + } + assertBom(bom); + } + + protected boolean isLogManifest() { + return false; + } + + protected abstract void initRepo(TestArtifactRepo repo); + + protected abstract ProjectDependencyConfig initConfig(ProjectDependencyConfig.Mutable config); + + protected abstract void assertBom(Bom bom); +} diff --git a/domino/api/src/test/java/io/quarkus/domino/manifest/SiblingConvergenceTest.java b/domino/api/src/test/java/io/quarkus/domino/manifest/SiblingConvergenceTest.java new file mode 100644 index 00000000..acc2f1ce --- /dev/null +++ b/domino/api/src/test/java/io/quarkus/domino/manifest/SiblingConvergenceTest.java @@ -0,0 +1,304 @@ +package io.quarkus.domino.manifest; + +import io.quarkus.domino.ProjectDependencyConfig; +import io.quarkus.domino.test.repo.TestArtifactRepo; +import io.quarkus.domino.test.repo.TestModule; +import io.quarkus.domino.test.repo.TestProject; +import io.quarkus.maven.dependency.ArtifactCoords; +import java.util.List; +import org.cyclonedx.model.Bom; + +public class SiblingConvergenceTest extends ManifestingTestBase { + @Override + protected void initRepo(TestArtifactRepo repo) { + + var projectA1 = TestProject.of("org.project-a", "0.1") + .setRepoUrl("https://project-a.org/code") + .setTag("0.1"); + var libA1 = projectA1.createMainModule("lib-a") + .addDependency(installLibX(repo, "0.1")); + repo.install(projectA1); + + var projectB1 = TestProject.of("org.project-b", "0.1") + .setRepoUrl("https://project-b.org/code") + .setTag("0.1"); + var libB1 = projectB1.createMainModule("lib-b") + .addDependency(installLibX(repo, "0.2")); + repo.install(projectB1); + + var projectC1 = TestProject.of("org.project-c", "0.1") + .setRepoUrl("https://project-c.org/code") + .setTag("0.1"); + var libC1 = projectC1.createMainModule("lib-c") + .addDependency(installLibX(repo, "0.3")); + repo.install(projectC1); + + var projectD1 = TestProject.of("org.project-d", "0.1") + .setRepoUrl("https://project-d.org/code") + .setTag("0.1"); + var libD1 = projectD1.createMainModule("lib-d") + .addDependency(installLibX(repo, "0.4")); + repo.install(projectD1); + + var projectE1 = TestProject.of("org.project-e", "0.1") + .setRepoUrl("https://project-e.org/code") + .setTag("0.1"); + var libE1 = projectE1.createMainModule("lib-e") + .addDependency(installLibX(repo, "0.5")); + repo.install(projectE1); + + var projectF1 = TestProject.of("org.project-f", "0.1") + .setRepoUrl("https://project-f.org/code") + .setTag("0.1"); + var libF1 = projectF1.createMainModule("lib-f") + .addDependency(installLibX(repo, "0.6")); + repo.install(projectF1); + + var projectG1 = TestProject.of("org.project-g", "0.1") + .setRepoUrl("https://project-g.org/code") + .setTag("0.1"); + var libG1 = projectG1.createMainModule("lib-g") + .addDependency(installLibX(repo, "0.7")); + repo.install(projectG1); + + var projectH1 = TestProject.of("org.project-h", "0.1") + .setRepoUrl("https://project-h.org/code") + .setTag("0.1"); + var libH1 = projectH1.createMainModule("lib-h") + .addDependency(installLibX(repo, "0.8")); + repo.install(projectH1); + + var projectI1 = TestProject.of("org.project-i", "0.1") + .setRepoUrl("https://project-i.org/code") + .setTag("0.1"); + var libI1 = projectI1.createMainModule("lib-i") + .addDependency(installLibX(repo, "0.9")); + repo.install(projectI1); + + var projectJ1 = TestProject.of("org.project-j", "0.1") + .setRepoUrl("https://project-j.org/code") + .setTag("0.1"); + var libJ1 = projectJ1.createMainModule("lib-j") + .addDependency(installLibX(repo, "0.10")); + repo.install(projectJ1); + + var projectK1 = TestProject.of("org.project-k", "0.1") + .setRepoUrl("https://project-k.org/code") + .setTag("0.1"); + var libK1 = projectK1.createMainModule("lib-k") + .addDependency(installLibX(repo, "0.11")); + repo.install(projectK1); + + var projectL1 = TestProject.of("org.project-l", "0.1") + .setRepoUrl("https://project-l.org/code") + .setTag("0.1"); + var libL1 = projectL1.createMainModule("lib-l") + .addDependency(installLibX(repo, "0.12")); + repo.install(projectL1); + + var projectM1 = TestProject.of("org.project-m", "0.1") + .setRepoUrl("https://project-m.org/code") + .setTag("0.1"); + var libM1 = projectM1.createMainModule("lib-m") + .addDependency(installLibX(repo, "0.13")); + repo.install(projectM1); + + var projectN1 = TestProject.of("org.project-n", "0.1") + .setRepoUrl("https://project-n.org/code") + .setTag("0.1"); + var libN1 = projectN1.createMainModule("lib-n") + .addDependency(installLibX(repo, "0.14")); + repo.install(projectN1); + + var projectO1 = TestProject.of("org.project-o", "0.1") + .setRepoUrl("https://project-o.org/code") + .setTag("0.1"); + var libO1 = projectO1.createMainModule("lib-o") + .addDependency(installLibX(repo, "0.15")); + repo.install(projectO1); + + var projectP1 = TestProject.of("org.project-p", "0.1") + .setRepoUrl("https://project-p.org/code") + .setTag("0.1"); + var libP1 = projectP1.createMainModule("lib-p") + .addDependency(installLibX(repo, "0.16")); + repo.install(projectP1); + + var projectQ1 = TestProject.of("org.project-q", "0.1") + .setRepoUrl("https://project-q.org/code") + .setTag("0.1"); + var libQ1 = projectQ1.createMainModule("lib-q") + .addDependency(installLibX(repo, "0.17")); + repo.install(projectQ1); + + var projectR1 = TestProject.of("org.project-r", "0.1") + .setRepoUrl("https://project-r.org/code") + .setTag("0.1"); + var libR1 = projectR1.createMainModule("lib-r") + .addDependency(installLibX(repo, "0.18")); + repo.install(projectR1); + + var projectS1 = TestProject.of("org.project-s", "0.1") + .setRepoUrl("https://project-s.org/code") + .setTag("0.1"); + var libS1 = projectS1.createMainModule("lib-s") + .addDependency(installLibX(repo, "0.19")); + repo.install(projectS1); + + var projectT1 = TestProject.of("org.project-t", "0.1") + .setRepoUrl("https://project-t.org/code") + .setTag("0.1"); + var libT1 = projectT1.createMainModule("lib-t") + .addDependency(installLibX(repo, "0.20")); + repo.install(projectT1); + + var projectU1 = TestProject.of("org.project-u", "0.1") + .setRepoUrl("https://project-u.org/code") + .setTag("0.1"); + var libU1 = projectU1.createMainModule("lib-u") + .addDependency(installLibX(repo, "0.21")); + repo.install(projectU1); + + var projectV1 = TestProject.of("org.project-v", "0.1") + .setRepoUrl("https://project-v.org/code") + .setTag("0.1"); + var libV1 = projectV1.createMainModule("lib-v") + .addDependency(installLibX(repo, "0.22")); + repo.install(projectV1); + + var projectW1 = TestProject.of("org.project-w", "0.1") + .setRepoUrl("https://project-w.org/code") + .setTag("0.1"); + var libW1 = projectW1.createMainModule("lib-w") + .addDependency(installLibX(repo, "0.23")); + repo.install(projectW1); + + var appProject = TestProject.of("org.acme", "1.0") + .setRepoUrl("https://acme.org/app") + .setTag("1.0"); + appProject.createMainModule("acme-app") + .addDependency(libA1) + .addDependency(libB1) + .addDependency(libC1) + .addDependency(libD1) + .addDependency(libE1) + .addDependency(libF1) + .addDependency(libG1) + .addDependency(libH1) + .addDependency(libI1) + .addDependency(libJ1) + .addDependency(libK1) + .addDependency(libL1) + .addDependency(libM1) + .addDependency(libN1) + .addDependency(libO1) + .addDependency(libP1) + .addDependency(libQ1) + .addDependency(libR1) + .addDependency(libS1) + .addDependency(libT1) + .addDependency(libU1) + .addDependency(libV1) + .addDependency(libW1); + repo.install(appProject); + + } + + private TestModule installLibX(TestArtifactRepo repo, String version) { + var projectY1 = TestProject.of("org.project-y", version) + .setRepoUrl("https://project-y.org/code") + .setTag(version); + var libY1 = projectY1.createMainModule("lib-y"); + repo.install(projectY1); + var projectX1 = TestProject.of("org.project-x", version) + .setRepoUrl("https://project-x.org/code") + .setTag(version); + var libX1 = projectX1.createMainModule("lib-x") + .addDependency(libY1); + repo.install(projectX1); + return libX1; + } + + @Override + protected ProjectDependencyConfig initConfig(ProjectDependencyConfig.Mutable config) { + return config.setProjectArtifacts(List.of(ArtifactCoords.jar("org.acme", "acme-app", "1.0"))); + } + + @Override + protected void assertBom(Bom bom) { + assertDependencies(bom, ArtifactCoords.jar("org.acme", "acme-app", "1.0"), + ArtifactCoords.jar("org.project-a", "lib-a", "0.1"), + ArtifactCoords.jar("org.project-b", "lib-b", "0.1"), + ArtifactCoords.jar("org.project-c", "lib-c", "0.1"), + ArtifactCoords.jar("org.project-d", "lib-d", "0.1"), + ArtifactCoords.jar("org.project-e", "lib-e", "0.1"), + ArtifactCoords.jar("org.project-f", "lib-f", "0.1"), + ArtifactCoords.jar("org.project-g", "lib-g", "0.1"), + ArtifactCoords.jar("org.project-h", "lib-h", "0.1"), + ArtifactCoords.jar("org.project-i", "lib-i", "0.1"), + ArtifactCoords.jar("org.project-j", "lib-j", "0.1"), + ArtifactCoords.jar("org.project-k", "lib-k", "0.1"), + ArtifactCoords.jar("org.project-l", "lib-l", "0.1"), + ArtifactCoords.jar("org.project-m", "lib-m", "0.1"), + ArtifactCoords.jar("org.project-n", "lib-n", "0.1"), + ArtifactCoords.jar("org.project-o", "lib-o", "0.1"), + ArtifactCoords.jar("org.project-p", "lib-p", "0.1"), + ArtifactCoords.jar("org.project-q", "lib-q", "0.1"), + ArtifactCoords.jar("org.project-r", "lib-r", "0.1"), + ArtifactCoords.jar("org.project-s", "lib-s", "0.1"), + ArtifactCoords.jar("org.project-t", "lib-t", "0.1"), + ArtifactCoords.jar("org.project-u", "lib-u", "0.1"), + ArtifactCoords.jar("org.project-v", "lib-v", "0.1"), + ArtifactCoords.jar("org.project-w", "lib-w", "0.1")); + + assertDependencies(bom, ArtifactCoords.jar("org.project-a", "lib-a", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-b", "lib-b", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-c", "lib-c", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-d", "lib-d", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-e", "lib-e", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-f", "lib-f", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-g", "lib-g", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-h", "lib-h", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-i", "lib-i", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-j", "lib-j", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-k", "lib-k", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-l", "lib-l", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-m", "lib-m", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-n", "lib-n", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-o", "lib-o", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-p", "lib-p", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-q", "lib-q", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-r", "lib-r", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-s", "lib-s", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-t", "lib-t", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-u", "lib-u", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-v", "lib-v", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + assertDependencies(bom, ArtifactCoords.jar("org.project-w", "lib-w", "0.1"), + ArtifactCoords.jar("org.project-x", "lib-x", "0.1")); + + assertDependencies(bom, ArtifactCoords.jar("org.project-x", "lib-x", "0.1"), + ArtifactCoords.jar("org.project-y", "lib-y", "0.1")); + } +} 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 700fc730..feba9444 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 @@ -24,7 +24,7 @@ public class Report extends BaseDepsToBuildCommand { public boolean flatManifest; @CommandLine.Option(names = { - "--manifest-dependencies" }, description = "Strategy to manifest dependencies: none, tree (the default, based on the default conflict free dependency trees returned by the Maven resolver), graph (records all direct dependencies of each artifact)", defaultValue = "false") + "--manifest-dependencies" }, description = "Strategy to manifest dependencies: none, tree (the default, based on the default conflict free dependency trees returned by the Maven resolver), graph (records all direct dependencies of each artifact)", defaultValue = MANIFEST_DEPS_GRAPH) public String manifestDependencies; @CommandLine.Option(names = { 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 dd6e99e9..432df1e5 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 @@ -200,7 +200,7 @@ public class DependenciesToBuildMojo extends AbstractMojo { *
  • tree - record default (conflicts resolved) dependency trees returned by Maven artifact resolver (the default)
  • *
  • graph - record all direct dependencies of each artifact
  • */ - @Parameter(required = false, property = "manifestDependencies", defaultValue = "tree") + @Parameter(required = false, property = "manifestDependencies", defaultValue = "graph") String manifestDependencies; /** @@ -335,13 +335,17 @@ public void execute() throws MojoExecutionException, MojoFailureException { if (includeNonManaged != null) { depsConfigBuilder.setIncludeNonManaged(includeNonManaged); } - if ("none".equals(manifestDependencies)) { - flatManifest = true; - } else if (manifestDependencies.equals("graph")) { - depsConfigBuilder.setVerboseGraphs(true); - } else if (!manifestDependencies.equals("tree")) { - throw new MojoExecutionException("Unrecognized value '" + manifestDependencies - + "' for parameter manifestDependencies. Supported values include graph, tree, none"); + if (manifest) { + if ("none".equals(manifestDependencies)) { + flatManifest = true; + } else if (manifestDependencies.equals("tree")) { + depsConfigBuilder.setVerboseGraphs(false); + } else if (!manifestDependencies.equals("graph")) { + throw new MojoExecutionException("Unrecognized value '" + manifestDependencies + + "' for parameter manifestDependencies. Supported values include graph, tree, none"); + } else { + depsConfigBuilder.setVerboseGraphs(true); + } } final ProjectDependencyConfig dependencyConfig = depsConfigBuilder.build(); final ProjectDependencyResolver.Builder depsResolver = ProjectDependencyResolver.builder()