Skip to content

license-gather-plugin: Fixed MANIFEST check is always skipped #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ Change log
v1.78
* chore: bump Gradle 6.7 -> 6.9.1
* license-gather: ignore xml namespaces when parsing POM files (see #43)
* license-gather: fix license inference from Bundle-License manifest attribute (see #48)

Thanks to [Florian Dreier](https://github.com/DreierF) for identifying bugs and suggesting fixes.

v1.77
* crlf-plugin: bump jgit to 5.13.0.202109080827-r
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,16 @@ open class EnumGeneratorTask @Inject constructor(objectFactory: ObjectFactory) :
.initializer("values().associateBy { it.id }")
.build()
)
.addProperty(
PropertySpec.builder(
"uriToInstance",
Map::class.asClassName()
.parameterizedBy(URI::class.asClassName(), className),
KModifier.PRIVATE
)
.initializer("values().flatMap { e -> (e.uri + e.detailsUri).map { it to e } }.toMap()")
.build()
)
.addFunction(
FunSpec.builder("fromId")
.addParameter("id", String::class)
Expand All @@ -159,6 +169,30 @@ open class EnumGeneratorTask @Inject constructor(objectFactory: ObjectFactory) :
.addStatement("return idToInstance[id]")
.build()
)
.addFunction(
FunSpec.builder("fromUri")
.addParameter("uri", URI::class)
.addStatement(
"return fromUriOrNull(uri) ?: throw %T(%P)",
NoSuchElementException::class,
"No license found for given URI: \$uri"
)
.build()
)
.addFunction(
FunSpec.builder("fromUriOrNull")
.addParameter("uri", URI::class)
.addStatement("return uriToInstance[uri.toHttps()]")
.build()
)
.addFunction(
FunSpec.builder("toHttps")
.addModifiers(KModifier.PRIVATE)
.receiver(URI::class)
.returns(URI::class)
.addStatement("return if (!toString().startsWith(\"http://\")) this else URI(toString().replaceFirst(\"http:\", \"https:\"))")
.build()
)
.build()
)
.addProperty(
Expand All @@ -179,10 +213,21 @@ open class EnumGeneratorTask @Inject constructor(objectFactory: ObjectFactory) :
TypeSpec.anonymousClassBuilder()
.addSuperclassConstructorParameter("%S", it.id)
.addSuperclassConstructorParameter("%S", it.name)
.addSuperclassConstructorParameter("%S", it.detailsUrl)
.addSuperclassConstructorParameter("arrayOf(%L)",
it.seeAlso.map { url -> CodeBlock.of("%S", url.trim()) }
.joinToCode(", "))
.addSuperclassConstructorParameter(
"%S",
it.detailsUrl.replaceFirst("http://", "https://")
)
.addSuperclassConstructorParameter(
"arrayOf(%L)",
it.seeAlso
.map { url ->
CodeBlock.of(
"%S",
url.trim().replaceFirst("http://", "https://")
)
}
.joinToCode(", ")
)
.build()
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import com.github.vlsi.gradle.license.api.JustLicense
import com.github.vlsi.gradle.license.api.License
import com.github.vlsi.gradle.license.api.LicenseExpression
import com.github.vlsi.gradle.license.api.LicenseExpressionParser
import com.github.vlsi.gradle.license.api.OsgiBundleLicenseParser
import com.github.vlsi.gradle.license.api.ParseException
import com.github.vlsi.gradle.license.api.SpdxLicense
import com.github.vlsi.gradle.license.api.asExpression
import com.github.vlsi.gradle.license.api.text
Expand Down Expand Up @@ -471,6 +473,9 @@ open class GatherLicenseTask @Inject constructor(
detectedLicenses: MutableMap<ComponentIdentifier, LicenseInfo>,
licenseExpressionParser: LicenseExpressionParser
) {
val bundleLicenseParser = OsgiBundleLicenseParser(licenseExpressionParser) {
SpdxLicense.fromUriOrNull(it)?.asExpression()
}
for (e in detectedLicenses) {
if (e.value.license != null) {
continue
Expand All @@ -484,7 +489,7 @@ open class GatherLicenseTask @Inject constructor(
)
continue
}
if (!file.endsWith(".jar")) {
if (file.extension != "jar") {
Comment on lines -487 to +492
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice catch. It might be worth filing an IDEA ticket to https://youtrack.jetbrains.com

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logger.debug(
"File {} for artifact {} does not look like a JAR. Will skip MANIFEST.MF check",
file,
Expand All @@ -500,10 +505,8 @@ open class GatherLicenseTask @Inject constructor(
)
JarFile(file).use { jar ->
val bundleLicense = jar.manifest.mainAttributes.getValue("Bundle-License")
val license = bundleLicense?.substringBefore(";")?.let {
licenseExpressionParser.parse(it)
}
if (license != null) {
?: return@use
bundleLicenseParser.parseOrNull(bundleLicense, file)?.let { license ->
logger.debug("Detected license for ${e.key}: $license")
e.setValue(e.value.copy(license = license))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2019 Vladimir Sitnikov <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.github.vlsi.gradle.license.api

import org.slf4j.LoggerFactory
import java.net.URI
import java.net.URISyntaxException

class OsgiBundleLicenseParser(
private val licenseExpressionParser: LicenseExpressionParser,
private val lookupLicenseByUri: (URI) -> LicenseExpression?
) {
private val logger = LoggerFactory.getLogger(OsgiBundleLicenseParser::class.java)

fun parseOrNull(bundleLicense: String, context: Any): LicenseExpression? {
return if (bundleLicense.contains(',')) {
logger.info(
"Ignoring Bundle-License '{}' in {} since it contains multiple license references",
bundleLicense,
context
)
null
} else if (bundleLicense.startsWith("http")) {
// Infer license from the URI
val uri = try {
URI(bundleLicense)
} catch (e: URISyntaxException) {
logger.info(
"Invalid URI for license in Bundle-License value '{}' in {}",
bundleLicense,
context,
e
)
return null
}
lookupLicenseByUri(uri)
} else {
// Infer license from "SPDX-Expression; licenseURI"
// We ignore URI as the expression should be more important
bundleLicense.substringBefore(";").let {
try {
licenseExpressionParser.parse(it)
} catch (e: ParseException) {
logger.info(
"Unable to parse Bundle-License value '{}' in {}",
bundleLicense,
context,
e
)
null
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2019 Vladimir Sitnikov <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.github.vlsi.gradle.license

import com.github.vlsi.gradle.license.api.LicenseExpressionParser
import com.github.vlsi.gradle.license.api.OsgiBundleLicenseParser
import com.github.vlsi.gradle.license.api.SpdxLicense
import com.github.vlsi.gradle.license.api.asExpression
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource

class OsgiBundleLicenseParserTest {
@ParameterizedTest
@CsvSource(
"license from https uri^Apache-2.0^https://www.apache.org/licenses/LICENSE-2.0",
"license from http uri^Apache-2.0^http://www.apache.org/licenses/LICENSE-2.0",
"license from https uri^Apache-1.0^https://www.apache.org/licenses/LICENSE-1.0",
"license from SPDX^Apache-2.0^Apache-2.0;https://www.apache.org/licenses/LICENSE-1.0",
"SPDX expression^Apache-1.0 OR Apache-2.0^Apache-2.0 OR Apache-1.0;https://www.apache.org/licenses/LICENSE-1.0",
delimiter = '^'
)
fun success(comment: String, expected: String, input: String) {
val parser = OsgiBundleLicenseParser(LicenseExpressionParser()) {
SpdxLicense.fromUriOrNull(it)?.asExpression()
}
assertEquals(expected, parser.parseOrNull(input, "test input").toString()) {
"$comment, input: $input"
}
}

@ParameterizedTest
@CsvSource(
"unknown uri^https://www.apache.org/licenses/LICENSE-1.2",
"invalid expression^Apache OR;http://www.apache.org/licenses/LICENSE-2.0",
"multiple licenses^license1,license2",
"multiple licenses^Apache-2.0;https://www.apache.org/licenses/LICENSE-2.0,Apache_1.0;https://www.apache.org/licenses/LICENSE-1.0",
delimiter = '^'
)
fun fail(comment: String, input: String) {
val parser = OsgiBundleLicenseParser(LicenseExpressionParser()) {
SpdxLicense.fromUriOrNull(it)?.asExpression()
}
assertNull(parser.parseOrNull(input, "test input")) {
"$comment should cause OsgiBundleLicenseParser.parse failure, input: $input"
}
}
}