Skip to content

Commit

Permalink
ISPN-12352 Set license information when missing
Browse files Browse the repository at this point in the history
  • Loading branch information
pruivo committed Sep 24, 2020
1 parent 766c544 commit 14fc7a9
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 29 deletions.
78 changes: 78 additions & 0 deletions tools/src/main/java/org/infinispan/tools/Dependency.java
@@ -0,0 +1,78 @@
package org.infinispan.tools;

import java.util.Objects;

import org.w3c.dom.Node;

/**
* Dependency from licenses.xml file.
* <p>
* It contains the group/artifact/version and the corresponding XML {@link Node}.
* <p>
* Note: the artifact is "empty" for NodeJS dependencies.
*
* @author Pedro Ruivo
* @since 12.0
*/
public class Dependency {
private final String group;
private final String artifact;
private final String version;
private final Node node;

Dependency(String group, String artifact, String version, Node node) {
this.group = group;
this.artifact = artifact;
this.version = version;
this.node = node;
}

public String getGroup() {
return group;
}

public String getArtifact() {
return artifact;
}

public String getVersion() {
return version;
}

public Node getNode() {
return node;
}

public String getId() {
return String.format("%s:%s", group, artifact);
}

@Override
public String toString() {
return "Dependency{" +
"group='" + group + '\'' +
", artifact='" + artifact + '\'' +
", version='" + version + '\'' +
'}';
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Dependency that = (Dependency) o;
return group.equals(that.group) &&
artifact.equals(that.artifact) &&
version.equals(that.version) &&
node.equals(that.node);
}

@Override
public int hashCode() {
return Objects.hash(group, artifact, version, node);
}
}
115 changes: 113 additions & 2 deletions tools/src/main/java/org/infinispan/tools/ToolUtils.java
@@ -1,9 +1,16 @@
package org.infinispan.tools;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
Expand All @@ -13,19 +20,23 @@
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
* @author Tristan Tarrant &lt;tristan@infinispan.org&gt;
* @since 10.0
**/
public class ToolUtils {

public static final String EMPTY = "";

public static String getBaseFileName(String absoluteFileName) {
int slash = absoluteFileName.lastIndexOf(File.separatorChar);
int dot = absoluteFileName.lastIndexOf('.');
return absoluteFileName.substring(slash + 1, dot);
}

public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
public static void printDocument(Document doc, OutputStream out) throws TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
Expand All @@ -35,6 +46,106 @@ public static void printDocument(Document doc, OutputStream out) throws IOExcept
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

transformer.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
new StreamResult(new OutputStreamWriter(out, StandardCharsets.UTF_8)));
}

/**
* Given a parent {@link Node}, it search all the children and returns the first one to match the {@code tagName}.
*
* @param parent The parent {@link Node}.
* @param tagName The tag name to search for.
* @return The {@link Node} of the first child with {@code tagName} or {@code null} if it does not exist.
*/
public static Optional<Node> findFirstChildByTagName(Node parent, String tagName) {
for (Node child = parent.getFirstChild(); child != null; ) {
if (tagName.equals(child.getLocalName())) {
return Optional.of(child);
}
child = child.getNextSibling();
}
return Optional.empty();
}

/**
* Similar to {@link #findFirstChildByTagName(Node, String)} but it uses a {@code fullPath} to search the first child
* that matches it.
*
* @param parent The parent {@link Node}.
* @param fullPath The path where to search for the child.
* @return The {@link Optional} with the {@link Node} instance if found. Otherwise, an empty {@link Optional}.
*/
public static Optional<Node> findFirstChildByPath(Node parent, String fullPath) {
String[] paths = fullPath.split("/", 2);
for (Node child = parent.getFirstChild(); child != null; ) {
if (paths[0].equals(child.getLocalName())) {
return paths.length == 2 ?
findFirstChildByPath(child, paths[1]) :
Optional.of(child);
}
child = child.getNextSibling();
}
return Optional.empty();
}

/**
* Parses the "licenses.xml" files generated by the Wildfly licenses-plugin (maven projects) or license-reporter
* (nodejs projects).
*
* @param document The {@link Document} to parse.
* @return A {@link List} with all the {@link Dependency} found.
*/
public static List<Dependency> parseXMLDependencies(Document document) {
List<Dependency> dependencyList = new LinkedList<>();
Node dependencies = document.getElementsByTagName("dependencies").item(0);
for (Node dependency = dependencies.getFirstChild(); dependency != null; ) {
if ("dependency".equals(dependency.getLocalName())) {

Optional<Node> groupIdNode = findFirstChildByTagName(dependency, "groupId");
if (!groupIdNode.isPresent()) {
groupIdNode = findFirstChildByTagName(dependency, "packageName");
}
//groupId/packageName must be present all the time
//noinspection OptionalGetWithoutIsPresent
String groupId = groupIdNode.map(ToolUtils::textFromNode).get();
String artifactId = findFirstChildByTagName(dependency, "artifactId")
.map(ToolUtils::textFromNode)
.orElse(EMPTY);
String version = findFirstChildByTagName(dependency, "version")
.map(ToolUtils::textFromNode)
.orElse(EMPTY);
// Only include artifact if not in inclusive mode or if it's one of the included jars
dependencyList.add(new Dependency(groupId, artifactId, version, dependency));
}
dependency = dependency.getNextSibling();
}
return dependencyList;
}

/**
* Trims all the empty lines from a file.
*
* @param file The {@link File} to trim.
* @throws IOException If an i/o error occurs.
*/
public static void removeEmptyLinesFromFile(File file) throws IOException {
//it assumes a small file!
List<String> lines = Files.lines(file.toPath())
.filter(s -> !s.trim().isEmpty())
.collect(Collectors.toList());
try (FileWriter writer = new FileWriter(file)) {
for (String line : lines) {
writer.write(line);
writer.write(System.lineSeparator());
}
}
}

/**
* @return the text context trimmed of {@link Node}
*/
public static String textFromNode(Node node) {
assert node != null;
return node.getTextContent().trim();
}

}
Expand Up @@ -2,7 +2,6 @@

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
Expand All @@ -18,6 +17,7 @@
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerException;

import org.infinispan.tools.Dependency;
import org.infinispan.tools.ToolUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
Expand Down Expand Up @@ -83,19 +83,9 @@ else if (filename.endsWith(".xml"))
throw new IllegalArgumentException(filename);
}

Node findFirstChildByTagName(Node parent, String tagName) {
for(Node child = parent.getFirstChild(); child != null; ) {
if (tagName.equals(child.getLocalName())) {
return child;
}
child = child.getNextSibling();
}
return null;
}

public void write(boolean inclusiveMode, OutputStream os) throws IOException, TransformerException {
public void write(boolean inclusiveMode, OutputStream os) throws TransformerException {
if (verbose) {
System.out.printf("Inclusive mode %s\n", Boolean.toString(inclusiveMode));
System.out.printf("Inclusive mode %s\n", inclusiveMode);
}
Document aggregated = docBuilder.newDocument();
Element aggregatedDependencies = (Element) aggregated
Expand All @@ -106,20 +96,10 @@ public void write(boolean inclusiveMode, OutputStream os) throws IOException, Tr
for (Map.Entry<String, Document> l : xmls.entrySet()) {
Document doc = l.getValue();
if (doc == emptyDocument) continue;
Node dependencies = doc.getElementsByTagName("dependencies").item(0);
for(Node dependency = dependencies.getFirstChild(); dependency != null; ) {
if ("dependency".equals(dependency.getLocalName())) {
String groupId = findFirstChildByTagName(dependency, "groupId").getTextContent().trim();
String artifactId = findFirstChildByTagName(dependency, "artifactId").getTextContent().trim();
String version = findFirstChildByTagName(dependency, "version").getTextContent().trim();
// Only include artifact if not in inclusive mode or if it's one of the included jars
if (!inclusiveMode || xmls.containsKey(String.format("%s-%s", artifactId, version))) {
String artifact = String.format("%s:%s", groupId, artifactId);
final Node dep = dependency;
artifacts.computeIfAbsent(artifact, a -> aggregated.adoptNode(dep.cloneNode(true)));
}
for (Dependency dep : ToolUtils.parseXMLDependencies(doc)) {
if (!inclusiveMode || xmls.containsKey(String.format("%s-%s", dep.getArtifact(), dep.getVersion()))) {
artifacts.computeIfAbsent(dep.getId(), a -> aggregated.adoptNode(dep.getNode().cloneNode(true)));
}
dependency = dependency.getNextSibling();
}
}
artifacts.entrySet().stream()
Expand All @@ -129,7 +109,7 @@ public void write(boolean inclusiveMode, OutputStream os) throws IOException, Tr

}

public static void main(String argv[]) throws Exception {
public static void main(String[] argv) throws Exception {
LicenseMerger licenseMerger = new LicenseMerger();
File outputFile = new File(System.getProperty("user.dir"), "licenses.xml");
boolean inclusiveMode = false;
Expand Down Expand Up @@ -165,5 +145,6 @@ public static void main(String argv[]) throws Exception {
System.out.printf("Wrote merged licenses to %s\n", outputFile);
}
}
ToolUtils.removeEmptyLinesFromFile(outputFile);
}
}

0 comments on commit 14fc7a9

Please sign in to comment.