From af515d325b7fb2bb25ecc26155554d1915d6939a Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 7 Nov 2022 21:41:50 +0100 Subject: [PATCH] NuGetSupport: Properly split the (technology) namespace from the name Use up to two namespace nodes from the name as defined at [1] as the package namespace. [1]: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-namespaces Signed-off-by: Sebastian Schuberth --- .../kotlin/managers/utils/NuGetSupport.kt | 32 +++++++++++++------ .../kotlin/managers/utils/NuGetSupportTest.kt | 21 +++++++++++- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/analyzer/src/main/kotlin/managers/utils/NuGetSupport.kt b/analyzer/src/main/kotlin/managers/utils/NuGetSupport.kt index 4e08734e11542..6a2b5c2230b9c 100644 --- a/analyzer/src/main/kotlin/managers/utils/NuGetSupport.kt +++ b/analyzer/src/main/kotlin/managers/utils/NuGetSupport.kt @@ -148,8 +148,12 @@ class NuGetSupport(serviceIndexUrls: List = listOf(DEFAULT_SERVICE_INDEX } private fun getAllPackageData(id: Identifier): NuGetAllPackageData { - // Note: The package name in the URL is case-sensitive and must be lower-case! - val lowerId = id.name.lowercase() + // Note: The id in the URL is case-sensitive and must be lower-case! + val lowerId = if (id.namespace.isNotEmpty()) { + "${id.namespace}.${id.name}" + } else { + id.name + }.lowercase() val data = registrationsBaseUrls.firstNotNullOfOrNull { baseUrl -> runCatching { @@ -289,8 +293,12 @@ private fun parseAuthors(spec: PackageSpec?): SortedSet = private fun resolveLocalSpec(definitionFile: File): File? = definitionFile.parentFile?.resolve(".nuspec")?.takeIf { it.isFile } -private fun getIdentifier(name: String, version: String) = - Identifier(type = "NuGet", namespace = "", name = name, version = version) +internal fun getIdentifier(name: String, version: String): Identifier { + val namespace = name.split('.', limit = 3).toMutableList() + val nameWithoutNamespace = namespace.removeLast() + val namespaceWithoutName = namespace.joinToString(".") + return Identifier(type = "NuGet", namespace = namespaceWithoutName, name = nameWithoutNamespace, version = version) +} data class NuGetDependency( val name: String, @@ -357,13 +365,19 @@ private fun PackageManager.getProject( ): Project { val spec = resolveLocalSpec(definitionFile)?.let { NuGetSupport.XML_MAPPER.readValue(it) } - return Project( - id = Identifier( + val id = if (spec != null) { + getIdentifier(spec.metadata.id, spec.metadata.version) + } else { + Identifier( type = managerName, namespace = "", - name = spec?.metadata?.id ?: definitionFile.relativeTo(analysisRoot).invariantSeparatorsPath, - version = spec?.metadata?.version.orEmpty() - ), + name = definitionFile.relativeTo(analysisRoot).invariantSeparatorsPath, + version = "" + ) + } + + return Project( + id = id, definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path, authors = parseAuthors(spec), declaredLicenses = parseLicenses(spec), diff --git a/analyzer/src/test/kotlin/managers/utils/NuGetSupportTest.kt b/analyzer/src/test/kotlin/managers/utils/NuGetSupportTest.kt index 391950843fd10..0232bbf6a85eb 100644 --- a/analyzer/src/test/kotlin/managers/utils/NuGetSupportTest.kt +++ b/analyzer/src/test/kotlin/managers/utils/NuGetSupportTest.kt @@ -19,14 +19,33 @@ package org.ossreviewtoolkit.analyzer.managers.utils +import io.kotest.assertions.assertSoftly import io.kotest.core.spec.style.WordSpec import io.kotest.matchers.collections.containExactly import io.kotest.matchers.should +import io.kotest.matchers.shouldBe import java.io.File +import org.ossreviewtoolkit.model.Identifier + class NuGetSupportTest : WordSpec({ - "getRegistrationsBaseUrls" should { + "getIdentifier()" should { + "split the namespace from the name" { + assertSoftly { + getIdentifier( "SharpCompress", "0.23.0") shouldBe + Identifier("NuGet::SharpCompress:0.23.0") + getIdentifier( "System.IO", "4.1.0") shouldBe + Identifier("NuGet:System:IO:4.1.0") + getIdentifier( "System.IO.Compression", "4.3.0") shouldBe + Identifier("NuGet:System.IO:Compression:4.3.0") + getIdentifier( "System.IO.Compression.ZipFile", "4.0.1") shouldBe + Identifier("NuGet:System.IO:Compression.ZipFile:4.0.1") + } + } + } + + "getRegistrationsBaseUrls()" should { "parse index urls" { val reader = NuGetConfigFileReader() val configFile = File("src/funTest/assets/projects/synthetic/nuget/nuget.config")