Skip to content

Commit 1d332e2

Browse files
authored
Remove the use of maven file generator so we have more control over the way the bom is serialized. (Azure#25125)
1 parent c029d7d commit 1d332e2

File tree

5 files changed

+159
-66
lines changed

5 files changed

+159
-66
lines changed

eng/bomgenerator/generateAzureSDKBOM.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ if(! (Test-Path $defaultPomFilePath)) {
2121
}
2222

2323
$mvnResults = mvn install
24-
$mvnResults = "mvn exec:java -Dexec.args=`"-inputDir=$inputDir -outputDir=$outputDir -mode=analyze`""
24+
$mvnResults = "mvn exec:java -Dexec.args=`"-inputDir=$inputDir -outputDir=$outputDir -mode=generate`""

eng/bomgenerator/src/main/java/com/azure/tools/bomgenerator/BomGenerator.java

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,34 @@
44
package com.azure.tools.bomgenerator;
55

66
import com.azure.tools.bomgenerator.models.BomDependency;
7+
import com.azure.tools.bomgenerator.models.BomDependencyManagement;
8+
import com.fasterxml.jackson.annotation.JsonInclude;
9+
import com.fasterxml.jackson.databind.SerializationFeature;
10+
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
711
import org.apache.maven.model.Dependency;
812
import org.apache.maven.model.DependencyManagement;
913
import org.apache.maven.model.Model;
10-
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
11-
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
12-
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
1314
import org.slf4j.Logger;
1415
import org.slf4j.LoggerFactory;
15-
16+
import org.w3c.dom.Document;
17+
import org.w3c.dom.Node;
18+
import org.xml.sax.InputSource;
19+
import org.xml.sax.SAXException;
20+
21+
import javax.xml.parsers.DocumentBuilder;
22+
import javax.xml.parsers.DocumentBuilderFactory;
23+
import javax.xml.parsers.ParserConfigurationException;
24+
import javax.xml.transform.OutputKeys;
25+
import javax.xml.transform.Transformer;
26+
import javax.xml.transform.TransformerException;
27+
import javax.xml.transform.TransformerFactory;
28+
import javax.xml.transform.dom.DOMSource;
29+
import javax.xml.transform.stream.StreamResult;
30+
import java.io.File;
1631
import java.io.FileNotFoundException;
17-
import java.io.FileReader;
1832
import java.io.FileWriter;
1933
import java.io.IOException;
34+
import java.io.StringReader;
2035
import java.nio.file.Files;
2136
import java.nio.file.Path;
2237
import java.nio.file.Paths;
@@ -29,9 +44,9 @@
2944
import java.util.stream.Collectors;
3045

3146
import static com.azure.tools.bomgenerator.Utils.ANALYZE_MODE;
32-
import static com.azure.tools.bomgenerator.Utils.BASE_AZURE_GROUPID;
3347
import static com.azure.tools.bomgenerator.Utils.AZURE_PERF_LIBRARY_IDENTIFIER;
3448
import static com.azure.tools.bomgenerator.Utils.AZURE_TEST_LIBRARY_IDENTIFIER;
49+
import static com.azure.tools.bomgenerator.Utils.BASE_AZURE_GROUPID;
3550
import static com.azure.tools.bomgenerator.Utils.EXCLUSION_LIST;
3651
import static com.azure.tools.bomgenerator.Utils.GENERATE_MODE;
3752
import static com.azure.tools.bomgenerator.Utils.INPUT_DEPENDENCY_PATTERN;
@@ -40,8 +55,10 @@
4055
import static com.azure.tools.bomgenerator.Utils.STRING_SPLIT_BY_COLON;
4156
import static com.azure.tools.bomgenerator.Utils.isPublishedArtifact;
4257
import static com.azure.tools.bomgenerator.Utils.parsePomFileContent;
58+
import static com.azure.tools.bomgenerator.Utils.parsePomFileModel;
4359
import static com.azure.tools.bomgenerator.Utils.toBomDependencyNoVersion;
4460
import static com.azure.tools.bomgenerator.Utils.validateNotNullOrEmpty;
61+
import static javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION;
4562

4663
public class BomGenerator {
4764
private String outputFileName;
@@ -137,8 +154,6 @@ private boolean generate() {
137154

138155
// 4. Create the new BOM file.
139156
if (!validationFailed) {
140-
// Rewrite the existing BOM to have the dependencies in the order in which we insert them, making the diff PR easier to review.
141-
rewriteExistingBomFile();
142157
writeBom(outputDependencies);
143158
return true;
144159
}
@@ -257,28 +272,41 @@ private BomDependency scanDependency(String line) {
257272
}
258273

259274
private Model readModel() {
260-
MavenXpp3Reader reader = new MavenXpp3Reader();
261-
try {
262-
Model model = reader.read(new FileReader(this.pomFileName));
263-
return model;
264-
} catch (XmlPullParserException | IOException e) {
265-
logger.error("BOM reading failed with: {}", e.toString());
266-
}
267-
268-
return null;
269-
}
270-
271-
private void writeModel(Model model) {
272-
String pomFileName = this.pomFileName;
273-
writeModel(pomFileName, model);
275+
return parsePomFileModel(this.pomFileName, Model.class);
274276
}
275277

276-
private void writeModel(String fileName, Model model) {
277-
MavenXpp3Writer writer = new MavenXpp3Writer();
278+
private void writeModel(String inputFileName, String outputFileName, Model model) {
279+
// First read the pom file.
278280
try {
279-
writer.write(new FileWriter(fileName), model);
280-
} catch (IOException exception) {
281-
logger.error("BOM writing failed with: {}", exception.toString());
281+
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
282+
Document oldBomDoc = db.parse(new File(inputFileName));
283+
Node oldDependencyManagementNode = oldBomDoc.getElementsByTagName("dependencyManagement").item(0);
284+
Node parentNode = oldDependencyManagementNode.getParentNode();
285+
286+
// Now add the other node to this list.
287+
XmlMapper mapper = new XmlMapper();
288+
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
289+
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
290+
BomDependencyManagement dependencyManagement = new BomDependencyManagement(model.getDependencyManagement().getDependencies());
291+
String dependencies = mapper.writeValueAsString(dependencyManagement);
292+
DocumentBuilder newBomDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder();
293+
Document newDependencies = newBomDoc.parse(new InputSource(new StringReader(dependencies)));
294+
Node newDependencyManagementNode = newDependencies.getElementsByTagName("dependencyManagement").item(0);
295+
Node firstDocImportedDependencyManagementNode = oldBomDoc.importNode(newDependencyManagementNode, true);
296+
parentNode.replaceChild(firstDocImportedDependencyManagementNode, oldDependencyManagementNode);
297+
298+
// Use a Transformer for output
299+
TransformerFactory tFactory = TransformerFactory.newInstance();
300+
Transformer transformer = tFactory.newTransformer();
301+
transformer.setOutputProperty(OMIT_XML_DECLARATION, "yes");
302+
transformer.setOutputProperty(OutputKeys.INDENT, "no");
303+
DOMSource source = new DOMSource(oldBomDoc);
304+
FileWriter writer = new FileWriter(outputFileName);
305+
StreamResult result = new StreamResult(writer);
306+
transformer.transform(source, result);
307+
308+
} catch (IOException | ParserConfigurationException | SAXException | TransformerException e) {
309+
e.printStackTrace();
282310
}
283311
}
284312

@@ -295,15 +323,6 @@ private List<Dependency> getExternalDependencies() {
295323
return management.getDependencies().stream().filter(dependency -> dependency.getType().equals(POM_TYPE)).collect(Collectors.toList());
296324
}
297325

298-
private void rewriteExistingBomFile() {
299-
Model model = readModel();
300-
DependencyManagement management = model.getDependencyManagement();
301-
List<Dependency> dependencies = management.getDependencies();
302-
dependencies.sort(new DependencyComparator());
303-
management.setDependencies(dependencies);
304-
writeModel(model);
305-
}
306-
307326
private void writeBom(Collection<BomDependency> bomDependencies) {
308327
Model model = readModel();
309328
DependencyManagement management = model.getDependencyManagement();
@@ -318,6 +337,6 @@ private void writeBom(Collection<BomDependency> bomDependencies) {
318337
dependencies.addAll(externalBomDependencies);
319338
dependencies.sort(new DependencyComparator());
320339
management.setDependencies(dependencies);
321-
writeModel(this.outputFileName, model);
340+
writeModel(this.pomFileName, this.outputFileName, model);
322341
}
323342
}

eng/bomgenerator/src/main/java/com/azure/tools/bomgenerator/Utils.java

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77
import com.azure.tools.bomgenerator.models.BomDependencyNoVersion;
88
import com.fasterxml.jackson.databind.DeserializationFeature;
99
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import com.fasterxml.jackson.databind.SerializationFeature;
1011
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
12+
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
1113
import org.apache.maven.model.Dependency;
12-
import org.apache.maven.model.DependencyManagement;
1314
import org.apache.maven.model.Model;
14-
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
15-
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
1615
import org.jboss.shrinkwrap.resolver.api.maven.Maven;
1716
import org.jboss.shrinkwrap.resolver.api.maven.MavenFormatStage;
1817
import org.jboss.shrinkwrap.resolver.api.maven.MavenResolvedArtifact;
@@ -26,9 +25,9 @@
2625
import org.slf4j.LoggerFactory;
2726

2827
import java.io.FileReader;
28+
import java.io.FileWriter;
2929
import java.io.IOException;
3030
import java.io.InputStreamReader;
31-
import java.io.Reader;
3231
import java.net.URI;
3332
import java.net.http.HttpClient;
3433
import java.net.http.HttpRequest;
@@ -173,45 +172,67 @@ static BomDependencyNoVersion toBomDependencyNoVersion(BomDependency bomDependen
173172
return new BomDependencyNoVersion(bomDependency.getGroupId(), bomDependency.getArtifactId());
174173
}
175174

176-
static List<BomDependency> parsePomFileContent(String fileName) {
175+
static <T> T parsePomFileModel(String fileName, Class<T> valueType) {
177176
try (FileReader reader = new FileReader(fileName)) {
178-
return parsePomFileContent(reader);
179-
} catch (IOException exception) {
180-
logger.error("Failed to read the contents of the pom file: {}", fileName);
177+
return parsePomFileModel(reader, valueType);
178+
}
179+
catch(IOException exception) {
180+
logger.error("Failed to read the contents of the file.");
181181
}
182182

183-
return new ArrayList<>();
183+
return null;
184184
}
185185

186-
static List<BomDependency> parsePomFileContent(Reader responseStream) {
186+
static <T> T parsePomFileModel(InputStreamReader reader, Class<T> valueType) {
187+
ObjectMapper mapper = new XmlMapper();
188+
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
189+
try{
190+
T value = mapper.readValue(reader, valueType);
191+
return value;
192+
}
193+
catch(IOException exception) {
194+
logger.error("Failed to read the contents of the file.");
195+
}
196+
197+
return null;
198+
}
199+
200+
static List<BomDependency> parsePomFileContent(InputStreamReader reader) {
201+
Model value = parsePomFileModel(reader, Model.class);
202+
return parseDependenciesFromModel(value);
203+
}
204+
205+
static List<BomDependency> parseDependenciesFromModel(Model value) {
187206
List<BomDependency> bomDependencies = new ArrayList<>();
188207
List<Dependency> dependencies;
189208

190-
ObjectMapper mapper = new XmlMapper();
191-
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
192-
try {
193-
Model value = mapper.readValue(responseStream, Model.class);
194-
if(value.getPackaging().equalsIgnoreCase("pom")) {
195-
// This is a bom file.
196-
dependencies = value.getDependencyManagement().getDependencies();
197-
}
198-
else {
199-
dependencies = value.getDependencies();
200-
}
209+
if (value == null) {
210+
return bomDependencies;
211+
}
201212

202-
if(dependencies == null) {
203-
return bomDependencies;
204-
}
213+
if (value.getPackaging().equalsIgnoreCase("pom")) {
214+
// This is a bom file.
215+
dependencies = value.getDependencyManagement().getDependencies();
216+
} else {
217+
dependencies = value.getDependencies();
218+
}
205219

206-
Properties properties = value.getProperties();
207-
bomDependencies.addAll(parseDependencyVersion(dependencies, properties, value.getModelVersion()));
208-
} catch (IOException exception) {
209-
exception.printStackTrace();
220+
if (dependencies == null) {
221+
return bomDependencies;
210222
}
211223

224+
Properties properties = value.getProperties();
225+
bomDependencies.addAll(parseDependencyVersion(dependencies, properties, value.getModelVersion()));
226+
212227
return bomDependencies.stream().distinct().collect(Collectors.toList());
213228
}
214229

230+
231+
static List<BomDependency> parsePomFileContent(String fileName) {
232+
Model value = parsePomFileModel(fileName, Model.class);
233+
return parseDependenciesFromModel(value);
234+
}
235+
215236
static List<BomDependency> parseDependencyVersion(List<Dependency> dependencies, Properties properties, String modelVersion) {
216237
return dependencies.stream().map(dep -> {
217238
String version = getPropertyName(dep.getVersion());

eng/bomgenerator/src/main/java/com/azure/tools/bomgenerator/models/BomDependency.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import org.jboss.shrinkwrap.resolver.api.maven.ScopeType;
77

8+
89
public class BomDependency extends BomDependencyNoVersion {
910
private String version;
1011
private ScopeType scope;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.azure.tools.bomgenerator.models;
2+
3+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
4+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
5+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
6+
import java.util.List;
7+
import java.util.stream.Collectors;
8+
9+
@JacksonXmlRootElement(localName = "dependencyManagement")
10+
public class BomDependencyManagement {
11+
12+
@JacksonXmlElementWrapper(localName = "dependencies")
13+
@JacksonXmlProperty(localName = "dependency")
14+
private List<Dependency> dependencies;
15+
16+
public BomDependencyManagement(List<org.apache.maven.model.Dependency> dependencies) {
17+
this.dependencies = dependencies
18+
.stream()
19+
.map(dependency ->
20+
new Dependency(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), dependency.getType(), dependency.getScope()))
21+
.collect(Collectors.toList());
22+
}
23+
}
24+
25+
class Dependency {
26+
@JacksonXmlProperty(localName = "groupId")
27+
private String groupId;
28+
29+
@JacksonXmlProperty(localName = "artifactId")
30+
private String artifactId;
31+
32+
@JacksonXmlProperty(localName = "version")
33+
private String version;
34+
35+
@JacksonXmlProperty(localName = "type")
36+
private String type;
37+
38+
@JacksonXmlProperty(localName = "scope")
39+
private String scope;
40+
41+
Dependency(String groupId, String artifactId, String version, String type, String scope) {
42+
this.artifactId = artifactId;
43+
this.groupId = groupId;
44+
this.version = version;
45+
46+
// We only want to serialize the pom type.
47+
if(type.equals("pom")) {
48+
this.type = type;
49+
}
50+
this.scope = scope;
51+
}
52+
}

0 commit comments

Comments
 (0)