From bc18878c04c3917951b2c3c80c667432d0bc4a58 Mon Sep 17 00:00:00 2001 From: Kevin Conner Date: Wed, 15 Mar 2023 11:15:50 -0700 Subject: [PATCH] Remove code generating resolved PURLs, fixes #311 Signed-off-by: Kevin Conner --- .../cyclonedx/maven/BaseCycloneDxMojo.java | 10 ++- .../maven/CycloneDxAggregateMojo.java | 6 +- .../org/cyclonedx/maven/CycloneDxMojo.java | 6 +- .../cyclonedx/maven/CycloneDxPackageMojo.java | 6 +- .../DefaultProjectDependenciesConverter.java | 90 +++++++++---------- .../maven/ProjectDependenciesConverter.java | 31 ++++--- 6 files changed, 78 insertions(+), 71 deletions(-) diff --git a/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java b/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java index 70a68f85..4d8db94b 100644 --- a/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java +++ b/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java @@ -32,6 +32,7 @@ import org.cyclonedx.exception.GeneratorException; import org.cyclonedx.generators.json.BomJsonGenerator; import org.cyclonedx.generators.xml.BomXmlGenerator; +import org.cyclonedx.maven.ProjectDependenciesConverter.BomDependencies; import org.cyclonedx.model.Bom; import org.cyclonedx.model.Component; import org.cyclonedx.model.Dependency; @@ -356,7 +357,7 @@ private void saveBomToFile(String bomString, String extension, Parser bomParser) } } - protected Map extractBOMDependencies(MavenProject mavenProject) throws MojoExecutionException { + protected BomDependencies extractBOMDependencies(MavenProject mavenProject) throws MojoExecutionException { ProjectDependenciesConverter.MavenDependencyScopes include = new ProjectDependenciesConverter.MavenDependencyScopes(includeCompileScope, includeProvidedScope, includeRuntimeScope, includeTestScope, includeSystemScope); return projectDependenciesConverter.extractBOMDependencies(mavenProject, include, excludeTypes); } @@ -402,9 +403,10 @@ protected void logParameters() { } } - protected void populateComponents(final Set topLevelComponents, final Map components, final Set artifacts, final ProjectDependencyAnalysis dependencyAnalysis) { - for (Artifact artifact: artifacts) { - final String purl = generatePackageUrl(artifact); + protected void populateComponents(final Set topLevelComponents, final Map components, final Map artifacts, final ProjectDependencyAnalysis dependencyAnalysis) { + for (Map.Entry entry: artifacts.entrySet()) { + final String purl = entry.getKey(); + final Artifact artifact = entry.getValue(); final Component.Scope artifactScope = (dependencyAnalysis != null ? inferComponentScope(artifact, dependencyAnalysis) : null); final Component component = components.get(purl); if (component == null) { diff --git a/src/main/java/org/cyclonedx/maven/CycloneDxAggregateMojo.java b/src/main/java/org/cyclonedx/maven/CycloneDxAggregateMojo.java index 769c15b1..447ffefb 100644 --- a/src/main/java/org/cyclonedx/maven/CycloneDxAggregateMojo.java +++ b/src/main/java/org/cyclonedx/maven/CycloneDxAggregateMojo.java @@ -24,6 +24,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; +import org.cyclonedx.maven.ProjectDependenciesConverter.BomDependencies; import org.cyclonedx.model.Component; import org.cyclonedx.model.Dependency; @@ -121,13 +122,14 @@ protected String extractComponentsAndDependencies(final Set topLevelComp continue; } - final Map projectDependencies = extractBOMDependencies(mavenProject); + final BomDependencies bomDependencies = extractBOMDependencies(mavenProject); + final Map projectDependencies = bomDependencies.getDependencies(); final Component projectBomComponent = convert(mavenProject.getArtifact()); components.put(projectBomComponent.getPurl(), projectBomComponent); topLevelComponents.add(projectBomComponent.getPurl()); - populateComponents(topLevelComponents, components, mavenProject.getArtifacts(), doProjectDependencyAnalysis(mavenProject)); + populateComponents(topLevelComponents, components, bomDependencies.getArtifacts(), doProjectDependencyAnalysis(mavenProject)); projectDependencies.forEach(dependencies::putIfAbsent); } diff --git a/src/main/java/org/cyclonedx/maven/CycloneDxMojo.java b/src/main/java/org/cyclonedx/maven/CycloneDxMojo.java index 84351ccf..463a0687 100644 --- a/src/main/java/org/cyclonedx/maven/CycloneDxMojo.java +++ b/src/main/java/org/cyclonedx/maven/CycloneDxMojo.java @@ -29,6 +29,7 @@ import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalyzerException; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.cyclonedx.maven.ProjectDependenciesConverter.BomDependencies; import org.cyclonedx.model.Component; import org.cyclonedx.model.Dependency; @@ -93,13 +94,14 @@ protected ProjectDependencyAnalysis doProjectDependencyAnalysis(MavenProject mav protected String extractComponentsAndDependencies(final Set topLevelComponents, final Map components, final Map dependencies) throws MojoExecutionException { getLog().info(MESSAGE_RESOLVING_DEPS); - final Map projectDependencies = extractBOMDependencies(getProject()); + final BomDependencies bomDependencies = extractBOMDependencies(getProject()); + final Map projectDependencies = bomDependencies.getDependencies(); final Component projectBomComponent = convert(getProject().getArtifact()); components.put(projectBomComponent.getPurl(), projectBomComponent); topLevelComponents.add(projectBomComponent.getPurl()); - populateComponents(topLevelComponents, components, getProject().getArtifacts(), doProjectDependencyAnalysis(getProject())); + populateComponents(topLevelComponents, components, bomDependencies.getArtifacts(), doProjectDependencyAnalysis(getProject())); projectDependencies.forEach(dependencies::putIfAbsent); diff --git a/src/main/java/org/cyclonedx/maven/CycloneDxPackageMojo.java b/src/main/java/org/cyclonedx/maven/CycloneDxPackageMojo.java index 075ae151..3dbb3182 100644 --- a/src/main/java/org/cyclonedx/maven/CycloneDxPackageMojo.java +++ b/src/main/java/org/cyclonedx/maven/CycloneDxPackageMojo.java @@ -24,6 +24,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; +import org.cyclonedx.maven.ProjectDependenciesConverter.BomDependencies; import org.cyclonedx.model.Component; import org.cyclonedx.model.Dependency; @@ -64,13 +65,14 @@ protected String extractComponentsAndDependencies(Set topLevelComponents } getLog().info("Analyzing " + mavenProject.getArtifactId()); - final Map projectDependencies = extractBOMDependencies(mavenProject); + final BomDependencies bomDependencies = extractBOMDependencies(mavenProject); + final Map projectDependencies = bomDependencies.getDependencies(); final Component projectBomComponent = convert(mavenProject.getArtifact()); components.put(projectBomComponent.getPurl(), projectBomComponent); topLevelComponents.add(projectBomComponent.getPurl()); - populateComponents(topLevelComponents, components, mavenProject.getArtifacts(), null); + populateComponents(topLevelComponents, components, bomDependencies.getArtifacts(), null); projectDependencies.forEach(dependencies::putIfAbsent); } diff --git a/src/main/java/org/cyclonedx/maven/DefaultProjectDependenciesConverter.java b/src/main/java/org/cyclonedx/maven/DefaultProjectDependenciesConverter.java index c452bde0..0903e0c5 100644 --- a/src/main/java/org/cyclonedx/maven/DefaultProjectDependenciesConverter.java +++ b/src/main/java/org/cyclonedx/maven/DefaultProjectDependenciesConverter.java @@ -18,7 +18,10 @@ */ package org.cyclonedx.maven; +import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.DefaultProjectBuildingRequest; @@ -34,12 +37,13 @@ import org.eclipse.aether.artifact.ArtifactProperties; import org.eclipse.aether.collection.CollectResult; import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.repository.LocalRepositoryManager; import org.eclipse.aether.util.graph.transformer.ConflictResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; @@ -66,19 +70,21 @@ public class DefaultProjectDependenciesConverter implements ProjectDependenciesC private MavenDependencyScopes include; @Override - public Map extractBOMDependencies(MavenProject mavenProject, MavenDependencyScopes include, String[] excludeTypes) throws MojoExecutionException { + public BomDependencies extractBOMDependencies(MavenProject mavenProject, MavenDependencyScopes include, String[] excludeTypes) throws MojoExecutionException { this.include = include; excludeTypesSet = new HashSet<>(Arrays.asList(excludeTypes)); final ProjectBuildingRequest buildingRequest = getProjectBuildingRequest(mavenProject); - final Map resolvedPUrls = generateResolvedPUrls(mavenProject); - final Map dependencies = new LinkedHashMap<>(); + final Map mavenArtifacts = new LinkedHashMap<>(); try { final DelegatingRepositorySystem delegateRepositorySystem = new DelegatingRepositorySystem(aetherRepositorySystem); final DependencyCollectorBuilder dependencyCollectorBuilder = new DefaultDependencyCollectorBuilder(delegateRepositorySystem); - dependencyCollectorBuilder.collectDependencyGraph(buildingRequest, null); + + final org.apache.maven.shared.dependency.graph.DependencyNode mavenRoot = dependencyCollectorBuilder.collectDependencyGraph(buildingRequest, null); + populateArtifactMap(mavenArtifacts, mavenRoot, false); + final CollectResult collectResult = delegateRepositorySystem.getCollectResult(); if (collectResult == null) { throw new MojoExecutionException("Failed to generate aether dependency graph"); @@ -86,16 +92,30 @@ public Map extractBOMDependencies(MavenProject mavenProject, final DependencyNode root = collectResult.getRoot(); // Generate the tree, removing excluded and filtered nodes - final Set loggedReplacementPUrls = new HashSet<>(); final Set loggedFilteredArtifacts = new HashSet<>(); - buildDependencyGraphNode(dependencies, root, null, null, resolvedPUrls, loggedReplacementPUrls, loggedFilteredArtifacts); + buildDependencyGraphNode(dependencies, root, null, null, loggedFilteredArtifacts); } catch (DependencyCollectorBuilderException e) { // When executing makeAggregateBom, some projects may not yet be built. Workaround is to warn on this // rather than throwing an exception https://github.com/CycloneDX/cyclonedx-maven-plugin/issues/55 logger.warn("An error occurred building dependency graph: " + e.getMessage()); } - return dependencies; + return new BomDependencies(dependencies, mavenArtifacts); + } + + private void populateArtifactMap(final Map artifactMap, final org.apache.maven.shared.dependency.graph.DependencyNode node, final boolean resolve) { + final Artifact artifact = node.getArtifact(); + final String purl = modelConverter.generatePackageUrl(artifact); + if (!artifactMap.containsKey(purl)) { + if (resolve && !artifact.isResolved()) { + session.getLocalRepository().find(artifact); + } + artifactMap.put(purl, artifact); + } + + for (org.apache.maven.shared.dependency.graph.DependencyNode child: node.getChildren()) { + populateArtifactMap(artifactMap, child, true); + } } private boolean isFilteredNode(final DependencyNode node, final Set loggedFilteredArtifacts) { @@ -129,10 +149,10 @@ private boolean isFilteredNode(final DependencyNode node, final Set logg scoped = Boolean.FALSE; } final boolean result = Boolean.FALSE.equals(scoped); - if (result) { + if (result && logger.isDebugEnabled()) { final String purl = modelConverter.generatePackageUrl(node.getArtifact()); final String key = purl + ":" + originalScope + ":" + node.getDependency().getScope(); - if (loggedFilteredArtifacts.add(key) && logger.isDebugEnabled()) { + if (loggedFilteredArtifacts.add(key)) { logger.debug("Filtering " + purl + " with original scope " + originalScope + " and scope " + node.getDependency().getScope()); } } @@ -145,9 +165,7 @@ private boolean isExcludedNode(final DependencyNode node) { } private void buildDependencyGraphNode(final Map dependencies, DependencyNode node, - final Dependency parent, final String parentClassifierlessPUrl, final Map resolvedPUrls, - final Set loggedReplacementPUrls, final Set loggedFilteredArtifacts) { - String purl = modelConverter.generatePackageUrl(node.getArtifact()); + final Dependency parent, final String parentClassifierlessPUrl, final Set loggedFilteredArtifacts) { if (isExcludedNode(node) || (parent != null && isFilteredNode(node, loggedFilteredArtifacts))) { return; @@ -157,50 +175,26 @@ private void buildDependencyGraphNode(final Map dependencies if (node.getChildren().isEmpty()) { final Map nodeData = node.getData(); final DependencyNode winner = (DependencyNode) nodeData.get(ConflictResolver.NODE_DATA_WINNER); - final String resolvedPurl = resolvedPUrls.get(modelConverter.generateVersionlessPackageUrl(node.getArtifact())); - if (!purl.equals(resolvedPurl)) { - if (!loggedReplacementPUrls.contains(purl)) { - if (logger.isDebugEnabled()) { - logger.debug("Replacing reference to " + purl + " with resolved package url " + resolvedPurl); - } - loggedReplacementPUrls.add(purl); - } - purl = resolvedPurl; - } if (winner != null) { node = winner; } } - Dependency topDependency = new Dependency(purl); - final Dependency origDependency = dependencies.putIfAbsent(purl, topDependency); - if (origDependency != null) { - topDependency = origDependency; - } - if (parent != null) { - parent.addDependency(new Dependency(purl)); - } - - final String nodeClassifierlessPUrl = modelConverter.generateClassifierlessPackageUrl(node.getArtifact()); - if (!nodeClassifierlessPUrl.equals(parentClassifierlessPUrl)) { - for (final DependencyNode childrenNode : node.getChildren()) { - buildDependencyGraphNode(dependencies, childrenNode, topDependency, nodeClassifierlessPUrl, resolvedPUrls, loggedReplacementPUrls, loggedFilteredArtifacts); + String purl = modelConverter.generatePackageUrl(node.getArtifact()); + if (!dependencies.containsKey(purl)) { + Dependency topDependency = new Dependency(purl); + dependencies.put(purl, topDependency); + final String nodeClassifierlessPUrl = modelConverter.generateClassifierlessPackageUrl(node.getArtifact()); + if (!nodeClassifierlessPUrl.equals(parentClassifierlessPUrl)) { + for (final DependencyNode childrenNode : node.getChildren()) { + buildDependencyGraphNode(dependencies, childrenNode, topDependency, nodeClassifierlessPUrl, loggedFilteredArtifacts); + } } } - } - /** - * Generate a map of versionless purls to their resolved versioned purl - * @return the map of versionless purls to resolved versioned purls - */ - private Map generateResolvedPUrls(final MavenProject mavenProject) { - final Map resolvedPUrls = new HashMap<>(); - final Artifact projectArtifact = mavenProject.getArtifact(); - resolvedPUrls.put(modelConverter.generateVersionlessPackageUrl(projectArtifact), modelConverter.generatePackageUrl(projectArtifact)); - for (Artifact artifact: mavenProject.getArtifacts()) { - resolvedPUrls.put(modelConverter.generateVersionlessPackageUrl(artifact), modelConverter.generatePackageUrl(artifact)); + if (parent != null) { + parent.addDependency(new Dependency(purl)); } - return resolvedPUrls; } /** diff --git a/src/main/java/org/cyclonedx/maven/ProjectDependenciesConverter.java b/src/main/java/org/cyclonedx/maven/ProjectDependenciesConverter.java index 10568769..1fa0f53d 100644 --- a/src/main/java/org/cyclonedx/maven/ProjectDependenciesConverter.java +++ b/src/main/java/org/cyclonedx/maven/ProjectDependenciesConverter.java @@ -18,16 +18,13 @@ */ package org.cyclonedx.maven; -import org.apache.maven.artifact.resolver.filter.ArtifactFilter; -import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter; +import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.cyclonedx.model.Component; import org.cyclonedx.model.Dependency; import org.cyclonedx.model.Metadata; -import java.util.Collection; -import java.util.HashSet; import java.util.Map; /** @@ -36,7 +33,7 @@ */ public interface ProjectDependenciesConverter { - Map extractBOMDependencies(MavenProject mavenProject, MavenDependencyScopes include, String[] excludes) throws MojoExecutionException; + BomDependencies extractBOMDependencies(MavenProject mavenProject, MavenDependencyScopes include, String[] excludes) throws MojoExecutionException; /** * Check consistency between BOM components and BOM dependencies, and cleanup: drop components found while walking the @@ -58,15 +55,23 @@ public MavenDependencyScopes(boolean compile, boolean provided, boolean runtime, this.test = test; this.system = system; } + } + + public static class BomDependencies { + private final Map dependencies; + private final Map artifacts; + + public BomDependencies(final Map dependencies, final Map artifacts) { + this.dependencies = dependencies; + this.artifacts = artifacts; + } + + public final Map getDependencies() { + return dependencies; + } - public ArtifactFilter getArtifactFilter() { - final Collection scope = new HashSet<>(); - if (compile) scope.add("compile"); - if (provided) scope.add("provided"); - if (runtime) scope.add("runtime"); - if (system) scope.add("system"); - if (test) scope.add("test"); - return new CumulativeScopeArtifactFilter(scope); + public final Map getArtifacts() { + return artifacts; } } }