aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@google.com>2015-06-29 21:59:14 +0000
committerandroid-build-merger <android-build-merger@google.com>2015-06-29 21:59:14 +0000
commitf4f48f30bbf591ac5e07512afefbbaa359c7d239 (patch)
tree8e07fa1fd2248af98f804c66370a92f1f476edee
parenta490a82d7ab101a1b12acbba82382d264ca4ba3b (diff)
parent562c750628953150ea1e42b3304be420f0903394 (diff)
downloadbuildSrc-f4f48f30bbf591ac5e07512afefbbaa359c7d239.tar.gz
License report plugin. automerge: 8882b6c automerge: 96b6b5a
automerge: 562c750 * commit '562c750628953150ea1e42b3304be420f0903394': License report plugin.
-rw-r--r--src/main/groovy/com/android/tools/internal/license/LicenseReportPlugin.java31
-rw-r--r--src/main/groovy/com/android/tools/internal/license/ReportTask.java201
-rw-r--r--src/main/java/com/android/tools/internal/artifacts/PomHandler.java83
-rw-r--r--src/main/resources/META-INF/gradle-plugins/license-report.properties1
4 files changed, 315 insertions, 1 deletions
diff --git a/src/main/groovy/com/android/tools/internal/license/LicenseReportPlugin.java b/src/main/groovy/com/android/tools/internal/license/LicenseReportPlugin.java
new file mode 100644
index 0000000..9244e8b
--- /dev/null
+++ b/src/main/groovy/com/android/tools/internal/license/LicenseReportPlugin.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tools.internal.license;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+
+/**
+ * Plugin setting up the licenseReport task.
+ */
+public class LicenseReportPlugin implements Plugin<Project> {
+ @Override
+ public void apply(Project project) {
+
+ ReportTask licenseReport = project.getTasks().create("licenseReport", ReportTask.class);
+ licenseReport.dependsOn(project.getConfigurations().getByName("runtime"));
+ }
+}
diff --git a/src/main/groovy/com/android/tools/internal/license/ReportTask.java b/src/main/groovy/com/android/tools/internal/license/ReportTask.java
new file mode 100644
index 0000000..8964c2f
--- /dev/null
+++ b/src/main/groovy/com/android/tools/internal/license/ReportTask.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tools.internal.license;
+
+import com.android.tools.internal.artifacts.PomHandler;
+import com.android.tools.internal.artifacts.PomHandler.License;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.ResolvedArtifact;
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
+import org.gradle.api.artifacts.result.DependencyResult;
+import org.gradle.api.artifacts.result.ResolvedComponentResult;
+import org.gradle.api.artifacts.result.ResolvedDependencyResult;
+import org.gradle.api.tasks.TaskAction;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Tasks outputting the license information for the external dependencies.
+ *
+ * It queries the 'runtime' configuration object, and fails if it doesn't find pom
+ * file associated with the dependencies.
+ *
+ * This will NOT work with local jars.
+ */
+public class ReportTask extends DefaultTask {
+
+ @TaskAction
+ public void report() throws IOException {
+ Project project = getProject();
+
+ Configuration runtimeConfig = project.getConfigurations().getByName("runtime");
+
+ Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts = collectArtifacts(runtimeConfig);
+
+ Set<? extends DependencyResult> dependencyResultSet = runtimeConfig
+ .getIncoming().getResolutionResult().getRoot().getDependencies();
+
+ Set<File> pomFiles = new HashSet<File>();
+
+ for (DependencyResult dependencyResult : dependencyResultSet) {
+ if (dependencyResult instanceof ResolvedDependencyResult) {
+ processConfig(
+ ((ResolvedDependencyResult) dependencyResult).getSelected(),
+ artifacts,
+ pomFiles);
+ }
+ }
+
+ for (File pomFile : pomFiles) {
+ PomHandler pomHandler = new PomHandler(pomFile);
+
+ ModuleVersionIdentifier artifactName = pomHandler.getArtifactName();
+ System.out.println(artifactName);
+
+ List<License> licenses = pomHandler.getLicenses();
+
+
+ File parentPomFile = pomFile;
+ PomHandler parentPomHandler = pomHandler;
+ while (licenses.isEmpty()) {
+ // get the parent pom
+ parentPomFile = computeParentPomLocation(parentPomFile, parentPomHandler);
+ parentPomHandler = new PomHandler(parentPomFile);
+ licenses = parentPomHandler.getLicenses();
+ }
+
+ if (!licenses.isEmpty()) {
+ for (License license : licenses) {
+ System.out.println(" > " + license.getName());
+ if (license.getUrl() != null) {
+ System.out.println(" " + license.getUrl());
+ }
+ if (license.getComments() != null) {
+ System.out.println(" " + license.getComments());
+ }
+ }
+ } else {
+ throw new RuntimeException("unable to find license info for " + artifactName);
+ }
+ }
+ }
+
+ private static File computeParentPomLocation(File pomFile, PomHandler pomHandler) throws IOException {
+ // To find the location of the parentPom, we can rely on the following location pattern for pom files:
+ // groupIdSeg1/groupIdSeg2/.../name/version/name-version.pom
+ // So first we back track from the current pom to find the root of the repo
+
+ // first remove the pom file, the version and the name:
+ File parentPomFile = pomFile.getParentFile().getParentFile().getParentFile();
+
+ // now get the number of groupId segment
+ Iterable<String> segments = Splitter.on('.').split(pomHandler.getArtifactName().getGroup());
+ //noinspection unused
+ for (String segment : segments) {
+ parentPomFile = parentPomFile.getParentFile();
+ }
+
+ // now get the parent pom coordinate
+ ModuleVersionIdentifier parentPomCoord = pomHandler.getParentPom();
+
+ // add the segments
+ segments = Splitter.on('.').split(parentPomCoord.getGroup());
+ for (String segment : segments) {
+ parentPomFile = new File(parentPomFile, segment);
+ }
+
+ // add the name, version
+ String name = parentPomCoord.getName();
+ parentPomFile = new File(parentPomFile, name);
+ String version = parentPomCoord.getVersion();
+ parentPomFile = new File(parentPomFile, version);
+
+ // add the pom filename
+ parentPomFile = new File(parentPomFile, name + "-" + version + ".pom");
+ return parentPomFile;
+ }
+
+ private static Map<ModuleVersionIdentifier, List<ResolvedArtifact>> collectArtifacts(Configuration configuration) {
+ Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts = new HashMap<ModuleVersionIdentifier, List<ResolvedArtifact>>();
+
+ Set<ResolvedArtifact> allArtifacts = configuration.getResolvedConfiguration().getResolvedArtifacts();
+
+ for (ResolvedArtifact artifact : allArtifacts) {
+ ModuleVersionIdentifier id = artifact.getModuleVersion().getId();
+ List<ResolvedArtifact> moduleArtifacts = artifacts.get(id);
+
+ if (moduleArtifacts == null) {
+ moduleArtifacts = Lists.newArrayList();
+ artifacts.put(id, moduleArtifacts);
+ }
+
+ if (!moduleArtifacts.contains(artifact)) {
+ moduleArtifacts.add(artifact);
+ }
+ }
+
+ return artifacts;
+ }
+
+ private static void processConfig(
+ ResolvedComponentResult resolvedComponentResult,
+ Map<ModuleVersionIdentifier, List<ResolvedArtifact>> artifacts,
+ Set<File> pomFiles) {
+
+ ModuleVersionIdentifier moduleVersion = resolvedComponentResult.getModuleVersion();
+
+ ComponentIdentifier id = resolvedComponentResult.getId();
+ if (!(id instanceof ProjectComponentIdentifier)) {
+
+ List<ResolvedArtifact> moduleArtifacts = artifacts.get(moduleVersion);
+
+ if (moduleArtifacts != null) {
+ for (ResolvedArtifact artifact : moduleArtifacts) {
+ File artifactFile = artifact.getFile();
+ String filename = artifactFile.getName().replaceAll(".jar$", ".pom").replaceAll(".aar$", ".pom");
+
+ // rename the file to get the pom.
+ File pomFile = new File(artifactFile.getParentFile(), filename);
+
+ if (!pomFile.exists()) {
+ throw new RuntimeException("Missing Pom file for artifact: " + artifactFile);
+ }
+
+ pomFiles.add(pomFile);
+ }
+ }
+ }
+
+ // then recursively
+ Set<? extends DependencyResult> dependencies = resolvedComponentResult.getDependencies();
+ for (DependencyResult dependencyResult : dependencies) {
+ if (dependencyResult instanceof ResolvedDependencyResult) {
+ processConfig(
+ ((ResolvedDependencyResult) dependencyResult).getSelected(),
+ artifacts,
+ pomFiles);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/internal/artifacts/PomHandler.java b/src/main/java/com/android/tools/internal/artifacts/PomHandler.java
index c0df733..74cd322 100644
--- a/src/main/java/com/android/tools/internal/artifacts/PomHandler.java
+++ b/src/main/java/com/android/tools/internal/artifacts/PomHandler.java
@@ -32,6 +32,9 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* Class able to parse a POM file, and provide some information from it:
@@ -83,10 +86,51 @@ public class PomHandler {
}
}
+ public static class License {
+ private final String name;
+ private final String url;
+ private final String comments;
+
+ public License(String name, String url, String comments) {
+ this.name = name;
+ this.url = url;
+ this.comments = comments;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public String getComments() {
+ return comments;
+ }
+ }
+
public PomHandler(File pomFile) {
this.pomFile = pomFile;
}
+ public ModuleVersionIdentifier getArtifactName() throws IOException {
+ Document document = getDocument();
+ Node rootNode = document.getDocumentElement();
+
+ ModuleVersionIdentifier version = readArtifactAddress(rootNode);
+ if (version.getGroup() == null || version.getVersion() == null) {
+ ModuleVersionIdentifier parentVersion = getParentPom();
+
+ return new FakeModuleVersionIdentifier(
+ version.getGroup() != null ? version.getGroup() : parentVersion.getGroup(),
+ version.getName(),
+ version.getVersion() != null ? version.getVersion() : parentVersion.getVersion());
+ }
+
+ return version;
+ }
+
ModuleVersionIdentifier getRelocation() throws IOException {
Document document = getDocument();
Node rootNode = document.getDocumentElement();
@@ -163,7 +207,6 @@ public class PomHandler {
public String getPackaging() throws IOException {
Document document = getDocument();
-
Node rootNode = document.getDocumentElement();
Node node = findNode(rootNode, "packaging");
@@ -174,6 +217,44 @@ public class PomHandler {
return getTextNode(node);
}
+ public List<License> getLicenses() throws IOException {
+ Document document = getDocument();
+ Node rootNode = document.getDocumentElement();
+
+ Node licensesNode = findNode(rootNode, "licenses");
+ if (licensesNode == null) {
+ return Collections.emptyList();
+ }
+
+ NodeList licenseNodes = licensesNode.getChildNodes();
+
+ List<License> list = new ArrayList<License>();
+
+ for (int i = 0, n = licenseNodes.getLength(); i < n; i++) {
+ Node licenseNode = licenseNodes.item(i);
+
+ if (licenseNode.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ if ("license".equals(licenseNode.getLocalName())) {
+ final Node name = findNode(licenseNode, "name");
+ final Node url = findNode(licenseNode, "url");
+ final Node comments = findNode(licenseNode, "comments");
+
+ String nameValue = name != null ? getTextNode(name) : null;
+ String urlValue = url != null ? getTextNode(url) : null;
+ String commentsValue = comments != null ? getTextNode(comments) : null;
+
+ if (nameValue != null) {
+ list.add(new License(nameValue, urlValue, commentsValue));
+ }
+ }
+ }
+
+ return list;
+ }
+
private Document getDocument() throws IOException {
if (document == null) {
document = parseDocument(pomFile);
diff --git a/src/main/resources/META-INF/gradle-plugins/license-report.properties b/src/main/resources/META-INF/gradle-plugins/license-report.properties
new file mode 100644
index 0000000..7502090
--- /dev/null
+++ b/src/main/resources/META-INF/gradle-plugins/license-report.properties
@@ -0,0 +1 @@
+implementation-class=com.android.tools.internal.license.LicenseReportPlugin