Skip to content

Commit 111e199

Browse files
✨(draft) Resolve BOM POMs for dependencies
Adds a "bom" key to each dependency node in case it declares BOM POMs in as part of its dependency management section of the "pom.xml" file. The algorithm implemented is roughly: - Traverse the dependency graph - Resolve the POM artifact for a node - Build a MavenProject for a node - Check the original model's dependency management section - Filter out BOM POMs from other dependencies - For each BOM POM found: - Resolve the POM artifact - Build the MavenProject (so we can get the resolved URL) - Resolve the potential hierarchy of parent POMs - Add it to the "boms" section of the relative node Signed-off-by: Bruno Pimentel <bpimente@redhat.com>
1 parent d0bca39 commit 111e199

File tree

4 files changed

+177
-4
lines changed

4 files changed

+177
-4
lines changed

maven_plugin/src/main/java/io/github/chains_project/maven_lockfile/LockFileFacade.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.github.chains_project.maven_lockfile.data.VersionNumber;
1616
import io.github.chains_project.maven_lockfile.graph.DependencyGraph;
1717
import io.github.chains_project.maven_lockfile.reporting.PluginLogManager;
18+
import io.github.chains_project.maven_lockfile.resolvers.BomResolver;
1819
import io.github.chains_project.maven_lockfile.resolvers.ProjectBuilder;
1920
import java.nio.file.Path;
2021
import java.util.*;
@@ -109,6 +110,7 @@ public static LockFile generateLockFileFromProject(
109110
.collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(
110111
io.github.chains_project.maven_lockfile.graph.DependencyNode::getComparatorString))));
111112
var pom = constructRecursivePom(project, checksumCalculator);
113+
resolveBoms(graph, session, project, checksumCalculator);
112114
return new LockFile(
113115
GroupId.of(project.getGroupId()),
114116
ArtifactId.of(project.getArtifactId()),
@@ -369,4 +371,32 @@ private static Pom constructRecursivePom(
369371

370372
return lastPom;
371373
}
374+
375+
private static void resolveBoms(
376+
DependencyGraph graph,
377+
MavenSession session,
378+
MavenProject rootProject,
379+
AbstractChecksumCalculator checksumCalculator) {
380+
ProjectBuilder projectBuilder = new ProjectBuilder(session, rootProject.getPluginArtifactRepositories());
381+
BomResolver bomResolver =
382+
new BomResolver(session, rootProject.getRemoteArtifactRepositories(), checksumCalculator);
383+
384+
graph.getGraph().forEach(node -> {
385+
var projectOptional = projectBuilder.buildFromGav(
386+
node.getGroupId().getValue(),
387+
node.getArtifactId().getValue(),
388+
node.getVersion().getValue());
389+
390+
if (projectOptional.isEmpty()) {
391+
PluginLogManager.getLog().warn(String.format("Skipping BOM resolution for %s", node));
392+
return;
393+
}
394+
395+
Set<Pom> boms = bomResolver.resolveForProject(projectOptional.get());
396+
397+
if (boms.size() > 0) {
398+
node.setBoms(boms);
399+
}
400+
});
401+
}
372402
}

maven_plugin/src/main/java/io/github/chains_project/maven_lockfile/graph/DependencyNode.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.github.chains_project.maven_lockfile.data.Classifier;
77
import io.github.chains_project.maven_lockfile.data.GroupId;
88
import io.github.chains_project.maven_lockfile.data.MavenScope;
9+
import io.github.chains_project.maven_lockfile.data.Pom;
910
import io.github.chains_project.maven_lockfile.data.RepositoryId;
1011
import io.github.chains_project.maven_lockfile.data.ResolvedUrl;
1112
import io.github.chains_project.maven_lockfile.data.VersionNumber;
@@ -39,6 +40,8 @@ public class DependencyNode implements Comparable<DependencyNode> {
3940

4041
private final Set<DependencyNode> children;
4142

43+
private Set<Pom> boms;
44+
4245
DependencyNode(
4346
ArtifactId artifactId,
4447
GroupId groupId,
@@ -117,6 +120,12 @@ public ResolvedUrl getResolved() {
117120
public RepositoryId getRepositoryId() {
118121
return repositoryId;
119122
}
123+
/**
124+
* @return the BOM POMs.
125+
*/
126+
public Set<Pom> getBoms() {
127+
return boms;
128+
}
120129

121130
void addChild(DependencyNode child) {
122131
children.add(child);
@@ -130,6 +139,10 @@ void setParent(NodeId parent) {
130139
this.parent = parent;
131140
}
132141

142+
public void setBoms(Set<Pom> boms) {
143+
this.boms = boms;
144+
}
145+
133146
/**
134147
* @return the children
135148
*/
@@ -190,7 +203,8 @@ public int hashCode() {
190203
selectedVersion,
191204
id,
192205
parent,
193-
children);
206+
children,
207+
boms);
194208
}
195209

196210
@Override
@@ -213,7 +227,8 @@ public boolean equals(Object obj) {
213227
&& Objects.equals(selectedVersion, other.selectedVersion)
214228
&& Objects.equals(id, other.id)
215229
&& Objects.equals(parent, other.parent)
216-
&& Objects.equals(children, other.children);
230+
&& Objects.equals(children, other.children)
231+
&& Objects.equals(boms, other.boms);
217232
}
218233

219234
@Override
@@ -248,7 +263,7 @@ public String toString() {
248263
+ ", classifier=" + classifier + ", type=" + type + ", checksumAlgorithm=" + checksumAlgorithm
249264
+ ", checksum=" + checksum + ", scope=" + scope + ", resolved=" + resolved + ", repositoryId="
250265
+ repositoryId + ", selectedVersion=" + selectedVersion + ", id=" + id + ", parent=" + parent
251-
+ ", children=" + children + "]";
266+
+ ", children=" + children + ", boms=" + boms + "]";
252267
}
253268

254269
public String getComparatorString() {
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package io.github.chains_project.maven_lockfile.resolvers;
2+
3+
import io.github.chains_project.maven_lockfile.checksum.AbstractChecksumCalculator;
4+
import io.github.chains_project.maven_lockfile.data.ArtifactId;
5+
import io.github.chains_project.maven_lockfile.data.GroupId;
6+
import io.github.chains_project.maven_lockfile.data.Pom;
7+
import io.github.chains_project.maven_lockfile.data.VersionNumber;
8+
import io.github.chains_project.maven_lockfile.reporting.PluginLogManager;
9+
import java.util.ArrayList;
10+
import java.util.Collections;
11+
import java.util.List;
12+
import java.util.Set;
13+
import java.util.TreeSet;
14+
import org.apache.maven.artifact.repository.ArtifactRepository;
15+
import org.apache.maven.execution.MavenSession;
16+
import org.apache.maven.model.Dependency;
17+
import org.apache.maven.project.MavenProject;
18+
19+
public class BomResolver {
20+
private final MavenSession session;
21+
22+
@SuppressWarnings("deprecation")
23+
private final List<ArtifactRepository> repositories;
24+
25+
private final AbstractChecksumCalculator checksumCalculator;
26+
27+
@SuppressWarnings("deprecation")
28+
public BomResolver(
29+
MavenSession session,
30+
List<ArtifactRepository> repositories,
31+
AbstractChecksumCalculator checksumCalculator) {
32+
this.session = session;
33+
this.repositories = repositories;
34+
this.checksumCalculator = checksumCalculator;
35+
}
36+
37+
public Set<Pom> resolveForProject(MavenProject project) {
38+
var model = project.getOriginalModel();
39+
var dependencyManagement = model.getDependencyManagement();
40+
var projectBuilder = new ProjectBuilder(session, repositories);
41+
var boms = new TreeSet<Pom>();
42+
43+
if (dependencyManagement == null
44+
|| dependencyManagement.getDependencies().isEmpty()) {
45+
return Collections.emptySet();
46+
}
47+
48+
for (Dependency dependency : dependencyManagement.getDependencies()) {
49+
if ("pom".equals(dependency.getType()) && "import".equals(dependency.getScope())) {
50+
var resolvedVersion = resolveVersionFromPlaceholder(dependency.getVersion(), project);
51+
var bomProjectOptional = projectBuilder.buildFromGav(
52+
dependency.getGroupId(), dependency.getArtifactId(), resolvedVersion);
53+
54+
if (bomProjectOptional.isEmpty()) {
55+
PluginLogManager.getLog().warn(String.format("Could not resolve BOM for %s", dependency));
56+
continue;
57+
}
58+
59+
var bomTree = resolveBomParents(bomProjectOptional.get());
60+
boms.add(bomTree);
61+
}
62+
}
63+
64+
return boms;
65+
}
66+
67+
private String resolveVersionFromPlaceholder(String version, MavenProject project) {
68+
if (version != null && version.startsWith("${") && version.endsWith("}")) {
69+
String propertyName = version.substring(2, version.length() - 1);
70+
71+
// Check project properties (interpolated model has all properties resolved)
72+
var resolvedVersion = project.getModel().getProperties().getProperty(propertyName);
73+
74+
if (resolvedVersion != null) {
75+
return resolvedVersion;
76+
}
77+
}
78+
79+
return version;
80+
}
81+
82+
private Pom resolveBomParents(MavenProject start) {
83+
List<MavenProject> projects = new ArrayList<>();
84+
Pom current = null;
85+
86+
if (!start.hasParent()) {
87+
return mavenProjectToBom(start, checksumCalculator, null);
88+
}
89+
90+
while (start.hasParent()) {
91+
projects.add(start);
92+
start = start.getParent();
93+
}
94+
95+
projects.add(start);
96+
97+
for (MavenProject project : projects.reversed()) {
98+
if (current == null) {
99+
current = mavenProjectToBom(project, checksumCalculator, null);
100+
} else {
101+
var bom = mavenProjectToBom(project, checksumCalculator, current);
102+
current = bom;
103+
}
104+
}
105+
106+
return current;
107+
}
108+
109+
private static Pom mavenProjectToBom(
110+
MavenProject project, AbstractChecksumCalculator checksumCalculator, Pom parent) {
111+
var dependency = project.getModel();
112+
113+
var repoInfo = checksumCalculator.getArtifactResolvedField(project.getArtifact());
114+
var checksum = checksumCalculator.calculateArtifactChecksum(project.getArtifact());
115+
var checksumAlgorithm = checksumCalculator.getChecksumAlgorithm();
116+
117+
return new Pom(
118+
GroupId.of(dependency.getGroupId()),
119+
ArtifactId.of(dependency.getArtifactId()),
120+
VersionNumber.of(dependency.getVersion()),
121+
null,
122+
repoInfo.getResolvedUrl(),
123+
repoInfo.getRepositoryId(),
124+
checksumAlgorithm,
125+
checksum,
126+
parent);
127+
}
128+
}

maven_plugin/src/main/java/io/github/chains_project/maven_lockfile/resolvers/ProjectBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private Optional<MavenProject> buildProjectFromPomFile(File pomFile) {
111111
session.getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
112112
ProjectBuildingResult result = projectBuilder.build(pomFile, buildingRequest);
113113

114-
if (result.getProblems() != null && !result.getProblems().isEmpty()) {
114+
if (result.getProject() == null) {
115115
log.warn(String.format(
116116
"Problems building plugin project for %s: %s",
117117
pomFile.getAbsoluteFile(), result.getProblems()));

0 commit comments

Comments
 (0)