diff --git a/analyzer/src/main/kotlin/managers/GoDep.kt b/analyzer/src/main/kotlin/managers/GoDep.kt index a979637c330db..1575872c68bab 100644 --- a/analyzer/src/main/kotlin/managers/GoDep.kt +++ b/analyzer/src/main/kotlin/managers/GoDep.kt @@ -116,7 +116,7 @@ class GoDep( val projects = parseProjects(workingDir, gopath) val packages = mutableSetOf() - val packageRefs = mutableListOf() + val packageRefs = mutableSetOf() for (project in projects) { // parseProjects() made sure that all entries contain these keys @@ -156,7 +156,7 @@ class GoDep( packageRefs += pkg.toReference(linkage = PackageLinkage.STATIC, issues = issues) } - val scope = Scope("default", packageRefs.toSortedSet()) + val scope = Scope("default", packageRefs) val projectName = runCatching { val uri = URI(projectVcs.url) diff --git a/analyzer/src/main/kotlin/managers/utils/Graph.kt b/analyzer/src/main/kotlin/managers/utils/Graph.kt index ef792224e8fdb..a147c0cc70d21 100644 --- a/analyzer/src/main/kotlin/managers/utils/Graph.kt +++ b/analyzer/src/main/kotlin/managers/utils/Graph.kt @@ -20,7 +20,6 @@ package org.ossreviewtoolkit.analyzer.managers.utils import java.util.LinkedList -import java.util.SortedSet import org.apache.logging.log4j.kotlin.Logging @@ -122,9 +121,9 @@ internal class Graph private constructor(private val nodeMap: MutableMap { + fun toPackageReferenceForest(root: Identifier): Set { fun getPackageReference(id: Identifier): PackageReference { - val dependencies = nodeMap.getValue(id).mapTo(sortedSetOf()) { + val dependencies = nodeMap.getValue(id).mapTo(mutableSetOf()) { getPackageReference(it) } @@ -135,7 +134,7 @@ internal class Graph private constructor(private val nodeMap: MutableMap>, unqualify: Boolean): Set = map.mapTo(mutableSetOf()) { entry -> - val dependencies = entry.value.mapTo(sortedSetOf()) { index -> + val dependencies = entry.value.mapTo(mutableSetOf()) { index -> referenceMapping[index.toKey()] ?: error("Could not resolve dependency index $index.") } @@ -201,7 +201,7 @@ data class DependencyGraph( ): PackageReference { val indexKey = RootDependencyIndex.generateKey(node.pkg, node.fragment) return refMapping.getOrPut(indexKey) { - val refDependencies = dependencies[node].orEmpty().mapTo(sortedSetOf()) { + val refDependencies = dependencies[node].orEmpty().mapTo(mutableSetOf()) { constructReferenceTree(it, refMapping) } diff --git a/model/src/main/kotlin/Package.kt b/model/src/main/kotlin/Package.kt index 60a0585a14e65..f6a4f28ef0d03 100644 --- a/model/src/main/kotlin/Package.kt +++ b/model/src/main/kotlin/Package.kt @@ -22,8 +22,6 @@ package org.ossreviewtoolkit.model import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.annotation.JsonSerialize -import java.util.SortedSet - import org.ossreviewtoolkit.model.utils.toPurl import org.ossreviewtoolkit.utils.common.StringSortedSetConverter import org.ossreviewtoolkit.utils.ort.DeclaredLicenseProcessor @@ -186,7 +184,7 @@ data class Package( */ fun toReference( linkage: PackageLinkage? = null, - dependencies: SortedSet? = null, + dependencies: Set? = null, issues: List? = null ): PackageReference { var ref = PackageReference(id) diff --git a/model/src/main/kotlin/PackageReference.kt b/model/src/main/kotlin/PackageReference.kt index e819acc36c292..a69dd1355f306 100644 --- a/model/src/main/kotlin/PackageReference.kt +++ b/model/src/main/kotlin/PackageReference.kt @@ -20,12 +20,13 @@ package org.ossreviewtoolkit.model import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.annotation.JsonSerialize import java.util.Deque import java.util.LinkedList -import java.util.SortedSet import org.ossreviewtoolkit.model.utils.PackageLinkageValueFilter +import org.ossreviewtoolkit.model.utils.PackageReferenceSortedSetConverter /** * A human-readable reference to a software [Package]. Each package reference itself refers to other package @@ -51,7 +52,8 @@ data class PackageReference( * The set of [references to packages][PackageReference] this package depends on. Note that this list depends on the * [scope][Scope] in which this package is referenced. */ - val dependencies: SortedSet = sortedSetOf(), + @JsonSerialize(converter = PackageReferenceSortedSetConverter::class) + val dependencies: Set = emptySet(), /** * A list of [Issue]s that occurred handling this [PackageReference]. @@ -116,10 +118,10 @@ data class PackageReference( * return the modified [PackageReference]. The tree is traversed depth-first (post-order). */ fun traverse(transform: (PackageReference) -> PackageReference): PackageReference { - val transformedDependencies = dependencies.map { + val transformedDependencies = dependencies.mapTo(mutableSetOf()) { it.traverse(transform) } - return transform(copy(dependencies = transformedDependencies.toSortedSet())) + return transform(copy(dependencies = transformedDependencies)) } override fun visitDependencies(block: (Sequence) -> T): T = block(dependencies.asSequence()) diff --git a/model/src/main/kotlin/Scope.kt b/model/src/main/kotlin/Scope.kt index 666033a40089c..efe2761d13603 100644 --- a/model/src/main/kotlin/Scope.kt +++ b/model/src/main/kotlin/Scope.kt @@ -19,7 +19,9 @@ package org.ossreviewtoolkit.model -import java.util.SortedSet +import com.fasterxml.jackson.databind.annotation.JsonSerialize + +import org.ossreviewtoolkit.model.utils.PackageReferenceSortedSetConverter /** * The scope class puts package dependencies into context. @@ -39,7 +41,8 @@ data class Scope( * dependencies would not be test dependencies of the test dependencies, but compile dependencies of test * dependencies. */ - val dependencies: SortedSet = sortedSetOf() + @JsonSerialize(converter = PackageReferenceSortedSetConverter::class) + val dependencies: Set = emptySet() ) : Comparable { /** * Return the set of package [Identifier]s in this [Scope], up to and including a depth of [maxDepth] where counting diff --git a/model/src/main/kotlin/utils/SortedSetConverters.kt b/model/src/main/kotlin/utils/SortedSetConverters.kt index 75afb66300593..435410de67610 100644 --- a/model/src/main/kotlin/utils/SortedSetConverters.kt +++ b/model/src/main/kotlin/utils/SortedSetConverters.kt @@ -28,6 +28,7 @@ import java.util.SortedSet import org.ossreviewtoolkit.model.CopyrightFinding import org.ossreviewtoolkit.model.LicenseFinding import org.ossreviewtoolkit.model.Package +import org.ossreviewtoolkit.model.PackageReference import org.ossreviewtoolkit.model.Project import org.ossreviewtoolkit.model.Scope @@ -39,6 +40,10 @@ class LicenseFindingSortedSetConverter : StdConverter, Sorte override fun convert(value: Set) = value.toSortedSet(LicenseFinding.COMPARATOR) } +class PackageReferenceSortedSetConverter : StdConverter, SortedSet>() { + override fun convert(value: Set) = value.toSortedSet(compareBy { it.id }) +} + class PackageSortedSetConverter : StdConverter, SortedSet>() { override fun convert(value: Set) = value.toSortedSet(compareBy { it.id }) } diff --git a/model/src/test/kotlin/AbstractDependencyNavigatorTest.kt b/model/src/test/kotlin/AbstractDependencyNavigatorTest.kt index 264956d1978b1..8d7be2b86d978 100644 --- a/model/src/test/kotlin/AbstractDependencyNavigatorTest.kt +++ b/model/src/test/kotlin/AbstractDependencyNavigatorTest.kt @@ -29,7 +29,7 @@ import io.kotest.matchers.collections.haveSize import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder import io.kotest.matchers.maps.containExactly as containExactlyEntries import io.kotest.matchers.sequences.beEmpty as beEmptySequence -import io.kotest.matchers.sequences.containExactly as containSequenceExactly +import io.kotest.matchers.sequences.containAllInAnyOrder import io.kotest.matchers.should import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNot @@ -72,7 +72,9 @@ abstract class AbstractDependencyNavigatorTest : WordSpec() { "directDependencies" should { "return the direct dependencies of a project" { - navigator.directDependencies(testProject, "test").map { it.id } should containSequenceExactly( + val scopeDependencies = navigator.directDependencies(testProject, "test").map { it.id } + + scopeDependencies should containAllInAnyOrder( Identifier("Maven:org.scalacheck:scalacheck_2.12:1.13.5"), Identifier("Maven:org.scalatest:scalatest_2.12:3.0.4") ) diff --git a/model/src/test/kotlin/CompatibilityDependencyNavigatorTest.kt b/model/src/test/kotlin/CompatibilityDependencyNavigatorTest.kt index d603585159b84..51be3e3b99333 100644 --- a/model/src/test/kotlin/CompatibilityDependencyNavigatorTest.kt +++ b/model/src/test/kotlin/CompatibilityDependencyNavigatorTest.kt @@ -253,7 +253,8 @@ private fun createProject( /** * Create a [Scope] with the given [name] and a synthetic dependency. */ -private fun createScope(name: String): Scope { - val dependencies = sortedSetOf(PackageReference(Identifier.EMPTY.copy(name = "dep$name"))) - return Scope(name, dependencies) -} +private fun createScope(name: String) = + Scope( + name = name, + dependencies = setOf(PackageReference(Identifier.EMPTY.copy(name = "dep$name"))) + ) diff --git a/model/src/test/kotlin/DependencyGraphTest.kt b/model/src/test/kotlin/DependencyGraphTest.kt index eb3a28b50339b..fb93ec5b223b4 100644 --- a/model/src/test/kotlin/DependencyGraphTest.kt +++ b/model/src/test/kotlin/DependencyGraphTest.kt @@ -242,7 +242,7 @@ private fun id(group: String, artifact: String, version: String): Identifier = */ private fun scopeDependencies(scopes: Set, name: String): String = buildString { scopes.find { it.name == name }?.let { scope -> - scope.dependencies.forEach { dumpDependencies(it) } + scope.dependencies.sorted().forEach { dumpDependencies(it) } } } @@ -253,7 +253,7 @@ private fun StringBuilder.dumpDependencies(ref: PackageReference) { append(ref.id) if (ref.dependencies.isNotEmpty()) { append('<') - ref.dependencies.forEach { dumpDependencies(it) } + ref.dependencies.sorted().forEach { dumpDependencies(it) } append('>') } } diff --git a/model/src/test/kotlin/DependencyTreeNavigatorTest.kt b/model/src/test/kotlin/DependencyTreeNavigatorTest.kt index 03eb00326c866..2558ff1690cb5 100644 --- a/model/src/test/kotlin/DependencyTreeNavigatorTest.kt +++ b/model/src/test/kotlin/DependencyTreeNavigatorTest.kt @@ -35,7 +35,7 @@ class DependencyTreeNavigatorTest : AbstractDependencyNavigatorTest() { // various corner cases. val scope = Scope( name = "test", - dependencies = sortedSetOf( + dependencies = setOf( pkg("A"), pkg("B") { pkg("A") @@ -92,7 +92,7 @@ class DependencyTreeNavigatorTest : AbstractDependencyNavigatorTest() { "return 1 if the scope contains only direct dependencies" { val scope = Scope( name = "test", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference(id = Identifier("a")), PackageReference(id = Identifier("b")) ) @@ -105,7 +105,7 @@ class DependencyTreeNavigatorTest : AbstractDependencyNavigatorTest() { "return 2 if the scope contains a tree of height 2" { val scope = Scope( name = "test", - dependencies = sortedSetOf( + dependencies = setOf( pkg("a") { pkg("a1") } @@ -119,7 +119,7 @@ class DependencyTreeNavigatorTest : AbstractDependencyNavigatorTest() { "return 3 if it contains a tree of height 3" { val scope = Scope( name = "test", - dependencies = sortedSetOf( + dependencies = setOf( pkg("a") { pkg("a1") { pkg("a11") @@ -146,7 +146,7 @@ private const val RESULT_WITH_ISSUES_FILE = "src/test/assets/result-with-issues- private class PackageRefBuilder(id: String) { private val id = Identifier(id) - private val dependencies = sortedSetOf() + private val dependencies = mutableSetOf() fun pkg(id: String, block: PackageRefBuilder.() -> Unit = {}) { dependencies += PackageRefBuilder(id).apply { block() }.build() diff --git a/model/src/test/kotlin/PackageReferenceTest.kt b/model/src/test/kotlin/PackageReferenceTest.kt index 7112c6a4120a3..7ebf1a02e50ba 100644 --- a/model/src/test/kotlin/PackageReferenceTest.kt +++ b/model/src/test/kotlin/PackageReferenceTest.kt @@ -30,7 +30,7 @@ import io.kotest.matchers.string.endWith class PackageReferenceTest : WordSpec() { companion object { fun pkgRefFromIdStr(id: String, vararg dependencies: PackageReference) = - PackageReference(Identifier(id), dependencies = dependencies.toSortedSet()) + PackageReference(Identifier(id), dependencies = dependencies.toSet()) } private val node111 = pkgRefFromIdStr("::node1_1_1") diff --git a/model/src/test/kotlin/config/ExcludesTest.kt b/model/src/test/kotlin/config/ExcludesTest.kt index a6c0b47a460b9..6b48605a11de3 100644 --- a/model/src/test/kotlin/config/ExcludesTest.kt +++ b/model/src/test/kotlin/config/ExcludesTest.kt @@ -56,9 +56,9 @@ class ExcludesTest : WordSpec() { private val pathExclude3 = PathExclude("**/*.ext", PathExcludeReason.BUILD_TOOL_OF, "") private val pathExclude4 = PathExclude("**/file.ext", PathExcludeReason.BUILD_TOOL_OF, "") - private val scope1 = Scope("scope1", sortedSetOf(PackageReference(id))) - private val scope2 = Scope("scope2", sortedSetOf(PackageReference(id))) - private val scopeProject1 = Scope("scopeProject1", sortedSetOf(PackageReference(project1.id))) + private val scope1 = Scope("scope1", setOf(PackageReference(id))) + private val scope2 = Scope("scope2", setOf(PackageReference(id))) + private val scopeProject1 = Scope("scopeProject1", setOf(PackageReference(project1.id))) private val scopeExclude1 = ScopeExclude("scope1", ScopeExcludeReason.PROVIDED_DEPENDENCY_OF, "") private val scopeExclude2 = ScopeExclude("scope2", ScopeExcludeReason.PROVIDED_DEPENDENCY_OF, "") diff --git a/model/src/test/kotlin/licenses/TestData.kt b/model/src/test/kotlin/licenses/TestData.kt index 008574e54b92a..5da9ee53863b7 100644 --- a/model/src/test/kotlin/licenses/TestData.kt +++ b/model/src/test/kotlin/licenses/TestData.kt @@ -117,7 +117,7 @@ val allPackages = setOf( val scope = Scope( name = "compile", - dependencies = sortedSetOf( + dependencies = setOf( packageWithoutLicense.toReference(), packageWithConcludedLicense.toReference(), packageWithDeclaredLicense.toReference(), diff --git a/model/src/test/kotlin/utils/DependencyGraphBuilderTest.kt b/model/src/test/kotlin/utils/DependencyGraphBuilderTest.kt index 442a4f88bded9..e041ba6931759 100644 --- a/model/src/test/kotlin/utils/DependencyGraphBuilderTest.kt +++ b/model/src/test/kotlin/utils/DependencyGraphBuilderTest.kt @@ -121,10 +121,10 @@ class DependencyGraphBuilderTest : WordSpec({ "org.apache.commons", "commons-configuration2", "2.7", - dependencies = listOf(dep1, dep2) + dependencies = setOf(dep1, dep2) ) - val dep4 = createDependency("org.apache.commons", "commons-csv", "1.5", dependencies = listOf(dep1)) - val dep5 = createDependency("com.acme", "dep", "0.7", dependencies = listOf(dep3)) + val dep4 = createDependency("org.apache.commons", "commons-csv", "1.5", dependencies = setOf(dep1)) + val dep5 = createDependency("com.acme", "dep", "0.7", dependencies = setOf(dep3)) val graph = createGraphBuilder() .addDependency(scope1, dep1) @@ -151,21 +151,21 @@ class DependencyGraphBuilderTest : WordSpec({ val depLog = createDependency("commons-logging", "commons-logging", "1.2") val depConfig1 = createDependency( "org.apache.commons", "commons-configuration2", "2.7", - dependencies = listOf(depLog, depLang) + dependencies = setOf(depLog, depLang) ) val depConfig2 = createDependency( "org.apache.commons", "commons-configuration2", "2.7", - dependencies = listOf(depLang) + dependencies = setOf(depLang) ) val depAcme = createDependency( "com.acme", "lib-full", "1.0", - dependencies = listOf(depConfig1, depLang) + dependencies = setOf(depConfig1, depLang) ) val depAcmeExclude = createDependency( "com.acme", "lib-exclude", "1.1", - dependencies = listOf(depConfig2) + dependencies = setOf(depConfig2) ) - val depLib = createDependency("com.business", "lib", "1", dependencies = listOf(depConfig1, depAcmeExclude)) + val depLib = createDependency("com.business", "lib", "1", dependencies = setOf(depConfig1, depAcmeExclude)) val graph = createGraphBuilder() .addDependency(scope, depAcme) @@ -182,15 +182,15 @@ class DependencyGraphBuilderTest : WordSpec({ val depLog = createDependency("commons-logging", "commons-logging", "1.2") val depConfig1 = createDependency( "org.apache.commons", "commons-configuration2", "2.7", - dependencies = listOf(depLog, depLang) + dependencies = setOf(depLog, depLang) ) val depConfig2 = createDependency( "org.apache.commons", "commons-configuration2", "2.7", - dependencies = listOf(depLang) + dependencies = setOf(depLang) ) val depAcmeExclude = createDependency( "com.acme", "lib-exclude", "1.1", - dependencies = listOf(depConfig2) + dependencies = setOf(depConfig2) ) val graph = createGraphBuilder() @@ -207,8 +207,8 @@ class DependencyGraphBuilderTest : WordSpec({ "deal with cycles in dependencies" { val scope = "CyclicScope" val depCyc1 = createDependency("org.cyclic", "cyclic", "77.7") - val depFoo = createDependency("org.foo", "foo", "1.2.0", dependencies = listOf(depCyc1)) - val depCyc2 = createDependency("org.cyclic", "cyclic", "77.7", dependencies = listOf(depFoo)) + val depFoo = createDependency("org.foo", "foo", "1.2.0", dependencies = setOf(depCyc1)) + val depCyc2 = createDependency("org.cyclic", "cyclic", "77.7", dependencies = setOf(depFoo)) val graph = createGraphBuilder() .addDependency(scope, depCyc2) @@ -225,7 +225,7 @@ class DependencyGraphBuilderTest : WordSpec({ "check for illegal references when building the graph" { val depLang = createDependency("org.apache.commons", "commons-lang3", "3.11") val depNoPkg = createDependency(NO_PACKAGE_NAMESPACE, "invalid", "1.2") - val depLog = createDependency("commons-logging", "commons-logging", "1.2", dependencies = listOf(depNoPkg)) + val depLog = createDependency("commons-logging", "commons-logging", "1.2", dependencies = setOf(depNoPkg)) val exception = shouldThrow { createGraphBuilder() @@ -243,7 +243,7 @@ class DependencyGraphBuilderTest : WordSpec({ issues = listOf(Issue(source = "test", message = "test issue")) ) val depLog = - createDependency("commons-logging", "commons-logging", "1.2", dependencies = listOf(depIssuesPkg)) + createDependency("commons-logging", "commons-logging", "1.2", dependencies = setOf(depIssuesPkg)) createGraphBuilder() .addDependency("s", depLang) @@ -263,7 +263,7 @@ class DependencyGraphBuilderTest : WordSpec({ "commons-logging", "commons-logging", "1.2", - dependencies = listOf(depProjectDynamicPkg, depProjectStaticPkg) + dependencies = setOf(depProjectDynamicPkg, depProjectStaticPkg) ) createGraphBuilder() @@ -275,7 +275,7 @@ class DependencyGraphBuilderTest : WordSpec({ "allow disabling the check for illegal references" { val depLang = createDependency("org.apache.commons", "commons-lang3", "3.11") val depNoPkg = createDependency(NO_PACKAGE_NAMESPACE, "invalid", "1.2") - val depLog = createDependency("commons-logging", "commons-logging", "1.2", dependencies = listOf(depNoPkg)) + val depLog = createDependency("commons-logging", "commons-logging", "1.2", dependencies = setOf(depNoPkg)) createGraphBuilder() .addDependency("s", depLang) @@ -383,11 +383,12 @@ private fun createDependency( group: String, artifact: String, version: String, - dependencies: List = emptyList() -): PackageReference { - val id = Identifier("test", group, artifact, version) - return PackageReference(id, dependencies = dependencies.toSortedSet()) -} + dependencies: Set = emptySet() +) = + PackageReference( + id = Identifier("test", group, artifact, version), + dependencies = dependencies + ) /** * Return the package references from the given [scopes] associated with the scope with the given [scopeName]. diff --git a/model/src/test/kotlin/utils/DependencyGraphConverterTest.kt b/model/src/test/kotlin/utils/DependencyGraphConverterTest.kt index 3a24a9477f0dd..42857df5dc8a3 100644 --- a/model/src/test/kotlin/utils/DependencyGraphConverterTest.kt +++ b/model/src/test/kotlin/utils/DependencyGraphConverterTest.kt @@ -34,7 +34,6 @@ import io.kotest.matchers.shouldNot import io.kotest.matchers.types.beTheSameInstanceAs import java.io.File -import java.util.SortedSet import org.ossreviewtoolkit.model.AnalyzerResult import org.ossreviewtoolkit.model.DependencyGraphNode @@ -221,8 +220,8 @@ private fun createIdentifier(managerName: String, index: Int, forProject: Boolea * Create a set of [PackageReference]s with the size of [count] simulating the dependencies of a project. Use * [managerName], [startIndex] to generate identifiers. */ -private fun createDependencies(managerName: String, startIndex: Int, count: Int): SortedSet = - (startIndex..(startIndex + count)).mapTo(sortedSetOf()) { index -> +private fun createDependencies(managerName: String, startIndex: Int, count: Int): Set = + (startIndex..(startIndex + count)).mapTo(mutableSetOf()) { index -> PackageReference(createIdentifier(managerName, index, forProject = false), issues = createIssues(index)) } diff --git a/plugins/package-managers/bower/src/main/kotlin/Bower.kt b/plugins/package-managers/bower/src/main/kotlin/Bower.kt index 499e0a19dd8f4..85349f59a1bd6 100644 --- a/plugins/package-managers/bower/src/main/kotlin/Bower.kt +++ b/plugins/package-managers/bower/src/main/kotlin/Bower.kt @@ -24,7 +24,6 @@ package org.ossreviewtoolkit.plugins.packagemanagers.bower import com.fasterxml.jackson.databind.JsonNode import java.io.File -import java.util.SortedSet import java.util.Stack import org.ossreviewtoolkit.analyzer.AbstractPackageManagerFactory @@ -241,7 +240,7 @@ private fun parseDependencyTree( node: JsonNode, scopeName: String, alternativeNodes: Map = getNodesWithCompleteDependencies(node) -): SortedSet { +): Set { val result = mutableSetOf() if (!hasCompleteDependencies(node, scopeName)) { @@ -265,5 +264,5 @@ private fun parseDependencyTree( result += packageReference } - return result.toSortedSet() + return result } diff --git a/plugins/package-managers/bundler/src/main/kotlin/Bundler.kt b/plugins/package-managers/bundler/src/main/kotlin/Bundler.kt index 8a68dddc08b2c..7e954b7dd4352 100644 --- a/plugins/package-managers/bundler/src/main/kotlin/Bundler.kt +++ b/plugins/package-managers/bundler/src/main/kotlin/Bundler.kt @@ -250,7 +250,7 @@ class Bundler( parseDependency(workingDir, projectId, it, gemSpecs, scopeDependencies, issues) } - scopes += Scope(groupName, scopeDependencies.toSortedSet()) + scopes += Scope(groupName, scopeDependencies) } private fun parseDependency( @@ -281,7 +281,7 @@ class Bundler( parseDependency(workingDir, projectId, it, gemSpecs, transitiveDependencies, issues) } - scopeDependencies += PackageReference(gemId, dependencies = transitiveDependencies.toSortedSet()) + scopeDependencies += PackageReference(gemId, dependencies = transitiveDependencies) } }.onFailure { it.showStackTrace() diff --git a/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt b/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt index 5e7d33eff14f3..59d478069db44 100644 --- a/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt +++ b/plugins/package-managers/cargo/src/main/kotlin/Cargo.kt @@ -150,7 +150,7 @@ class Cargo( // Filter dev and build dependencies, because they are not transitive. val kind = it["kind"].textValueOrEmpty() kind != "dev" && kind != "build" - }.mapNotNull { + }.mapNotNullTo(mutableSetOf()) { // TODO: Handle renamed dependencies here, see: // https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml val dependencyName = it["name"].textValue() @@ -158,7 +158,7 @@ class Cargo( getResolvedVersion(name, version, dependencyName, metadata)?.let { dependencyVersion -> buildDependencyTree(dependencyName, dependencyVersion, packages, metadata) } - }.toSortedSet() + } val id = parseCargoId(node) val pkg = packages.getValue(id) @@ -200,10 +200,9 @@ class Cargo( val version = getResolvedVersion(projectName, projectVersion, dependencyName, metadata) version?.let { Pair(dependencyName, it) } } - .map { + .mapTo(mutableSetOf()) { buildDependencyTree(name = it.first, version = it.second, packages = packages, metadata = metadata) } - .toSortedSet() return Scope(scope, transitiveDependencies) } diff --git a/plugins/package-managers/cocoapods/src/main/kotlin/CocoaPods.kt b/plugins/package-managers/cocoapods/src/main/kotlin/CocoaPods.kt index 8fd6a3eea4e29..224494acd39e8 100644 --- a/plugins/package-managers/cocoapods/src/main/kotlin/CocoaPods.kt +++ b/plugins/package-managers/cocoapods/src/main/kotlin/CocoaPods.kt @@ -29,7 +29,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode import java.io.File import java.io.IOException -import java.util.SortedSet import org.apache.logging.log4j.kotlin.Logging @@ -232,7 +231,7 @@ private const val SCOPE_NAME = "dependencies" private val NAME_AND_VERSION_REGEX = "(\\S+)\\s+(.*)".toRegex() -private fun getPackageReferences(podfileLock: File): SortedSet { +private fun getPackageReferences(podfileLock: File): Set { val versionForName = mutableMapOf() val dependenciesForName = mutableMapOf>() val root = yamlMapper.readTree(podfileLock) @@ -255,10 +254,10 @@ private fun getPackageReferences(podfileLock: File): SortedSet fun createPackageReference(name: String): PackageReference = PackageReference( id = Identifier("Pod", "", name, versionForName.getValue(name)), - dependencies = dependenciesForName.getValue(name).mapTo(sortedSetOf()) { createPackageReference(it) } + dependencies = dependenciesForName.getValue(name).mapTo(mutableSetOf()) { createPackageReference(it) } ) - return root.get("DEPENDENCIES").mapTo(sortedSetOf()) { node -> + return root.get("DEPENDENCIES").mapTo(mutableSetOf()) { node -> val name = node.textValue().substringBefore(" ") createPackageReference(name) } diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index dd3db354b8350..35bfb6efcfb7d 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -24,7 +24,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode import java.io.File import java.io.IOException -import java.util.SortedSet import org.apache.logging.log4j.kotlin.Logging @@ -171,7 +170,7 @@ class Composer( packages: Map, virtualPackages: Set, dependencyBranch: List = emptyList() - ): SortedSet { + ): Set { val packageReferences = mutableSetOf() dependencies.filterNot { packageName -> @@ -209,7 +208,7 @@ class Composer( } } - return packageReferences.toSortedSet() + return packageReferences } private fun parseProject(definitionFile: File, scopes: Set): Project { diff --git a/plugins/package-managers/conan/src/main/kotlin/Conan.kt b/plugins/package-managers/conan/src/main/kotlin/Conan.kt index 3bfa5e541356c..c20195257ffc5 100644 --- a/plugins/package-managers/conan/src/main/kotlin/Conan.kt +++ b/plugins/package-managers/conan/src/main/kotlin/Conan.kt @@ -23,7 +23,6 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.module.kotlin.readValue import java.io.File -import java.util.SortedSet import org.apache.logging.log4j.kotlin.Logging @@ -268,25 +267,22 @@ class Conan( pkg: JsonNode, scopeName: String, workingDir: File - ): SortedSet { - val result = mutableSetOf() - - pkg[scopeName]?.forEach { childNode -> - val childRef = childNode.textValueOrEmpty() - pkgInfos.find { it["reference"].textValueOrEmpty() == childRef }?.let { pkgInfo -> - logger.debug { "Found child '$childRef'." } - - val id = parsePackageId(pkgInfo, workingDir) - val dependencies = parseDependencyTree(pkgInfos, pkgInfo, SCOPE_NAME_DEPENDENCIES, workingDir) + - parseDependencyTree(pkgInfos, pkgInfo, SCOPE_NAME_DEV_DEPENDENCIES, workingDir) - - result += PackageReference(id, dependencies = dependencies.toSortedSet()) + ): Set = + buildSet { + pkg[scopeName]?.forEach { childNode -> + val childRef = childNode.textValueOrEmpty() + pkgInfos.find { it["reference"].textValueOrEmpty() == childRef }?.let { pkgInfo -> + logger.debug { "Found child '$childRef'." } + + val id = parsePackageId(pkgInfo, workingDir) + val dependencies = parseDependencyTree(pkgInfos, pkgInfo, SCOPE_NAME_DEPENDENCIES, workingDir) + + parseDependencyTree(pkgInfos, pkgInfo, SCOPE_NAME_DEV_DEPENDENCIES, workingDir) + + this += PackageReference(id, dependencies = dependencies) + } } } - return result.toSortedSet() - } - /** * Run through each package and parse the list of its dependencies (also transitive ones). */ @@ -295,7 +291,7 @@ class Conan( definitionFileName: String, scopeName: String, workingDir: File - ): SortedSet = + ): Set = parseDependencyTree(pkgInfos, findProjectNode(pkgInfos, definitionFileName), scopeName, workingDir) /** diff --git a/plugins/package-managers/gradle-inspector/src/main/kotlin/GradleInspector.kt b/plugins/package-managers/gradle-inspector/src/main/kotlin/GradleInspector.kt index 6557c4ab16238..506d131264309 100644 --- a/plugins/package-managers/gradle-inspector/src/main/kotlin/GradleInspector.kt +++ b/plugins/package-managers/gradle-inspector/src/main/kotlin/GradleInspector.kt @@ -24,7 +24,6 @@ import OrtDependencyTreeModel import java.io.ByteArrayOutputStream import java.io.File -import java.util.SortedSet import java.util.concurrent.TimeUnit import org.apache.logging.log4j.kotlin.Logging @@ -291,8 +290,8 @@ class GradleInspector( */ private fun Collection.toPackageRefs( packageDependencies: MutableCollection -): SortedSet = - mapTo(sortedSetOf()) { dep -> +): Set = + mapTo(mutableSetOf()) { dep -> val (id, linkage) = if (dep.localPath != null) { val id = Identifier("Gradle", dep.groupId, dep.artifactId, dep.version) id to PackageLinkage.PROJECT_DYNAMIC diff --git a/plugins/package-managers/nuget/src/main/kotlin/utils/NuGetInspector.kt b/plugins/package-managers/nuget/src/main/kotlin/utils/NuGetInspector.kt index 7b4d99b114f6f..d26bca3204203 100644 --- a/plugins/package-managers/nuget/src/main/kotlin/utils/NuGetInspector.kt +++ b/plugins/package-managers/nuget/src/main/kotlin/utils/NuGetInspector.kt @@ -184,8 +184,8 @@ internal fun NuGetInspector.Result.toOrtProject( ) } -private fun List.toPackageReferences(): SortedSet = - mapTo(sortedSetOf()) { data -> +private fun List.toPackageReferences(): Set = + mapTo(mutableSetOf()) { data -> PackageReference( id = Identifier(type = TYPE, namespace = "", name = data.name, version = data.version.orEmpty()), dependencies = data.dependencies.toPackageReferences(), diff --git a/plugins/package-managers/pub/src/main/kotlin/Pub.kt b/plugins/package-managers/pub/src/main/kotlin/Pub.kt index 78df635ebf3b2..1e0ad1b4b2f86 100644 --- a/plugins/package-managers/pub/src/main/kotlin/Pub.kt +++ b/plugins/package-managers/pub/src/main/kotlin/Pub.kt @@ -24,7 +24,6 @@ import com.fasterxml.jackson.dataformat.yaml.JacksonYAMLParseException import java.io.File import java.io.IOException -import java.util.SortedSet import org.apache.logging.log4j.kotlin.Logging @@ -267,14 +266,14 @@ class Pub( .toList() if (gradleDefinitionFiles.isNotEmpty()) { - val gradleDependencies = gradleDefinitionFiles.map { + val gradleDependencies = gradleDefinitionFiles.mapTo(mutableSetOf()) { PackageManagerDependencyHandler.createPackageManagerDependency( packageManager = gradleFactory.type, definitionFile = VersionControlSystem.getPathInfo(it).path, scope = "releaseCompileClasspath", linkage = PackageLinkage.PROJECT_STATIC ) - }.toSortedSet() + } scopes += Scope("android", gradleDependencies) } @@ -331,7 +330,7 @@ class Pub( labels: Map, workingDir: File, processedPackages: Set = emptySet() - ): SortedSet { + ): Set { val packageReferences = mutableSetOf() val nameOfCurrentPackage = manifest["name"].textValue() val containsFlutter = "flutter" in dependencies @@ -403,7 +402,7 @@ class Pub( } } - return packageReferences.toSortedSet() + return packageReferences } private val analyzerResultCacheAndroid = mutableMapOf>() diff --git a/plugins/package-managers/python/src/main/kotlin/utils/PythonInspector.kt b/plugins/package-managers/python/src/main/kotlin/utils/PythonInspector.kt index ed1258a19b5e4..79691ee426d5a 100644 --- a/plugins/package-managers/python/src/main/kotlin/utils/PythonInspector.kt +++ b/plugins/package-managers/python/src/main/kotlin/utils/PythonInspector.kt @@ -20,7 +20,6 @@ package org.ossreviewtoolkit.plugins.packagemanagers.python.utils import java.io.File -import java.util.SortedSet import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -344,8 +343,8 @@ private fun List.toAuthors(): Set = }.takeIf { it.isNotBlank() } } -private fun List.toPackageReferences(): SortedSet = - mapTo(sortedSetOf()) { it.toPackageReference() } +private fun List.toPackageReferences(): Set = + mapTo(mutableSetOf()) { it.toPackageReference() } private fun PythonInspector.ResolvedDependency.toPackageReference() = PackageReference( diff --git a/plugins/package-managers/spdx/src/main/kotlin/SpdxDocumentFile.kt b/plugins/package-managers/spdx/src/main/kotlin/SpdxDocumentFile.kt index d352761671ddb..be7b251ea29ff 100644 --- a/plugins/package-managers/spdx/src/main/kotlin/SpdxDocumentFile.kt +++ b/plugins/package-managers/spdx/src/main/kotlin/SpdxDocumentFile.kt @@ -22,7 +22,6 @@ package org.ossreviewtoolkit.plugins.packagemanagers.spdx import java.io.File -import java.util.SortedSet import org.apache.logging.log4j.kotlin.Logging @@ -335,7 +334,7 @@ class SpdxDocumentFile( pkgId: String, doc: SpdxResolvedDocument, packages: MutableSet - ): SortedSet = + ): Set = getDependencies(pkgId, doc, packages, SpdxRelationship.Type.DEPENDENCY_OF) { target -> val issues = mutableListOf() getPackageManagerDependency(target, doc) ?: doc.getSpdxPackageForId(target, issues)?.let { dependency -> @@ -390,8 +389,8 @@ class SpdxDocumentFile( packages: MutableSet, dependencyOfRelation: SpdxRelationship.Type, dependsOnCase: (String) -> PackageReference? = { null } - ): SortedSet = - doc.relationships.mapNotNullTo(sortedSetOf()) { (source, relation, target, _) -> + ): Set = + doc.relationships.mapNotNullTo(mutableSetOf()) { (source, relation, target, _) -> val issues = mutableListOf() val isDependsOnRelation = relation == SpdxRelationship.Type.DEPENDS_ON || hasDefaultScopeLinkage( diff --git a/plugins/package-managers/stack/src/main/kotlin/Stack.kt b/plugins/package-managers/stack/src/main/kotlin/Stack.kt index 8677bb94c641f..0b611cd35f35e 100644 --- a/plugins/package-managers/stack/src/main/kotlin/Stack.kt +++ b/plugins/package-managers/stack/src/main/kotlin/Stack.kt @@ -24,7 +24,6 @@ import com.fasterxml.jackson.module.kotlin.readValue import java.io.File import java.io.IOException -import java.util.SortedSet import org.apache.logging.log4j.kotlin.Logging @@ -190,8 +189,8 @@ class Stack( if (pkg != null && pkg.id.name != "ghc") dependencyPackageMap[dependency] = pkg } - fun List.toPackageReferences(): SortedSet = - mapNotNullTo(sortedSetOf()) { name -> + fun List.toPackageReferences(): Set = + mapNotNullTo(mutableSetOf()) { name -> // TODO: Stack identifies dependencies only by name. Find out how dependencies with the same name but in // different namespaces should be handled. dependencyPackageMap.entries.find { (dependency, _) -> dependency.name == name }?.let { entry -> diff --git a/plugins/reporters/evaluated-model/src/main/kotlin/EvaluatedModelMapper.kt b/plugins/reporters/evaluated-model/src/main/kotlin/EvaluatedModelMapper.kt index 2cfe624fde4f7..002c2f22ed836 100644 --- a/plugins/reporters/evaluated-model/src/main/kotlin/EvaluatedModelMapper.kt +++ b/plugins/reporters/evaluated-model/src/main/kotlin/EvaluatedModelMapper.kt @@ -492,7 +492,7 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) { visitedNodes += getInternalId() to createDependencyNode(dependency, linkage, issues) val children = visitDependencies { dependencies -> - dependencies.map { node -> + dependencies.sortedBy { it.id }.map { node -> val nodeId = node.getInternalId() if (deduplicateDependencyTree && nodeId in visitedNodes) { @@ -511,9 +511,8 @@ internal class EvaluatedModelMapper(private val input: ReporterInput) { // Deduplication should not happen across scopes. visitedNodes.clear() - val subTrees = input.ortResult.dependencyNavigator.directDependencies(project, scope).map { - it.toEvaluatedTreeNode(scopes.getValue(scope), mutableListOf()) - }.toList() + val subTrees = input.ortResult.dependencyNavigator.directDependencies(project, scope).sortedBy { it.id } + .mapTo(mutableListOf()) { it.toEvaluatedTreeNode(scopes.getValue(scope), mutableListOf()) } val applicableScopeExcludes = input.ortResult.getExcludes().findScopeExcludes(scope) val evaluatedScopeExcludes = scopeExcludes.addIfRequired(applicableScopeExcludes) diff --git a/plugins/reporters/gitlab/src/funTest/kotlin/GitLabLicenseModelReporterFunTest.kt b/plugins/reporters/gitlab/src/funTest/kotlin/GitLabLicenseModelReporterFunTest.kt index ec0306eab909c..5255d3bbd8660 100644 --- a/plugins/reporters/gitlab/src/funTest/kotlin/GitLabLicenseModelReporterFunTest.kt +++ b/plugins/reporters/gitlab/src/funTest/kotlin/GitLabLicenseModelReporterFunTest.kt @@ -95,7 +95,7 @@ private fun createOrtResult(): OrtResult { scopeDependencies = setOf( Scope( name = "compile", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("Maven:some-group:first-package:0.0.1") ) @@ -103,7 +103,7 @@ private fun createOrtResult(): OrtResult { ), Scope( name = "test", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("Maven:some-group:excluded-package:0.0.4") ) @@ -116,7 +116,7 @@ private fun createOrtResult(): OrtResult { scopeDependencies = setOf( Scope( name = "install", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("PIP::second-package:0.0.2") ) diff --git a/plugins/reporters/opossum/src/test/kotlin/OpossumReporterTest.kt b/plugins/reporters/opossum/src/test/kotlin/OpossumReporterTest.kt index c7ae99ff555f7..1d91a62a3b155 100644 --- a/plugins/reporters/opossum/src/test/kotlin/OpossumReporterTest.kt +++ b/plugins/reporters/opossum/src/test/kotlin/OpossumReporterTest.kt @@ -266,7 +266,7 @@ private fun createOrtResult(): OrtResult { scopeDependencies = setOf( Scope( name = "compile", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("Maven:first-package-group:first-package:0.0.1") ), @@ -286,7 +286,7 @@ private fun createOrtResult(): OrtResult { ), Scope( name = "test", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("Maven:fifth-package-group:fifth-package:0.0.1") ) @@ -303,16 +303,16 @@ private fun createOrtResult(): OrtResult { scopeDependencies = setOf( Scope( name = "devDependencies", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("NPM:@something:somepackage:1.2.3"), - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("NPM:@something:somepackage-dep:1.2.3"), - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("NPM:@something:somepackage-dep-dep:1.2.3"), - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier( "NPM:@something:" + diff --git a/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.json b/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.json index 0298f85940e43..2397a6bfad36f 100644 --- a/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.json +++ b/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.json @@ -155,11 +155,15 @@ "relationships" : [ { "spdxElementId" : "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1", "relationshipType" : "GENERATED_FROM", - "relatedSpdxElement" : "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-vcs" + "relatedSpdxElement" : "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-source-artifact" }, { "spdxElementId" : "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1", "relationshipType" : "GENERATED_FROM", - "relatedSpdxElement" : "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-source-artifact" + "relatedSpdxElement" : "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-vcs" + }, { + "spdxElementId" : "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1", + "relationshipType" : "DEPENDS_ON", + "relatedSpdxElement" : "SPDXRef-Package-Maven-fifth-package-group-fifth-package-0.0.1" }, { "spdxElementId" : "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1", "relationshipType" : "DEPENDS_ON", @@ -180,9 +184,5 @@ "spdxElementId" : "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1", "relationshipType" : "DEPENDS_ON", "relatedSpdxElement" : "SPDXRef-Package-Maven-third-package-group-third-package-0.0.1" - }, { - "spdxElementId" : "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1", - "relationshipType" : "DEPENDS_ON", - "relatedSpdxElement" : "SPDXRef-Package-Maven-fifth-package-group-fifth-package-0.0.1" } ] } \ No newline at end of file diff --git a/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.yml b/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.yml index 0609f4e009eaf..fe28cc62cd7f6 100644 --- a/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.yml +++ b/plugins/reporters/spdx/src/funTest/assets/spdx-document-reporter-expected-output.spdx.yml @@ -166,10 +166,13 @@ packages: relationships: - spdxElementId: "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1" relationshipType: "GENERATED_FROM" - relatedSpdxElement: "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-vcs" + relatedSpdxElement: "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-source-artifact" - spdxElementId: "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1" relationshipType: "GENERATED_FROM" - relatedSpdxElement: "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-source-artifact" + relatedSpdxElement: "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1-vcs" +- spdxElementId: "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1" + relationshipType: "DEPENDS_ON" + relatedSpdxElement: "SPDXRef-Package-Maven-fifth-package-group-fifth-package-0.0.1" - spdxElementId: "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1" relationshipType: "DEPENDS_ON" relatedSpdxElement: "SPDXRef-Package-Maven-first-package-group-first-package-0.0.1" @@ -185,6 +188,3 @@ relationships: - spdxElementId: "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1" relationshipType: "DEPENDS_ON" relatedSpdxElement: "SPDXRef-Package-Maven-third-package-group-third-package-0.0.1" -- spdxElementId: "SPDXRef-Project-Maven-first-project-group-first-project-name-0.0.1" - relationshipType: "DEPENDS_ON" - relatedSpdxElement: "SPDXRef-Package-Maven-fifth-package-group-fifth-package-0.0.1" diff --git a/plugins/reporters/spdx/src/funTest/kotlin/SpdxDocumentReporterFunTest.kt b/plugins/reporters/spdx/src/funTest/kotlin/SpdxDocumentReporterFunTest.kt index 2dedd03bd9551..cf8e8ed2fcdb1 100644 --- a/plugins/reporters/spdx/src/funTest/kotlin/SpdxDocumentReporterFunTest.kt +++ b/plugins/reporters/spdx/src/funTest/kotlin/SpdxDocumentReporterFunTest.kt @@ -165,7 +165,7 @@ private val ortResult = OrtResult( scopeDependencies = setOf( Scope( name = "compile", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("Maven:first-package-group:first-package:0.0.1") ), @@ -185,7 +185,7 @@ private val ortResult = OrtResult( ), Scope( name = "test", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("Maven:fifth-package-group:fifth-package:0.0.1") ) diff --git a/reporter/src/testFixtures/kotlin/TestData.kt b/reporter/src/testFixtures/kotlin/TestData.kt index cac44cf2c15f9..a9fc47a4c9c14 100644 --- a/reporter/src/testFixtures/kotlin/TestData.kt +++ b/reporter/src/testFixtures/kotlin/TestData.kt @@ -96,7 +96,7 @@ val ORT_RESULT = OrtResult( scopeDependencies = setOf( Scope( name = "dependencies", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("NPM:@ort:no-license-file:1.0") ), @@ -116,7 +116,7 @@ val ORT_RESULT = OrtResult( ), Scope( name = "devDependencies", - dependencies = sortedSetOf( + dependencies = setOf( PackageReference( id = Identifier("NPM:@ort:declared-license:1.0") ), @@ -133,7 +133,7 @@ val ORT_RESULT = OrtResult( scopeDependencies = setOf( Scope( name = "dependencies", - dependencies = sortedSetOf() + dependencies = emptySet() ) ) ), diff --git a/utils/spdx/build.gradle.kts b/utils/spdx/build.gradle.kts index 3f6f6c25ec13a..f30635089a5fa 100644 --- a/utils/spdx/build.gradle.kts +++ b/utils/spdx/build.gradle.kts @@ -81,6 +81,8 @@ dependencies { implementation(libs.jacksonDataformatYaml) implementation(libs.jacksonDatatypeJsr310) implementation(libs.jacksonModuleKotlin) + + testImplementation(libs.kotestAssertionsJson) } data class LicenseInfo( diff --git a/utils/spdx/src/main/kotlin/model/Converters.kt b/utils/spdx/src/main/kotlin/model/Converters.kt new file mode 100644 index 0000000000000..9de05c14449ff --- /dev/null +++ b/utils/spdx/src/main/kotlin/model/Converters.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 The ORT Project Authors (see ) + * + * 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 + * + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +@file:Suppress("Filename", "MatchingDeclarationName") + +package org.ossreviewtoolkit.utils.spdx.model + +import com.fasterxml.jackson.databind.util.StdConverter + +import java.util.SortedSet + +internal class SpdxRelationshipSortedSetConverter : + StdConverter, SortedSet>() { + override fun convert(value: List) = + value.toSortedSet( + compareBy { it.spdxElementId } + .thenBy { it.relatedSpdxElement } + .thenBy { it.relationshipType } + ) +} + +// TODO: Add more converters for SpdxDocument to improve serialization, see +// https://github.com/oss-review-toolkit/ort/issues/7023. diff --git a/utils/spdx/src/main/kotlin/model/SpdxDocument.kt b/utils/spdx/src/main/kotlin/model/SpdxDocument.kt index d44d55318f09b..117e1391b9a87 100644 --- a/utils/spdx/src/main/kotlin/model/SpdxDocument.kt +++ b/utils/spdx/src/main/kotlin/model/SpdxDocument.kt @@ -21,6 +21,7 @@ package org.ossreviewtoolkit.utils.spdx.model import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.annotation.JsonSerialize import org.ossreviewtoolkit.utils.common.getDuplicates import org.ossreviewtoolkit.utils.spdx.SpdxConstants.REF_PREFIX @@ -127,6 +128,7 @@ data class SpdxDocument( * All relationships described in this [SpdxDocument]. */ @JsonInclude(JsonInclude.Include.NON_EMPTY) + @JsonSerialize(converter = SpdxRelationshipSortedSetConverter::class) val relationships: List = emptyList() ) { init { diff --git a/utils/spdx/src/test/kotlin/model/SpdxDocumentTest.kt b/utils/spdx/src/test/kotlin/model/SpdxDocumentTest.kt index 5b97f9b0f53a9..af271917d193b 100644 --- a/utils/spdx/src/test/kotlin/model/SpdxDocumentTest.kt +++ b/utils/spdx/src/test/kotlin/model/SpdxDocumentTest.kt @@ -21,14 +21,16 @@ package org.ossreviewtoolkit.utils.spdx.model import com.fasterxml.jackson.databind.exc.ValueInstantiationException +import io.kotest.assertions.json.ArrayOrder +import io.kotest.assertions.json.shouldEqualJson import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.WordSpec -import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import java.io.File import org.ossreviewtoolkit.utils.spdx.SpdxModelMapper +import org.ossreviewtoolkit.utils.spdx.yamlMapper /** * This test uses the following test assets copied from the SPDX 2.2.1 specification examples. @@ -52,13 +54,13 @@ class SpdxDocumentTest : WordSpec({ "The official YAML example without ranges from the SPDX specification version 2.2" should { "have idempotent (de)-serialization" { - val yaml = spdxExamplesDir.resolve("SPDXYAMLExample-2.2-no-ranges.spdx.yaml") - val document = SpdxModelMapper.read(yaml) + val yaml = spdxExamplesDir.resolve("SPDXYAMLExample-2.2-no-ranges.spdx.yaml").readText() - val serializedYaml = SpdxModelMapper.toYaml(document) - val deserializedYaml = SpdxModelMapper.fromYaml(serializedYaml) + val reSerializedYaml = SpdxModelMapper.fromYaml(yaml).let { + SpdxModelMapper.toYaml(it) + } - deserializedYaml shouldBe document + reSerializedYaml lenientShouldEqualYaml yaml } } @@ -72,13 +74,13 @@ class SpdxDocumentTest : WordSpec({ "The official JSON example without ranges from the SPDX specification version 2.2" should { "have idempotent (de-)serialization" { - val json = spdxExamplesDir.resolve("SPDXJSONExample-v2.2-no-ranges.spdx.json") - val document = SpdxModelMapper.read(json) + val json = spdxExamplesDir.resolve("SPDXJSONExample-v2.2-no-ranges.spdx.json").readText() - val serializedJson = SpdxModelMapper.toJson(document) - val deserializedJson = SpdxModelMapper.fromJson(serializedJson) + val reSerializedJson = SpdxModelMapper.fromJson(json).let { + SpdxModelMapper.toJson(it) + } - deserializedJson shouldBe document + reSerializedJson lenientShouldEqualJson json } } @@ -97,3 +99,16 @@ class SpdxDocumentTest : WordSpec({ } } }) + +private infix fun String.lenientShouldEqualJson(expected: String): String = + shouldEqualJson { + arrayOrder = ArrayOrder.Lenient + expected + } + +private infix fun String.lenientShouldEqualYaml(expected: String): String { + val json = yamlMapper.readTree(this).toString() + val expectedJson = yamlMapper.readTree(expected).toString() + + return json.lenientShouldEqualJson(expectedJson) +} diff --git a/utils/test/src/main/kotlin/OrtResultDsl.kt b/utils/test/src/main/kotlin/OrtResultDsl.kt index 92f80325761b5..fe31815d1a39d 100644 --- a/utils/test/src/main/kotlin/OrtResultDsl.kt +++ b/utils/test/src/main/kotlin/OrtResultDsl.kt @@ -19,8 +19,6 @@ package org.ossreviewtoolkit.utils.test -import java.util.SortedSet - import org.ossreviewtoolkit.model.AnalyzerResult import org.ossreviewtoolkit.model.AnalyzerRun import org.ossreviewtoolkit.model.Identifier @@ -55,8 +53,8 @@ class OrtResultBuilder { return pkg } - private fun getDependencies(ids: Set): SortedSet = - ids.mapTo(sortedSetOf()) { + private fun getDependencies(ids: Set): Set = + ids.mapTo(mutableSetOf()) { PackageReference( id = Identifier(it), dependencies = getDependencies(this@OrtResultBuilder.parentChildIds[it].orEmpty())