Suppress missing license information for sub-projects in a multi-project build.
This commit is contained in:
parent
b2bb05e6cc
commit
5d7e14d380
|
@ -15,9 +15,10 @@ object LicenseDependencyScanner {
|
||||||
// scans and loads license data into the extension
|
// scans and loads license data into the extension
|
||||||
// - from jars on runtime/compile classpath
|
// - from jars on runtime/compile classpath
|
||||||
|
|
||||||
|
data class ScanDep(val project: Project, val preloadedText: MutableList<String>, val embeddedText: MutableList<String>, val missingText: MutableList<String>)
|
||||||
|
|
||||||
// THIS MUST BE IN "afterEvaluate" or run from a specific task.
|
// THIS MUST BE IN "afterEvaluate" or run from a specific task.
|
||||||
fun scanForLicenseData(project: Project, allProjects: Boolean,
|
fun scanForLicenseData(project: Project, allProjects: Boolean, licenses: MutableList<LicenseData>): ScanDep {
|
||||||
licenses: MutableList<LicenseData>): Triple<MutableList<String>, MutableList<String>, MutableList<String>> {
|
|
||||||
|
|
||||||
val preloadedText = mutableListOf<String>();
|
val preloadedText = mutableListOf<String>();
|
||||||
val embeddedText = mutableListOf<String>();
|
val embeddedText = mutableListOf<String>();
|
||||||
|
@ -25,7 +26,7 @@ object LicenseDependencyScanner {
|
||||||
|
|
||||||
|
|
||||||
// NOTE: there will be some duplicates, so we want to remove them
|
// NOTE: there will be some duplicates, so we want to remove them
|
||||||
val dependencies = mutableSetOf<Dependency>()
|
val dependencies = mutableSetOf<ProjAndDependency>()
|
||||||
|
|
||||||
if (allProjects) {
|
if (allProjects) {
|
||||||
project.allprojects.forEach { proj ->
|
project.allprojects.forEach { proj ->
|
||||||
|
@ -39,36 +40,46 @@ object LicenseDependencyScanner {
|
||||||
dependencies.addAll(scan(project, "runtimeClasspath"))
|
dependencies.addAll(scan(project, "runtimeClasspath"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this will contain duplicates if sub-projects ALSO have the same deps
|
||||||
val projectDependencies = dependencies.toList()
|
val projectDependencies = dependencies.toList()
|
||||||
|
|
||||||
val missingLicenseInfo = mutableSetOf<Dependency>()
|
val missingLicenseInfo = mutableSetOf<ProjAndDependency>()
|
||||||
val actuallyMissingLicenseInfo = mutableSetOf<Dependency>()
|
val actuallyMissingLicenseInfo = mutableSetOf<ProjAndDependency>()
|
||||||
|
|
||||||
|
val alreadyScanDeps = mutableSetOf<Dependency>()
|
||||||
|
|
||||||
if (licenses.isNotEmpty()) {
|
if (licenses.isNotEmpty()) {
|
||||||
// when we scan, we ONLY want to scan a SINGLE LAYER (if we have license info for module ID, then we don't need license info for it's children)
|
// when we scan, we ONLY want to scan a SINGLE LAYER (if we have license info for module ID, then we don't need license info for it's children)
|
||||||
val primaryLicense = licenses.first()
|
val primaryLicense = licenses.first()
|
||||||
|
|
||||||
// scan to see if we have in our predefined section
|
// scan to see if we have in our predefined section
|
||||||
projectDependencies.forEach { info: Dependency ->
|
projectDependencies.forEach { projAndDep: ProjAndDependency ->
|
||||||
|
val dep = projAndDep.dep
|
||||||
|
if (alreadyScanDeps.contains(dep)) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
val data: LicenseData? = try {
|
val data: LicenseData? = try {
|
||||||
AppLicensing.getLicense(info.mavenId())
|
AppLicensing.getLicense(dep.mavenId())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("\tError getting license information for ${info.mavenId()}")
|
println("\tError getting license information for ${dep.mavenId()}")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
missingLicenseInfo.add(info)
|
missingLicenseInfo.add(projAndDep)
|
||||||
} else {
|
} else {
|
||||||
if (!primaryLicense.extras.contains(data)) {
|
if (!primaryLicense.extras.contains(data)) {
|
||||||
preloadedText.add("\t\t${info.mavenId()} [${data.license}]")
|
alreadyScanDeps.add(dep)
|
||||||
|
|
||||||
|
preloadedText.add("\t\t${dep.mavenId()} [${data.license}]")
|
||||||
|
|
||||||
// NOTE: the END copyright for these are determined by the DATE of the files!
|
// NOTE: the END copyright for these are determined by the DATE of the files!
|
||||||
// Some dates are WRONG (because the jar build is mucked with), so we manually fix it
|
// Some dates are WRONG (because the jar build is mucked with), so we manually fix it
|
||||||
if (data.copyright == 0) {
|
if (data.copyright == 0) {
|
||||||
// get the OLDEST date from the artifacts and use that as the copyright date
|
// get the OLDEST date from the artifacts and use that as the copyright date
|
||||||
var oldestDate = 0L
|
var oldestDate = 0L
|
||||||
info.artifacts.forEach { artifact ->
|
dep.artifacts.forEach { artifact ->
|
||||||
// get the date of the manifest file (which is the first entry)
|
// get the date of the manifest file (which is the first entry)
|
||||||
ZipInputStream(FileInputStream(artifact.file)).use {
|
ZipInputStream(FileInputStream(artifact.file)).use {
|
||||||
oldestDate = oldestDate.coerceAtLeast(it.nextEntry.lastModifiedTime.toMillis())
|
oldestDate = oldestDate.coerceAtLeast(it.nextEntry.lastModifiedTime.toMillis())
|
||||||
|
@ -96,10 +107,15 @@ object LicenseDependencyScanner {
|
||||||
|
|
||||||
// now scan to see if the jar has a license blob in it
|
// now scan to see if the jar has a license blob in it
|
||||||
if (missingLicenseInfo.isNotEmpty()) {
|
if (missingLicenseInfo.isNotEmpty()) {
|
||||||
missingLicenseInfo.forEach { info ->
|
missingLicenseInfo.forEach { projAndDep: ProjAndDependency ->
|
||||||
|
val dep = projAndDep.dep
|
||||||
|
if (alreadyScanDeps.contains(dep)) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
// see if we have it in the dependency jar
|
// see if we have it in the dependency jar
|
||||||
var licenseData: License? = null
|
var licenseData: License? = null
|
||||||
info.artifacts.forEach search@{ artifact ->
|
dep.artifacts.forEach search@{ artifact ->
|
||||||
val file = artifact.file
|
val file = artifact.file
|
||||||
try {
|
try {
|
||||||
if (file.canRead()) {
|
if (file.canRead()) {
|
||||||
|
@ -125,7 +141,7 @@ object LicenseDependencyScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("\t$info [ERROR $file], ${e.message ?: e.javaClass}")
|
println("\t$dep [ERROR $file], ${e.message ?: e.javaClass}")
|
||||||
}
|
}
|
||||||
|
|
||||||
return@search
|
return@search
|
||||||
|
@ -134,27 +150,48 @@ object LicenseDependencyScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("\t$info [ERROR $file], ${e.message ?: e.javaClass}")
|
println("\t$dep [ERROR $file], ${e.message ?: e.javaClass}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (licenseData != null) {
|
if (licenseData != null) {
|
||||||
embeddedText.add("\t\t$info [$licenseData]")
|
alreadyScanDeps.add(dep)
|
||||||
|
embeddedText.add("\t\t$dep [$licenseData]")
|
||||||
} else {
|
} else {
|
||||||
actuallyMissingLicenseInfo.add(info)
|
actuallyMissingLicenseInfo.add(projAndDep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actuallyMissingLicenseInfo.isNotEmpty()) {
|
if (actuallyMissingLicenseInfo.isNotEmpty()) {
|
||||||
actuallyMissingLicenseInfo.forEach { missingDep ->
|
// we have to prune sub-project data first...
|
||||||
missingText.add("\t ${missingDep.mavenId()}")
|
val projectMavenIds = mutableSetOf<String>()
|
||||||
|
project.allprojects.forEach {
|
||||||
|
projectMavenIds.add("${it.group}:${it.name}:${it.version}")
|
||||||
|
}
|
||||||
|
|
||||||
|
actuallyMissingLicenseInfo.forEach { missingDepAndProj ->
|
||||||
|
// we DO NOT want to show missing deps for project sub-projects.
|
||||||
|
val proj = missingDepAndProj.project
|
||||||
|
val dep = missingDepAndProj.dep
|
||||||
|
|
||||||
|
if (alreadyScanDeps.contains(dep)) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
alreadyScanDeps.add(dep)
|
||||||
|
|
||||||
|
val mavenId = dep.mavenId()
|
||||||
|
|
||||||
|
// if the missing dep IS ALSO the same as a subproject .... we don't want to report it
|
||||||
|
if (!projectMavenIds.contains(mavenId)) {
|
||||||
|
missingText.add("\t ${dep.mavenId()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Triple(preloadedText, embeddedText, missingText)
|
return ScanDep(project, preloadedText, embeddedText, missingText)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,9 +204,9 @@ object LicenseDependencyScanner {
|
||||||
*
|
*
|
||||||
* This is an actual problem...
|
* This is an actual problem...
|
||||||
*/
|
*/
|
||||||
private fun scan(project: Project, configurationName: String): List<Dependency> {
|
private fun scan(project: Project, configurationName: String): List<ProjAndDependency> {
|
||||||
|
|
||||||
val projectDependencies = mutableListOf<Dependency>()
|
val projectDependencies = mutableListOf<ProjAndDependency>()
|
||||||
val config = project.configurations.getByName(configurationName)
|
val config = project.configurations.getByName(configurationName)
|
||||||
if (!config.isCanBeResolved) {
|
if (!config.isCanBeResolved) {
|
||||||
return projectDependencies
|
return projectDependencies
|
||||||
|
@ -204,16 +241,19 @@ object LicenseDependencyScanner {
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
listOf()
|
listOf()
|
||||||
}
|
}
|
||||||
projectDependencies.add(Dependency(group, name, version, artifacts))
|
projectDependencies.add(ProjAndDependency(project, Dependency(group, name, version, artifacts)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectDependencies
|
return projectDependencies
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class Dependency(val group: String,
|
internal data class ProjAndDependency(val project: Project, val dep: Dependency)
|
||||||
val name: String,
|
|
||||||
val version: String,
|
internal data class Dependency(
|
||||||
val artifacts: List<Artifact>) {
|
val group: String,
|
||||||
|
val name: String,
|
||||||
|
val version: String,
|
||||||
|
val artifacts: List<Artifact>) {
|
||||||
|
|
||||||
fun mavenId(): String {
|
fun mavenId(): String {
|
||||||
return "$group:$name:$version"
|
return "$group:$name:$version"
|
||||||
|
|
|
@ -36,7 +36,7 @@ internal open class LicenseInjector @Inject constructor(@Internal val extension:
|
||||||
// This MUST be first, since it loads license data that is used elsewhere
|
// This MUST be first, since it loads license data that is used elsewhere
|
||||||
// show scanning or missing, but not both
|
// show scanning or missing, but not both
|
||||||
// NOTE: we scan the dependencies in ALL subprojects as well.
|
// NOTE: we scan the dependencies in ALL subprojects as well.
|
||||||
val (preloadedText, embeddedText, missingText) = extension.scanDependencies(project, true)
|
val (proj, preloadedText, embeddedText, missingText) = extension.scanDependencies(project, true)
|
||||||
|
|
||||||
// validate the license text configuration section in the gradle file ONLY WHEN PUSHING A JAR
|
// validate the license text configuration section in the gradle file ONLY WHEN PUSHING A JAR
|
||||||
val licensing = extension.licenses
|
val licensing = extension.licenses
|
||||||
|
|
|
@ -53,7 +53,3 @@ class LicensePlugin : Plugin<Project> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -181,14 +181,16 @@ open class Licensing(private val project: Project) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// scan as part of the plugin
|
// scan as part of the plugin
|
||||||
fun scanDependencies(project: Project, allProjects: Boolean): Triple<MutableList<String>, MutableList<String>, MutableList<String>> {
|
fun scanDependencies(project: Project, allProjects: Boolean): LicenseDependencyScanner.ScanDep {
|
||||||
// now we want to add license information that we know about from our dependencies to our list
|
// now we want to add license information that we know about from our dependencies to our list
|
||||||
// just to make it clear, license information CAN CHANGE BETWEEN VERSIONS! For example, JNA changed from GPL to Apache in version 4+
|
// just to make it clear, license information CAN CHANGE BETWEEN VERSIONS! For example, JNA changed from GPL to Apache in version 4+
|
||||||
// we associate the artifact group + id + (start) version as a license.
|
// we associate the artifact group + id + (start) version as a license.
|
||||||
// if a license for a dependency is UNKNOWN, then we emit a warning to the user to add it as a pull request
|
// if a license for a dependency is UNKNOWN, then we emit a warning to the user to add it as a pull request
|
||||||
// if a license version is not specified, then we use the default
|
// if a license version is not specified, then we use the default
|
||||||
val textOutput = LicenseDependencyScanner.scanForLicenseData(project, allProjects, this.licenses)
|
val depInfo = LicenseDependencyScanner.scanForLicenseData(project, allProjects, this.licenses)
|
||||||
|
|
||||||
|
|
||||||
// we only should include the kotlin license information IF we actually use kotlin.
|
// we only should include the kotlin license information IF we actually use kotlin.
|
||||||
|
@ -211,7 +213,7 @@ open class Licensing(private val project: Project) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return textOutput
|
return depInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue