Skip to content

Commit c8770a6

Browse files
committed
flatten-bom
A new mojo that helps you to maintain (and synchronize) with published (but bloated) BOMs. mvn toolbox:flatten-bom -Dbom=g:a:v And outputs flat BOM. Optionally, you can specify -Dgav=g:a:v and output a BOM POM with provided coordinates.
1 parent 7201683 commit c8770a6

File tree

3 files changed

+97
-13
lines changed

3 files changed

+97
-13
lines changed

shared/src/main/java/eu/maveniverse/maven/toolbox/shared/ToolboxCommando.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ Result<List<List<Artifact>>> treeFind(
337337
*/
338338
Result<Model> effectiveModel(ReactorLocator reactorLocator) throws Exception;
339339

340+
/**
341+
* Returns the effective model flattened BOM. Works only for "loaded" BOMs naturally, so it has to be installed or deployed..
342+
*/
343+
Result<Model> flattenBOM(Artifact artifact, ResolutionRoot resolutionRoot) throws Exception;
344+
340345
// Search API related commands: they target one single RemoteRepository
341346

342347
/**

shared/src/main/java/eu/maveniverse/maven/toolbox/shared/internal/ToolboxCommandoImpl.java

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.io.ByteArrayOutputStream;
4444
import java.io.IOException;
4545
import java.io.InputStream;
46+
import java.io.StringReader;
4647
import java.nio.charset.StandardCharsets;
4748
import java.nio.file.Files;
4849
import java.nio.file.Path;
@@ -68,7 +69,9 @@
6869
import java.util.function.BiFunction;
6970
import java.util.function.Predicate;
7071
import java.util.stream.Collectors;
72+
import org.apache.maven.model.DependencyManagement;
7173
import org.apache.maven.model.Model;
74+
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
7275
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
7376
import org.apache.maven.search.api.MAVEN;
7477
import org.apache.maven.search.api.SearchBackend;
@@ -963,31 +966,60 @@ public Result<CollectResult> projectDependencyTree(ReactorLocator reactorLocator
963966
return Result.success(collectResult);
964967
}
965968

966-
@Override
967-
public Result<Model> effectiveModel(ResolutionRoot resolutionRoot) throws Exception {
969+
protected void tellModel(String title, Model model) throws IOException {
970+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
971+
MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer();
972+
mavenXpp3Writer.write(baos, model);
973+
output.doTell(
974+
title != null && !title.trim().isEmpty() ? title + "\n{}" : "{}",
975+
baos.toString(StandardCharsets.UTF_8));
976+
}
977+
978+
protected Result<Model> doEffectiveModel(boolean tell, ResolutionRoot resolutionRoot) throws Exception {
968979
if (!resolutionRoot.isLoad()) {
969980
throw new IllegalArgumentException("only loaded roots can be shown as effective model");
970981
}
971982
ModelResponse response = toolboxResolver.readModel(resolutionRoot.getArtifact());
972-
973-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
974-
MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer();
975-
mavenXpp3Writer.write(baos, response.getEffectiveModel());
976-
output.doTell("Effective model:\n{}", baos.toString(StandardCharsets.UTF_8));
977-
983+
if (tell) {
984+
tellModel("Effective model:", response.getEffectiveModel());
985+
}
978986
return Result.success(response.getEffectiveModel());
979987
}
980988

989+
@Override
990+
public Result<Model> effectiveModel(ResolutionRoot resolutionRoot) throws Exception {
991+
return doEffectiveModel(true, resolutionRoot);
992+
}
993+
981994
@Override
982995
public Result<Model> effectiveModel(ReactorLocator reactorLocator) throws Exception {
983996
requireNonNull(reactorLocator);
984997
Result<Model> result = Result.success(reactorLocator.getCurrentProject().effectiveModel());
998+
tellModel("Effective model:", result.getData().orElseThrow());
999+
return result;
1000+
}
9851001

986-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
987-
MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer();
988-
mavenXpp3Writer.write(baos, result.getData().orElseThrow());
989-
output.doTell("Effective model:\n{}", baos.toString(StandardCharsets.UTF_8));
990-
1002+
@Override
1003+
public Result<Model> flattenBOM(Artifact artifact, ResolutionRoot resolutionRoot) throws Exception {
1004+
requireNonNull(artifact);
1005+
requireNonNull(resolutionRoot);
1006+
Result<Model> result = doEffectiveModel(false, resolutionRoot);
1007+
if (result.isSuccess()) {
1008+
Model resultModel = new MavenXpp3Reader()
1009+
.read(new StringReader(PomSuppliers.empty400(
1010+
artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion())));
1011+
resultModel.setDependencyManagement(new DependencyManagement());
1012+
1013+
Model bomModel = result.getData().orElseThrow();
1014+
if (bomModel.getDependencyManagement() != null) {
1015+
for (org.apache.maven.model.Dependency dependency :
1016+
bomModel.getDependencyManagement().getDependencies()) {
1017+
resultModel.getDependencyManagement().addDependency(dependency);
1018+
}
1019+
}
1020+
tellModel("Flattened BOM:", resultModel);
1021+
return Result.success(resultModel);
1022+
}
9911023
return result;
9921024
}
9931025

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2023-2024 Maveniverse Org.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v2.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-v20.html
7+
*/
8+
package eu.maveniverse.maven.toolbox.plugin.gav;
9+
10+
import eu.maveniverse.maven.toolbox.plugin.GavMojoSupport;
11+
import eu.maveniverse.maven.toolbox.shared.Result;
12+
import eu.maveniverse.maven.toolbox.shared.ToolboxCommando;
13+
import org.apache.maven.model.Model;
14+
import org.apache.maven.plugins.annotations.Mojo;
15+
import org.apache.maven.plugins.annotations.Parameter;
16+
import org.eclipse.aether.artifact.DefaultArtifact;
17+
import picocli.CommandLine;
18+
19+
/**
20+
* Flattens a BOM.
21+
*/
22+
@CommandLine.Command(name = "flatten-bom", description = "Flattens a BOM")
23+
@Mojo(name = "gav-flatten-bom", requiresProject = false, threadSafe = true)
24+
public class GavFlattenBomMojo extends GavMojoSupport {
25+
/**
26+
* The GAV to emit flattened BOM with.
27+
*/
28+
@CommandLine.Parameters(
29+
index = "0",
30+
defaultValue = "org.acme:acme:1.0",
31+
description = "The GAV to emit flattened BOM with")
32+
@Parameter(property = "gav", defaultValue = "org.acme:acme:1.0")
33+
private String gav;
34+
35+
/**
36+
* The GAV of BOM to flatten.
37+
*/
38+
@CommandLine.Parameters(index = "0", description = "The GAV of BOM to flatten")
39+
@Parameter(property = "bom", required = true)
40+
private String bom;
41+
42+
@Override
43+
protected Result<Model> doExecute() throws Exception {
44+
ToolboxCommando toolboxCommando = getToolboxCommando();
45+
return toolboxCommando.flattenBOM(new DefaultArtifact(gav), toolboxCommando.loadGav(bom));
46+
}
47+
}

0 commit comments

Comments
 (0)