Add the ability to include extra notices in a plugin's NOTICES file (#23898)

Adds the option for a plugin to specify extra directories containing notices
and licenses files to be incorporated into the overall notices file that is
generated for the plugin.

This can be useful, for example, where the plugin has a non-Java dependency
that itself incorporates many 3rd party components.
This commit is contained in:
David Roberts 2017-04-10 12:37:42 +01:00 committed by GitHub
parent 2c545c064d
commit 37aadb2adf
3 changed files with 36 additions and 17 deletions

View File

@ -37,16 +37,21 @@ public class NoticeTask extends DefaultTask {
@OutputFile
File outputFile = new File(project.buildDir, "notices/${name}/NOTICE.txt")
/** Configurations to inspect dependencies*/
private List<Project> dependencies = new ArrayList<>()
/** Directories to include notices from */
private List<File> licensesDirs = new ArrayList<>()
public NoticeTask() {
description = 'Create a notice file from dependencies'
// Default licenses directory is ${projectDir}/licenses (if it exists)
File licensesDir = new File(project.projectDir, 'licenses')
if (licensesDir.exists()) {
licensesDirs.add(licensesDir)
}
}
/** Add notices from licenses found in the given project. */
public void dependencies(Project project) {
dependencies.add(project)
/** Add notices from the specified directory. */
public void licensesDir(File licensesDir) {
licensesDirs.add(licensesDir)
}
@TaskAction
@ -54,17 +59,29 @@ public class NoticeTask extends DefaultTask {
StringBuilder output = new StringBuilder()
output.append(inputFile.getText('UTF-8'))
output.append('\n\n')
Set<String> seen = new HashSet<>()
for (Project dep : dependencies) {
File licensesDir = new File(dep.projectDir, 'licenses')
if (licensesDir.exists() == false) continue
licensesDir.eachFileMatch({ it ==~ /.*-NOTICE\.txt/ && seen.contains(it) == false}) { File file ->
// This is a map rather than a set so that the sort order is the 3rd
// party component names, unaffected by the full path to the various files
Map<String, File> seen = new TreeMap<>()
for (File licensesDir : licensesDirs) {
licensesDir.eachFileMatch({ it ==~ /.*-NOTICE\.txt/ }) { File file ->
String name = file.name.substring(0, file.name.length() - '-NOTICE.txt'.length())
appendFile(file, name, 'NOTICE', output)
appendFile(new File(file.parentFile, "${name}-LICENSE.txt"), name, 'LICENSE', output)
seen.add(file.name)
if (seen.containsKey(name)) {
File prevFile = seen.get(name)
if (prevFile.text != file.text) {
throw new RuntimeException("Two different notices exist for dependency '" +
name + "': " + prevFile + " and " + file)
}
} else {
seen.put(name, file)
}
}
}
for (Map.Entry<String, File> entry : seen.entrySet()) {
String name = entry.getKey()
File file = entry.getValue()
appendFile(file, name, 'NOTICE', output)
appendFile(new File(file.parentFile, "${name}-LICENSE.txt"), name, 'LICENSE', output)
}
outputFile.setText(output.toString(), 'UTF-8')
}

View File

@ -260,7 +260,6 @@ public class PluginBuildPlugin extends BuildPlugin {
File noticeFile = project.pluginProperties.extension.noticeFile
if (noticeFile != null) {
NoticeTask generateNotice = project.tasks.create('generateNotice', NoticeTask.class)
generateNotice.dependencies(project)
generateNotice.inputFile = noticeFile
project.bundlePlugin.from(generateNotice)
}

View File

@ -49,12 +49,12 @@ Collection distributions = project.subprojects.findAll {
// integ test zip only uses core, so a different notice file is needed there
task buildCoreNotice(type: NoticeTask) {
dependencies project(':core')
licensesDir new File(project(':core').projectDir, 'licenses')
}
// other distributions include notices from modules as well, which are added below later
task buildFullNotice(type: NoticeTask) {
dependencies project(':core')
licensesDir new File(project(':core').projectDir, 'licenses')
}
/*****************************************************************************
@ -73,7 +73,10 @@ ext.restTestExpansions = [
// loop over modules to also setup cross task dependencies and increment our modules counter
project.rootProject.subprojects.findAll { it.path.startsWith(':modules:') }.each { Project module ->
buildFullNotice {
dependencies module
def defaultLicensesDir = new File(module.projectDir, 'licenses')
if (defaultLicensesDir.exists()) {
licensesDir defaultLicensesDir
}
}
buildModules {
dependsOn({ project(module.path).bundlePlugin })