Fixed issues with copyright (Now following USC 17.4)
This commit is contained in:
parent
116ee8d1ea
commit
439016cb6b
23
LICENSE
23
LICENSE
|
@ -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
21
LICENSE.MIT
Normal 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.
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ->
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue
Block a user