From 5d7e14d3809e4ad0ef055eaa6c042893a0a0647b Mon Sep 17 00:00:00 2001 From: Robinson Date: Wed, 16 Nov 2022 01:03:36 +0100 Subject: [PATCH] Suppress missing license information for sub-projects in a multi-project build. --- .../license/LicenseDependencyScanner.kt | 94 +++++++++++++------ src/dorkbox/license/LicenseInjector.kt | 2 +- src/dorkbox/license/LicensePlugin.kt | 4 - src/dorkbox/license/Licensing.kt | 8 +- 4 files changed, 73 insertions(+), 35 deletions(-) diff --git a/src/dorkbox/license/LicenseDependencyScanner.kt b/src/dorkbox/license/LicenseDependencyScanner.kt index 22c6561..516bca6 100644 --- a/src/dorkbox/license/LicenseDependencyScanner.kt +++ b/src/dorkbox/license/LicenseDependencyScanner.kt @@ -15,9 +15,10 @@ object LicenseDependencyScanner { // scans and loads license data into the extension // - from jars on runtime/compile classpath + data class ScanDep(val project: Project, val preloadedText: MutableList, val embeddedText: MutableList, val missingText: MutableList) + // THIS MUST BE IN "afterEvaluate" or run from a specific task. - fun scanForLicenseData(project: Project, allProjects: Boolean, - licenses: MutableList): Triple, MutableList, MutableList> { + fun scanForLicenseData(project: Project, allProjects: Boolean, licenses: MutableList): ScanDep { val preloadedText = mutableListOf(); val embeddedText = mutableListOf(); @@ -25,7 +26,7 @@ object LicenseDependencyScanner { // NOTE: there will be some duplicates, so we want to remove them - val dependencies = mutableSetOf() + val dependencies = mutableSetOf() if (allProjects) { project.allprojects.forEach { proj -> @@ -39,36 +40,46 @@ object LicenseDependencyScanner { dependencies.addAll(scan(project, "runtimeClasspath")) } + // this will contain duplicates if sub-projects ALSO have the same deps val projectDependencies = dependencies.toList() - val missingLicenseInfo = mutableSetOf() - val actuallyMissingLicenseInfo = mutableSetOf() + val missingLicenseInfo = mutableSetOf() + val actuallyMissingLicenseInfo = mutableSetOf() + + val alreadyScanDeps = mutableSetOf() 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) val primaryLicense = licenses.first() // 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 { - AppLicensing.getLicense(info.mavenId()) + AppLicensing.getLicense(dep.mavenId()) } catch (e: Exception) { - println("\tError getting license information for ${info.mavenId()}") + println("\tError getting license information for ${dep.mavenId()}") null } if (data == null) { - missingLicenseInfo.add(info) + missingLicenseInfo.add(projAndDep) } else { 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! // Some dates are WRONG (because the jar build is mucked with), so we manually fix it if (data.copyright == 0) { // get the OLDEST date from the artifacts and use that as the copyright date var oldestDate = 0L - info.artifacts.forEach { artifact -> + dep.artifacts.forEach { artifact -> // get the date of the manifest file (which is the first entry) ZipInputStream(FileInputStream(artifact.file)).use { 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 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 var licenseData: License? = null - info.artifacts.forEach search@{ artifact -> + dep.artifacts.forEach search@{ artifact -> val file = artifact.file try { if (file.canRead()) { @@ -125,7 +141,7 @@ object LicenseDependencyScanner { } } } catch (e: Exception) { - println("\t$info [ERROR $file], ${e.message ?: e.javaClass}") + println("\t$dep [ERROR $file], ${e.message ?: e.javaClass}") } return@search @@ -134,27 +150,48 @@ object LicenseDependencyScanner { } } } catch (e: Exception) { - println("\t$info [ERROR $file], ${e.message ?: e.javaClass}") + println("\t$dep [ERROR $file], ${e.message ?: e.javaClass}") } } if (licenseData != null) { - embeddedText.add("\t\t$info [$licenseData]") + alreadyScanDeps.add(dep) + embeddedText.add("\t\t$dep [$licenseData]") } else { - actuallyMissingLicenseInfo.add(info) + actuallyMissingLicenseInfo.add(projAndDep) } } } if (actuallyMissingLicenseInfo.isNotEmpty()) { - actuallyMissingLicenseInfo.forEach { missingDep -> - missingText.add("\t ${missingDep.mavenId()}") + // we have to prune sub-project data first... + val projectMavenIds = mutableSetOf() + 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... */ - private fun scan(project: Project, configurationName: String): List { + private fun scan(project: Project, configurationName: String): List { - val projectDependencies = mutableListOf() + val projectDependencies = mutableListOf() val config = project.configurations.getByName(configurationName) if (!config.isCanBeResolved) { return projectDependencies @@ -204,16 +241,19 @@ object LicenseDependencyScanner { } catch (e: Exception) { listOf() } - projectDependencies.add(Dependency(group, name, version, artifacts)) + projectDependencies.add(ProjAndDependency(project, Dependency(group, name, version, artifacts))) } return projectDependencies } - internal data class Dependency(val group: String, - val name: String, - val version: String, - val artifacts: List) { + internal data class ProjAndDependency(val project: Project, val dep: Dependency) + + internal data class Dependency( + val group: String, + val name: String, + val version: String, + val artifacts: List) { fun mavenId(): String { return "$group:$name:$version" diff --git a/src/dorkbox/license/LicenseInjector.kt b/src/dorkbox/license/LicenseInjector.kt index d13a62e..218433a 100644 --- a/src/dorkbox/license/LicenseInjector.kt +++ b/src/dorkbox/license/LicenseInjector.kt @@ -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 // show scanning or missing, but not both // 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 val licensing = extension.licenses diff --git a/src/dorkbox/license/LicensePlugin.kt b/src/dorkbox/license/LicensePlugin.kt index e91df26..593a692 100644 --- a/src/dorkbox/license/LicensePlugin.kt +++ b/src/dorkbox/license/LicensePlugin.kt @@ -53,7 +53,3 @@ class LicensePlugin : Plugin { } } } - - - - diff --git a/src/dorkbox/license/Licensing.kt b/src/dorkbox/license/Licensing.kt index a1e39ea..adc0e24 100644 --- a/src/dorkbox/license/Licensing.kt +++ b/src/dorkbox/license/Licensing.kt @@ -181,14 +181,16 @@ open class Licensing(private val project: Project) { } + + // scan as part of the plugin - fun scanDependencies(project: Project, allProjects: Boolean): Triple, MutableList, MutableList> { + 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 // 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. // 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 - 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. @@ -211,7 +213,7 @@ open class Licensing(private val project: Project) { } } - return textOutput + return depInfo } /**