diff options
author | Xavier Ducrohet <xav@google.com> | 2015-06-29 21:59:14 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2015-06-29 21:59:14 +0000 |
commit | f4f48f30bbf591ac5e07512afefbbaa359c7d239 (patch) | |
tree | 8e07fa1fd2248af98f804c66370a92f1f476edee | |
parent | a490a82d7ab101a1b12acbba82382d264ca4ba3b (diff) | |
parent | 562c750628953150ea1e42b3304be420f0903394 (diff) | |
download | buildSrc-f4f48f30bbf591ac5e07512afefbbaa359c7d239.tar.gz |
License report plugin. automerge: 8882b6c automerge: 96b6b5a
automerge: 562c750
* commit '562c750628953150ea1e42b3304be420f0903394':
License report plugin.
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 |