Fixed issues with copyright (Now following USC 17.4)

This commit is contained in:
nathan 2020-08-06 23:59:26 +02:00
parent 116ee8d1ea
commit 439016cb6b
9 changed files with 207 additions and 186 deletions

23
LICENSE
View File

@ -1,4 +1,25 @@
- Licensing - License definitions and legal management plugin for the Gradle build system
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Licensing
Copyright 2020 - The Apache Software License, Version 2.0
Copyright 2020
Dorkbox LLC
Extra license information
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- Version - Java Semantic Versioning with exceptions. Minor/Patch number optional and build-after-final-dot (minor/patch) permitted.
[MIT License]
https://git.dorkbox.com/dorkbox/Version
Copyright 2020
Dorkbox LLC
G. Richard Bellamy
Kenduck
Larry Bordowitz <lbordowitz@yahoo-inc.com>
Martin Rüegg <martin.rueegg@bristolpound.org> <martin.rueegg@metaworx.ch>
Zafar Khaja <zafarkhaja@gmail.com>

21
LICENSE.MIT Normal file
View File

@ -0,0 +1,21 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -16,13 +16,18 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.time.Instant
gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS // always show the stacktrace!
gradle.startParameter.warningMode = WarningMode.All
plugins {
java
`java-gradle-plugin`
id("com.gradle.plugin-publish") version "0.12.0"
id("com.dorkbox.VersionUpdate") version "1.7"
id("com.dorkbox.Licensing") version "2.1"
id("com.dorkbox.VersionUpdate") version "1.8"
id("com.dorkbox.GradleUtils") version "1.8"
kotlin("jvm") version "1.3.72"
@ -33,7 +38,7 @@ object Extras {
// set for the project
const val description = "License definitions and legal management plugin for the Gradle build system"
const val group = "com.dorkbox"
const val version = "2.0"
const val version = "2.1"
// set as project.ext
const val name = "Gradle Licensing Plugin"
@ -53,6 +58,15 @@ object Extras {
GradleUtils.load("$projectDir/../../gradle.properties", Extras)
GradleUtils.fixIntellijPaths()
licensing {
license(License.APACHE_2) {
description(Extras.description)
author(Extras.vendor)
url(Extras.url)
}
}
sourceSets {
main {
java {
@ -83,7 +97,7 @@ dependencies {
// the kotlin version is taken from the plugin, so it is not necessary to set it here
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin")
implementation("com.dorkbox:Version:1.2")
implementation("com.dorkbox:Version:2.4")
}
java {

View File

@ -43,7 +43,6 @@ object AppLicensing {
private val map = listOf(
LicenseChain("org.jetbrains.kotlin",
LicenseData("Kotlin", License.APACHE_2).apply {
copyright(2000)
author("JetBrains s.r.o. and Kotlin Programming Language contributors")
url("https://github.com/JetBrains/kotlin")
note("Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply")
@ -54,7 +53,6 @@ object AppLicensing {
LicenseData("Java Annotations", License.APACHE_2).apply {
description("Annotations for JVM-based languages")
url("https://github.com/JetBrains/java-annotations")
copyright(2000)
author("JetBrains s.r.o.")
}
),
@ -62,7 +60,6 @@ object AppLicensing {
LicenseData("kotlinx.coroutines", License.APACHE_2).apply {
description("Library support for Kotlin coroutines with multiplatform support")
url("https://github.com/Kotlin/kotlinx.coroutines")
copyright(2000)
author("JetBrains s.r.o.")
}
),
@ -70,7 +67,6 @@ object AppLicensing {
LicenseData("kotlin-logging", License.APACHE_2).apply {
description("Lightweight logging framework for Kotlin")
url("https://github.com/MicroUtils/kotlin-logging")
copyright(2016)
author("Ohad Shai")
}
),
@ -78,7 +74,6 @@ object AppLicensing {
LicenseData("SLF4J", License.MIT).apply {
description("Simple facade or abstraction for various logging frameworks")
url("http://www.slf4j.org")
copyright(2004)
author("QOS.ch")
}
),
@ -86,7 +81,6 @@ object AppLicensing {
LicenseData("JNA", License.LGPLv2_1).apply {
description("Simplified native library access for Java.")
url("https://github.com/twall/jna")
copyright(2004)
author("Timothy Wall")
}
),
@ -94,7 +88,6 @@ object AppLicensing {
LicenseData("JNA", License.APACHE_2).apply {
description("Simplified native library access for Java.")
url("https://github.com/twall/jna")
copyright(2013)
author("Timothy Wall")
}
),
@ -103,7 +96,6 @@ object AppLicensing {
LicenseData("JNA-Platform", License.LGPLv2_1).apply {
description("Mappings for a number of commonly used platform functions")
url("https://github.com/twall/jna")
copyright(2013)
author("Timothy Wall")
}
),
@ -111,7 +103,6 @@ object AppLicensing {
LicenseData("JNA-Platform", License.APACHE_2).apply {
description("Mappings for a number of commonly used platform functions")
url("https://github.com/twall/jna")
copyright(2013)
author("Timothy Wall")
}
),
@ -120,29 +111,24 @@ object AppLicensing {
LicenseData("SSHJ", License.APACHE_2).apply {
description("SSHv2 library for Java")
url("https://github.com/hierynomus/sshj")
copyright(2009)
author("Jeroen van Erp")
author("SSHJ Contributors")
extra("Apache MINA", License.APACHE_2) {
it.url("https://mina.apache.org/sshd-project/")
it.copyright(2003).to(2017)
it.author("The Apache Software Foundation")
}
extra("Apache Commons-Net", License.APACHE_2) {
it.url("https://commons.apache.org/proper/commons-net/")
it.copyright(2001).to(2017)
it.author("The Apache Software Foundation")
}
extra("JZlib", License.APACHE_2) {
it.url("http://www.jcraft.com/jzlib")
it.copyright(2002).to(2008)
it.author("Atsuhiko Yamanaka")
it.author("JCraft, Inc.")
}
extra("Bouncy Castle Crypto", License.APACHE_2) {
it.url("http://www.bouncycastle.org")
it.copyright(2000).to(2006)
it.author("The Legion of the Bouncy Castle Inc")
}
extra("ed25519-java", License.CC0) {
@ -155,7 +141,6 @@ object AppLicensing {
LicenseChain("org.bouncycastle",
LicenseData("Bouncy Castle Crypto", License.APACHE_2).apply {
description("Lightweight cryptography API and JCE Extension")
copyright(2000)
author("The Legion of the Bouncy Castle Inc")
url("http://www.bouncycastle.org")
}
@ -164,7 +149,6 @@ object AppLicensing {
LicenseChain("com.fasterxml.uuid:java-uuid-generator",
LicenseData("Java Uuid Generator", License.APACHE_2).apply {
description("A set of Java classes for working with UUIDs")
copyright(2002)
author("Tatu Saloranta (tatu.saloranta@iki.fi)")
author("Contributors. See source release-notes/CREDITS")
url("https://github.com/cowtowncoder/java-uuid-generator")
@ -181,7 +165,6 @@ object AppLicensing {
LicenseChain("io.netty",
LicenseData("Netty", License.APACHE_2).apply {
description("An event-driven asynchronous network application framework")
copyright(2014)
author("The Netty Project")
author("Contributors. See source NOTICE")
url("https://netty.io")
@ -190,7 +173,6 @@ object AppLicensing {
LicenseChain("org.lwjgl:lwjgl-xxhash",
LicenseData("Lightweight Java Game Library", License.BSD_3).apply {
description("Java library that enables cross-platform access to popular native APIs")
copyright(2012)
author("Lightweight Java Game Library")
url("https://github.com/LWJGL/lwjgl3")
}
@ -199,7 +181,6 @@ object AppLicensing {
LicenseChain("com.github.ben-manes:gradle-versions-plugin",
LicenseData("Gradle Versions Plugin", License.APACHE_2).apply {
description("This plugin provides a task to determine which dependencies have updates")
copyright(2012)
author("Ben Manes")
url("https://github.com/ben-manes/gradle-versions-plugin")
}
@ -208,7 +189,6 @@ object AppLicensing {
LicenseChain("org.json:json",
LicenseData("JSON in Java", License.JSON).apply {
description("A light-weight language independent data interchange format.")
copyright(2002)
author("JSON.org")
url("https://github.com/stleary/JSON-java")
url("https://www.json.org/json-en.html")
@ -218,7 +198,6 @@ object AppLicensing {
LicenseChain("net.jodah:typetools",
LicenseData("TypeTools", License.APACHE_2).apply {
description("A simple, zero-dependency library for working with types. Supports Java 1.6+ and Android.")
copyright(2010)
author("Jonathan Halterman and friends")
url("https://github.com/jhalterman/typetools")
}

View File

@ -40,17 +40,16 @@ class DependencyScanner(private val project: Project, private val extension: Lic
}
val missingLicenseInfo = mutableListOf<Dependency>()
val actuallyMissingLicenseInfo = mutableListOf<Dependency>()
val missingLicenseInfo = mutableSetOf<Dependency>()
val actuallyMissingLicenseInfo = mutableSetOf<Dependency>()
if (extension.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)
println("\tLicense Detection")
print("\t\tScanning for preloaded license data...")
println("\t\tScanning for preloaded license data...")
val primaryLicense = extension.licenses.first()
var found = false
// scan to see if we have in our predefined section
projectDependencies.forEach { info: Dependency ->
val license: LicenseData? = try {
AppLicensing.getLicense(info.mavenId())
@ -64,6 +63,8 @@ class DependencyScanner(private val project: Project, private val extension: Lic
missingLicenseInfo.add(info)
} else {
if (!primaryLicense.extras.contains(license)) {
println("\t\t\t${info.mavenId()}")
// get the OLDEST date from the artifacts and use that as the copyright date
var oldestDate = 0L
info.artifacts.forEach { artifact ->
@ -77,35 +78,22 @@ class DependencyScanner(private val project: Project, private val extension: Lic
oldestDate = Instant.now().toEpochMilli()
}
// as per US Code Title 17, Chapter 4; for "visually perceptive copies" (which includes software).
// http://www.copyright.gov/title17/92chap4.html
// it is ONLY... © year name
val year = Date(oldestDate).toInstant().atZone(ZoneId.systemDefault()).toLocalDate().year
if (license.copyrights.size == 1) {
if (year > license.copyrights.first()) {
// only do this if we have copyright greater than our specified (it can be the SAME, so don't want to do this!)
try {
CopyrightRange(license, license.copyrights.first(), license.copyrights).to(year)
} catch (e: GradleException) {
throw GradleException("Error assigning internal copyright for ${info.mavenId()}", e)
}
}
} else {
license.copyright(year)
}
license.copyright = year
primaryLicense.extras.add(license)
}
}
}
if (found) {
found = false
println(" found")
} else {
println()
}
print("\t\tScanning for embedded license data...")
println("\t\tScanning for embedded license data...")
// now scan to see if the jar has a license blob in it
if (missingLicenseInfo.isNotEmpty()) {
missingLicenseInfo.forEach { info ->
// see if we have it in the dependency jar
@ -114,12 +102,12 @@ class DependencyScanner(private val project: Project, private val extension: Lic
info.artifacts.forEach search@{ artifact ->
ZipFile(artifact.file).use {
try {
// read the license blob information
val ze = it.getEntry(LicenseInjector.LICENSE_BLOB)
if (ze != null) {
it.getInputStream(ze).use { licenseStream ->
licenseStream.copyTo(output)
missingFound = true
found = true
return@search
}
}
@ -132,7 +120,7 @@ class DependencyScanner(private val project: Project, private val extension: Lic
if (!missingFound) {
actuallyMissingLicenseInfo.add(info)
} else {
// println("Found license info in: $info")
println("\t\t\t$info")
try {
ObjectInputStream(ByteArrayInputStream(output.toByteArray())).use { ois ->
@ -141,7 +129,11 @@ class DependencyScanner(private val project: Project, private val extension: Lic
val license = LicenseData("", License.CUSTOM)
license.readObject(ois)
// println("Adding license: $license")
// as per US Code Title 17, Chapter 4; for "visually perceptive copies" (which includes software).
// http://www.copyright.gov/title17/92chap4.html
// it is ONLY... © year name
//
// this is correctly saved in the license blob
if (!primaryLicense.extras.contains(license)) {
primaryLicense.extras.add(license)
}
@ -154,23 +146,23 @@ class DependencyScanner(private val project: Project, private val extension: Lic
}
}
if (found) {
found = false
println(" found")
} else {
println()
}
if (actuallyMissingLicenseInfo.isNotEmpty()) {
println("\t\tLicense information is missing for the following. Please submit an issue with this information to include it in future license scans\n")
println("\t\tLicense information is missing for the following. Please submit an issue with this information to include it in future license scans")
actuallyMissingLicenseInfo.forEach { missingDep ->
val flatDependencies = mutableSetOf<Dependency>()
missingDep.children.forEach {
flattenDep(it, flatDependencies)
}
println("\t\t ${missingDep.mavenId()} ${flatDependencies.map { it.mavenId() }}")
val flat = flatDependencies.map { it.mavenId() }
val extras = if (flat.isEmpty()) {
""
} else {
flat.toString()
}
println("\t\t ${missingDep.mavenId()} $extras")
}
}
}

View File

@ -38,17 +38,33 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
}
/**
* Copyright
* The Berne Convention leaves "implementation details" up to individual countries.
*
* In the US (which is the relevant country for FSF documents), copyright notices are defined by Title 17, Chapter 4;
* for "visually perceptive copies" (which includes software). http://www.copyright.gov/title17/92chap4.html
*
* These take the form :
*
* © year name
*
* where
*
* `©` is specifically that symbol (not "(c)", which has no legal value), and can be replaced by "Copyright" or "Copr." (§ 401(b)(1))
*
* `year` is the year of first publication of the work, or the year of first publication of the compilation or derivative work if relevant
*
* `name` is the name of the owner of the copyright.
*
* What counts is years of publication; for software this is generally considered years in which the software is released.
*
* So if you release a piece of software in 2014, and release it again in 2016 without making changes in 2015, the years of publication
* would be 2014 and 2016, and the copyright notices would be "© 2014" in the first release and "© 2016" in the second release.
*
*
*
* When scanning for license copyright dates, we use the date of publication (the date of the manifest file, within the published jar)
*/
val copyrights = mutableListOf<Int>()
/**
* If not specified, will use the current year
*/
fun copyright(copyright: Int = LocalDate.now().year): CopyrightRange {
copyrights.add(copyright)
return CopyrightRange(this, copyright, copyrights)
}
var copyright = LocalDate.now().year
/**
* URL
@ -129,7 +145,7 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
if (name != other.name) return false
if (license != other.license) return false
if (description != other.description) return false
if (copyrights != other.copyrights) return false
if (copyright != other.copyright) return false
if (urls != other.urls) return false
if (notes != other.notes) return false
if (authors != other.authors) return false
@ -142,7 +158,7 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
var result = name.hashCode()
result = 31 * result + license.hashCode()
result = 31 * result + description.hashCode()
result = 31 * result + copyrights.hashCode()
result = 31 * result + copyright
result = 31 * result + urls.hashCode()
result = 31 * result + notes.hashCode()
result = 31 * result + authors.hashCode()
@ -156,10 +172,7 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
s.writeUTF(license.name)
s.writeUTF(description)
s.writeInt(copyrights.size)
copyrights.forEach {
s.writeInt(it)
}
s.writeInt(copyright)
s.writeInt(urls.size)
urls.forEach {
@ -184,18 +197,14 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
}
}
// Gradle only needs to serialize objects, so this isn't strictly needed
// this is used to load license data from supported dependencies
@Throws(IOException::class)
fun readObject(s: ObjectInputStream) {
name = s.readUTF()
license = License.valueOfLicenseName(s.readUTF())
description = s.readUTF()
val copyrightsSize = s.readInt()
for (i in 1..copyrightsSize) {
copyrights.add(s.readInt())
}
copyright = s.readInt()
val urlsSize = s.readInt()
for (i in 1..urlsSize) {
@ -225,10 +234,9 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
// NOTE: we ALWAYS use unix line endings!
private const val NL = "\n"
private const val HEADER = " - "
private const val HEADR4 = " ---- "
private const val HEADER1 = " - "
private const val HEADER4 = " ---- "
private const val SPACER3 = " "
private const val SPACER4 = " "
private fun prefix(prefix: Int, builder: StringBuilder): StringBuilder {
if (prefix == 0) {
@ -279,43 +287,25 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
// NOTE: we ALWAYS use unix line endings!
private fun buildLicenseString(b: StringBuilder, license: LicenseData, prefixOffset: Int) {
line(prefixOffset, b, HEADER, license.name, " - ", license.description)
line(prefixOffset, b, HEADER1, license.name, " - ", license.description)
line(prefixOffset, b, SPACER3, "[", license.license.preferedName, "]")
license.urls.forEach {
line(prefixOffset, b, SPACER3, it)
}
prefix(prefixOffset, b).append(SPACER3).append("Copyright")
if (license.copyrights.isEmpty()) {
// append the current year
b.append(" ").append(LocalDate.now().year)
}
else if (license.copyrights.size == 1) {
// this is 2001
b.append(" ").append(license.copyrights.first())
} else {
// is this 2001,2002,2004,2014 <OR> 2001-2014
val sumA = license.copyrights.sum()
val sumB = license.copyrights.first().rangeTo(license.copyrights.last()).sum()
if (sumA == sumB) {
// this is 2001-2004
b.append(" ").append(license.copyrights.first()).append("-").append(license.copyrights.last())
} else {
// this is 2001,2002,2004
license.copyrights.forEach {
b.append(" ").append(it).append(",")
}
b.deleteCharAt(b.length-1)
}
}
b.append(HEADER).append(license.license.preferedName).append(NL)
// as per US Code Title 17, Chapter 4; for "visually perceptive copies" (which includes software).
// http://www.copyright.gov/title17/92chap4.html
// it is ONLY... © year name (or Copyright year name)
// authors go on a separate line
line(prefixOffset, b, SPACER3, "Copyright ", license.copyright)
license.authors.forEach {
line(prefixOffset, b, SPACER4, it)
line(prefixOffset, b, SPACER3, " ", it)
}
if (license.license === License.CUSTOM) {
line(prefixOffset, b, HEADR4)
line(prefixOffset, b, HEADER4)
}
license.notes.forEach {
@ -371,26 +361,3 @@ class LicenseData(var name: String, var license: License) : java.io.Serializable
}
}
}
class CopyrightRange internal constructor(private val license: LicenseData,
private val start: Int,
private val copyrights: MutableList<Int>) {
fun to(copyRight: Int) {
if (start >= copyRight) {
throw GradleException("Cannot have a start copyright date that is equal or greater than the `to` copyright date for ${license.name}")
}
val newStart = start+1
if (newStart < copyRight) {
// increment by 1, since the first part of the range is already added
copyrights.addAll((newStart).rangeTo(copyRight))
}
}
fun toNow() {
val nowYear = LocalDate.now().year
if (start < nowYear) {
to(nowYear)
}
}
}

View File

@ -2,40 +2,49 @@ package dorkbox.license
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.tasks.*
import java.io.File
import java.io.FileOutputStream
import java.io.ObjectOutputStream
import java.util.*
import javax.inject.Inject
internal open class LicenseInjector @Inject constructor(@Internal val extension: Licensing) : DefaultTask() {
// only want to build these files once
private var alreadyBuilt = false
internal open class LicenseInjector @Inject constructor(project: Project, @Internal val extension: Licensing) : DefaultTask() {
companion object {
const val LICENSE_FILE = "LICENSE"
const val LICENSE_BLOB = "LICENSE.blob"
}
@Input lateinit var licenses: MutableList<LicenseData>
@OutputDirectory lateinit var outputDir: File
@InputDirectory lateinit var rootDir: File
@Input val licenses = extension.licenses
@Internal private val outputBuildDir = File(project.buildDir, "licensing")
@OutputFiles val outputFiles = mutableListOf<File>()
init {
/// outputBuildDir
outputFiles.add(File(outputBuildDir, LICENSE_FILE))
outputFiles.add(File(outputBuildDir, LICENSE_BLOB))
licenses.forEach {
outputFiles.add(File(outputBuildDir, it.license.licenseFile))
}
/// root dir
outputFiles.add(File(project.rootDir, LICENSE_FILE))
outputFiles.add(File(project.rootDir, LICENSE_BLOB))
licenses.forEach {
outputFiles.add(File(project.rootDir, it.license.licenseFile))
}
outputs.upToDateWhen {
alreadyBuilt || !(checkLicenseFiles(outputDir, licenses) && checkLicenseFiles(rootDir, licenses))
!(checkLicenseFiles(outputBuildDir, licenses) && checkLicenseFiles(project.rootDir, licenses))
}
}
@TaskAction
fun doTask() {
if (alreadyBuilt) {
return
}
alreadyBuilt = true
// 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.
@ -44,14 +53,13 @@ internal open class LicenseInjector @Inject constructor(@Internal val extension:
DependencyScanner(project, extension).scanForLicenseData()
// true if there was any work done
didWork = buildLicenseFiles(outputDir, licenses) && buildLicenseFiles(rootDir, licenses)
didWork = buildLicenseFiles(outputBuildDir, licenses, true) && buildLicenseFiles(project.rootDir, licenses, false)
}
/**
* @return true when there is work that needs to be done
*/
private fun checkLicenseFiles(outputDir: File, licenses: MutableList<LicenseData>): Boolean {
var needsToDoWork = false
if (!outputDir.exists()) outputDir.mkdirs()
val licenseText = LicenseData.buildString(licenses)
@ -59,29 +67,26 @@ internal open class LicenseInjector @Inject constructor(@Internal val extension:
if (fileIsNotSame(licenseFile, licenseText)) {
// write out the LICENSE and various license files
needsToDoWork = true
return true
}
if (!needsToDoWork) {
licenses.forEach {
val license = it.license
val file = File(outputDir, license.licenseFile)
val sourceText = license.licenseText
licenses.forEach {
val license = it.license
val file = File(outputDir, license.licenseFile)
val sourceText = license.licenseText
if (fileIsNotSame(file, sourceText)) {
needsToDoWork = true
}
if (fileIsNotSame(file, sourceText)) {
return true
}
}
return needsToDoWork
return false
}
/**
* @return true when there is work that has be done
*/
private fun buildLicenseFiles(outputDir: File, licenses: MutableList<LicenseData>): Boolean {
private fun buildLicenseFiles(outputDir: File, licenses: MutableList<LicenseData>, buildLicenseBlob: Boolean): Boolean {
var hasDoneWork = false
if (!outputDir.exists()) outputDir.mkdirs()
@ -97,20 +102,36 @@ internal open class LicenseInjector @Inject constructor(@Internal val extension:
// write out the LICENSE files
licenseFile.writeText(licenseText)
// save off the blob, so we can check when reading dependencies if we can
// import this license info as extra license info for the project
ObjectOutputStream(FileOutputStream(licenseBlob)).use { oos ->
oos.writeInt(licenses.size)
if (buildLicenseBlob) {
// save off the blob, so we can check when reading dependencies if we can
// import this license info as extra license info for the project
ObjectOutputStream(FileOutputStream(licenseBlob)).use { oos ->
oos.writeInt(licenses.size)
licenses.forEach {
it.writeObject(oos)
licenses.forEach {
it.writeObject(oos)
}
}
}
hasDoneWork = true
}
licenses.forEach {
// for the license files, we have to FLATTEN the list of licenses!
val flattenedLicenses = mutableSetOf<LicenseData>()
val scanningLicenses: LinkedList<LicenseData> = LinkedList<LicenseData>()
scanningLicenses.addAll(licenses)
while(scanningLicenses.isNotEmpty()) {
val license = scanningLicenses.remove()
val wasAdded = flattenedLicenses.add(license)
if (wasAdded) {
// should always be added, but MAYBE there is a loop somewhere. this hopefully prevents that
scanningLicenses.addAll(license.extras)
}
}
flattenedLicenses.forEach {
val license = it.license
val file = File(outputDir, license.licenseFile)
val sourceText = license.licenseText

View File

@ -19,6 +19,7 @@ import License
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.plugins.JavaPlugin
@ -41,21 +42,14 @@ import java.util.zip.ZipInputStream
class LicensePlugin : Plugin<Project> {
override fun apply(project: Project) {
val outputDir = File(project.buildDir, "licensing")
// Create the Plugin extension object (for users to configure our execution).
val extension: Licensing = project.extensions.create(Licensing.NAME, Licensing::class.java, project, outputDir)
val extension: Licensing = project.extensions.create(Licensing.NAME, Licensing::class.java, project)
val licenseInjector = project.tasks.create("generateLicenseFiles", LicenseInjector::class.java, extension).apply {
val licenseInjector = project.tasks.create("generateLicenseFiles", LicenseInjector::class.java, project, extension).apply {
group = "other"
}
licenseInjector.outputDir = outputDir
licenseInjector.rootDir = project.rootDir
licenseInjector.licenses = extension.licenses
project.afterEvaluate { prj ->
// the task will only build files that it needs to (and will only run once)
prj.tasks.forEach {
when (it) {
@ -64,6 +58,16 @@ class LicensePlugin : Plugin<Project> {
}
}
// Make sure to cleanup the generated license files on clean
project.tasks.getByName("clean").apply {
// delete the license info
extension.output().forEach {
if (it.exists()) {
it.delete()
}
}
}
prj.configurations.asIterable().forEach { extension.projectDependencies.addAll(it.dependencies) }
val licensing = extension.licenses
@ -82,7 +86,7 @@ class LicensePlugin : Plugin<Project> {
if (MavenPublication::class.java.isAssignableFrom(it.javaClass)) {
it as MavenPublication
// add the license information. ONLY THE FIRST ONE!
// get the license information. ONLY FROM THE FIRST ONE! (which is the license for our project)
val licenseData = extension.licenses.first()
val license = licenseData.license
it.pom.licenses { licSpec ->

View File

@ -21,7 +21,7 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import java.io.File
open class Licensing(project: Project, private val outputDir: File) {
open class Licensing(private val project: Project) {
private val projectName = project.name
val projectDependencies = mutableListOf<Dependency>()
@ -32,13 +32,15 @@ open class Licensing(project: Project, private val outputDir: File) {
* Gets a list of files, representing the on-disk location of each generated license file
*/
fun output() : List<File> {
val outputBuilDir = File(project.buildDir, "licensing")
val files = mutableSetOf<File>()
files.add(File(outputDir, LicenseInjector.LICENSE_FILE))
files.add(File(outputDir, LicenseInjector.LICENSE_BLOB))
files.add(File(outputBuilDir, LicenseInjector.LICENSE_FILE))
files.add(File(outputBuilDir, LicenseInjector.LICENSE_BLOB))
licenses.forEach {
files.add(File(outputDir, it.license.licenseFile))
files.add(File(outputBuilDir, it.license.licenseFile))
}
return files.toList()