From 9bf736318e3447296630a2080a911be91a5d4603 Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Tue, 23 Jul 2024 23:29:23 +0200 Subject: [PATCH 1/9] chore(composer): Reduce the visibility of two constants Signed-off-by: Frank Viernau --- plugins/package-managers/composer/src/main/kotlin/Composer.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index f4f593cdcf62d..efffa97641c85 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -59,8 +59,8 @@ import org.semver4j.RangesList import org.semver4j.RangesListFactory import org.semver4j.Semver -const val COMPOSER_PHAR_BINARY = "composer.phar" -const val COMPOSER_LOCK_FILE = "composer.lock" +private const val COMPOSER_PHAR_BINARY = "composer.phar" +private const val COMPOSER_LOCK_FILE = "composer.lock" /** * The [Composer](https://getcomposer.org/) package manager for PHP. From a5a271a76c2813e069ae17665ad5f56ae7b93128 Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Tue, 23 Jul 2024 23:30:03 +0200 Subject: [PATCH 2/9] refactor(composer): Extract scope names to constants Prepare for an upcoming change. Signed-off-by: Frank Viernau --- .../package-managers/composer/src/main/kotlin/Composer.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index efffa97641c85..e49066c37259c 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -61,6 +61,8 @@ import org.semver4j.Semver private const val COMPOSER_PHAR_BINARY = "composer.phar" private const val COMPOSER_LOCK_FILE = "composer.lock" +private const val SCOPE_NAME_REQUIRE = "require" +private const val SCOPE_NAME_REQUIRE_DEV = "require-dev" /** * The [Composer](https://getcomposer.org/) package manager for PHP. @@ -144,8 +146,8 @@ class Composer( val virtualPackages = parseVirtualPackageNames(packages, manifest, json) val scopes = setOf( - parseScope("require", manifest, json, packages, virtualPackages), - parseScope("require-dev", manifest, json, packages, virtualPackages) + parseScope(SCOPE_NAME_REQUIRE, manifest, json, packages, virtualPackages), + parseScope(SCOPE_NAME_REQUIRE_DEV, manifest, json, packages, virtualPackages) ) val project = parseProject(definitionFile, scopes) From c5efa722404e96c00c37b18d30127384a3ead84f Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Tue, 23 Jul 2024 23:31:31 +0200 Subject: [PATCH 3/9] refactor(composer): Remove redundancy in scope construction Signed-off-by: Frank Viernau --- .../package-managers/composer/src/main/kotlin/Composer.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index e49066c37259c..b706afa29c352 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -63,6 +63,7 @@ private const val COMPOSER_PHAR_BINARY = "composer.phar" private const val COMPOSER_LOCK_FILE = "composer.lock" private const val SCOPE_NAME_REQUIRE = "require" private const val SCOPE_NAME_REQUIRE_DEV = "require-dev" +private val ALL_SCOPE_NAMES = setOf(SCOPE_NAME_REQUIRE, SCOPE_NAME_REQUIRE_DEV) /** * The [Composer](https://getcomposer.org/) package manager for PHP. @@ -145,10 +146,9 @@ class Composer( // the "replacing" package. val virtualPackages = parseVirtualPackageNames(packages, manifest, json) - val scopes = setOf( - parseScope(SCOPE_NAME_REQUIRE, manifest, json, packages, virtualPackages), - parseScope(SCOPE_NAME_REQUIRE_DEV, manifest, json, packages, virtualPackages) - ) + val scopes = ALL_SCOPE_NAMES.mapTo(mutableSetOf()) { scopeName -> + parseScope(scopeName, manifest, json, packages, virtualPackages) + } val project = parseProject(definitionFile, scopes) val result = ProjectAnalyzerResult(project, packages.values.toSet()) From 7b4739227249c500b4a1706e1e07b65abb64dafd Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Tue, 23 Jul 2024 23:46:27 +0200 Subject: [PATCH 4/9] refactor(composer): Use data classes for the deserialization Prepare for the porting from Jackson to KxS. Signed-off-by: Frank Viernau --- .../composer/build.gradle.kts | 2 + .../composer/src/main/kotlin/Composer.kt | 172 ++++++++---------- .../composer/src/main/kotlin/Model.kt | 77 ++++++++ 3 files changed, 156 insertions(+), 95 deletions(-) create mode 100644 plugins/package-managers/composer/src/main/kotlin/Model.kt diff --git a/plugins/package-managers/composer/build.gradle.kts b/plugins/package-managers/composer/build.gradle.kts index aa6b690f003bf..9a4976a9ca903 100644 --- a/plugins/package-managers/composer/build.gradle.kts +++ b/plugins/package-managers/composer/build.gradle.kts @@ -37,7 +37,9 @@ dependencies { implementation(projects.utils.ortUtils) implementation(projects.utils.spdxUtils) + implementation(libs.jackson.core) implementation(libs.jackson.databind) + implementation(libs.jackson.module.kotlin) funTestImplementation(testFixtures(projects.analyzer)) } diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index b706afa29c352..f295f9c07460b 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -19,9 +19,6 @@ package org.ossreviewtoolkit.plugins.packagemanagers.composer -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.node.ObjectNode - import java.io.File import java.io.IOException @@ -43,16 +40,11 @@ import org.ossreviewtoolkit.model.VcsType import org.ossreviewtoolkit.model.config.AnalyzerConfiguration import org.ossreviewtoolkit.model.config.RepositoryConfiguration import org.ossreviewtoolkit.model.createAndLogIssue -import org.ossreviewtoolkit.model.jsonMapper import org.ossreviewtoolkit.model.orEmpty -import org.ossreviewtoolkit.model.readTree import org.ossreviewtoolkit.utils.common.CommandLineTool import org.ossreviewtoolkit.utils.common.Os import org.ossreviewtoolkit.utils.common.collectMessages -import org.ossreviewtoolkit.utils.common.fieldNamesOrEmpty -import org.ossreviewtoolkit.utils.common.isNotEmpty import org.ossreviewtoolkit.utils.common.splitOnWhitespace -import org.ossreviewtoolkit.utils.common.textValueOrEmpty import org.ossreviewtoolkit.utils.ort.showStackTrace import org.semver4j.RangesList @@ -119,10 +111,8 @@ class Composer( override fun resolveDependencies(definitionFile: File, labels: Map): List { val workingDir = definitionFile.parentFile - val manifest = definitionFile.readTree() - val hasDependencies = manifest.fields().asSequence().any { (key, value) -> - key.startsWith("require") && value.isNotEmpty() - } + val projectPackageInfo = parsePackageInfo(definitionFile.readText()) + val hasDependencies = projectPackageInfo.require.isNotEmpty() if (!hasDependencies) { val project = parseProject(definitionFile, scopes = emptySet()) @@ -131,12 +121,12 @@ class Composer( return listOf(result) } - val lockfile = ensureLockfile(workingDir) - - logger.info { "Parsing lockfile at '$lockfile'..." } + val lockfile = ensureLockfile(workingDir).let { + logger.info { "Parsing lockfile at '$it'..." } + parseLockfile(it.readText()) + } - val json = jsonMapper.readTree(lockfile) - val packages = parseInstalledPackages(json) + val packages = parseInstalledPackages(lockfile) // Let's also determine the "virtual" (replaced and provided) packages. These can be declared as // required, but are not listed in composer.lock as installed. @@ -144,10 +134,10 @@ class Composer( // dependency information for them. We can't simply put these "virtual" packages in the normal package // map as this would cause us to report a package which is not actually installed with the contents of // the "replacing" package. - val virtualPackages = parseVirtualPackageNames(packages, manifest, json) + val virtualPackages = parseVirtualPackageNames(packages, projectPackageInfo, lockfile) val scopes = ALL_SCOPE_NAMES.mapTo(mutableSetOf()) { scopeName -> - parseScope(scopeName, manifest, json, packages, virtualPackages) + parseScope(scopeName, projectPackageInfo, lockfile, packages, virtualPackages) } val project = parseProject(definitionFile, scopes) @@ -158,19 +148,19 @@ class Composer( private fun parseScope( scopeName: String, - manifest: JsonNode, - lockfile: JsonNode, + projectPackageInfo: PackageInfo, + lockfile: Lockfile, packages: Map, virtualPackages: Set ): Scope { - val requiredPackages = manifest[scopeName].fieldNamesOrEmpty().asSequence() + val requiredPackages = projectPackageInfo.getScopeDependencies(scopeName) val dependencies = buildDependencyTree(requiredPackages, lockfile, packages, virtualPackages) return Scope(scopeName, dependencies) } private fun buildDependencyTree( - dependencies: Sequence, - lockfile: JsonNode, + dependencies: Set, + lockfile: Lockfile, packages: Map, virtualPackages: Set, dependencyBranch: List = emptyList() @@ -218,10 +208,10 @@ class Composer( private fun parseProject(definitionFile: File, scopes: Set): Project { logger.info { "Parsing project metadata from '$definitionFile'..." } - val json = definitionFile.readTree() - val homepageUrl = json["homepage"].textValueOrEmpty() - val vcs = parseVcsInfo(json) - val rawName = json["name"]?.textValue() + val pkgInfo = parsePackageInfo(definitionFile.readText()) + val homepageUrl = pkgInfo.homepage.orEmpty() + val vcs = parseVcsInfo(pkgInfo) + val rawName = pkgInfo.name val namespace = rawName?.substringBefore("/", missingDelimiterValue = "").orEmpty() val name = rawName?.substringAfter("/") ?: getFallbackProjectName(analysisRoot, definitionFile) @@ -230,11 +220,11 @@ class Composer( type = managerName, namespace = namespace, name = name, - version = json["version"].textValueOrEmpty() + version = pkgInfo.version.orEmpty() ), definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path, - authors = parseAuthors(json), - declaredLicenses = parseDeclaredLicenses(json), + authors = parseAuthors(pkgInfo), + declaredLicenses = parseDeclaredLicenses(pkgInfo), vcs = vcs, vcsProcessed = processProjectVcs(definitionFile.parentFile, vcs, homepageUrl), homepageUrl = homepageUrl, @@ -242,39 +232,37 @@ class Composer( ) } - private fun parseInstalledPackages(json: JsonNode): Map { + private fun parseInstalledPackages(lockfile: Lockfile): Map { val packages = mutableMapOf() - listOf("packages", "packages-dev").forEach { - json[it]?.forEach { pkgInfo -> - val rawName = pkgInfo["name"].textValue() - val version = pkgInfo["version"].textValueOrEmpty() - val homepageUrl = pkgInfo["homepage"].textValueOrEmpty() - val vcsFromPackage = parseVcsInfo(pkgInfo) - - // Just warn if the version is missing as Composer itself declares it as optional, see - // https://getcomposer.org/doc/04-schema.md#version. - if (version.isEmpty()) { - logger.warn { "No version information found for package $rawName." } - } + (lockfile.packages + lockfile.packagesDev).forEach { pkgInfo -> + val rawName = checkNotNull(pkgInfo.name) + val version = pkgInfo.version.orEmpty() + val homepageUrl = pkgInfo.homepage.orEmpty() + val vcsFromPackage = parseVcsInfo(pkgInfo) - packages[rawName] = Package( - id = Identifier( - type = managerName, - namespace = rawName.substringBefore('/'), - name = rawName.substringAfter('/'), - version = version - ), - authors = parseAuthors(pkgInfo), - declaredLicenses = parseDeclaredLicenses(pkgInfo), - description = pkgInfo["description"].textValueOrEmpty(), - homepageUrl = homepageUrl, - binaryArtifact = RemoteArtifact.EMPTY, - sourceArtifact = parseArtifact(pkgInfo), - vcs = vcsFromPackage, - vcsProcessed = processPackageVcs(vcsFromPackage, homepageUrl) - ) + // Just warn if the version is missing as Composer itself declares it as optional, see + // https://getcomposer.org/doc/04-schema.md#version. + if (version.isEmpty()) { + logger.warn { "No version information found for package $rawName." } } + + packages[rawName] = Package( + id = Identifier( + type = managerName, + namespace = rawName.substringBefore('/'), + name = rawName.substringAfter('/'), + version = version + ), + authors = parseAuthors(pkgInfo), + declaredLicenses = parseDeclaredLicenses(pkgInfo), + description = pkgInfo.description.orEmpty(), + homepageUrl = homepageUrl, + binaryArtifact = RemoteArtifact.EMPTY, + sourceArtifact = parseArtifact(pkgInfo), + vcs = vcsFromPackage, + vcsProcessed = processPackageVcs(vcsFromPackage, homepageUrl) + ) } return packages @@ -310,39 +298,32 @@ private fun String.isPlatformDependency(): Boolean = private val COMPOSER_PLATFORM_TYPES = setOf("composer", "composer-plugin-api", "composer-runtime-api") private val PHP_PLATFORM_TYPES = setOf("php", "php-64bit", "php-ipv6", "php-zts", "php-debug") -private fun getRuntimeDependencies(packageName: String, lockfile: JsonNode): Sequence { - listOf("packages", "packages-dev").forEach { - lockfile[it]?.forEach { packageInfo -> - if (packageInfo["name"].textValueOrEmpty() == packageName) { - val requiredPackages = packageInfo["require"] - if (requiredPackages != null && requiredPackages.isObject) { - return (requiredPackages as ObjectNode).fieldNames().asSequence() - } - } +private fun getRuntimeDependencies(packageName: String, lockfile: Lockfile): Set { + (lockfile.packages + lockfile.packagesDev).forEach { packageInfo -> + if (packageInfo.name == packageName) { + return packageInfo.require.keys } } - return emptySequence() + return emptySet() } -private fun parseArtifact(packageInfo: JsonNode): RemoteArtifact = - packageInfo["dist"]?.let { - val shasum = it["shasum"].textValueOrEmpty() - RemoteArtifact(it["url"].textValueOrEmpty(), Hash.create(shasum)) +private fun parseArtifact(packageInfo: PackageInfo): RemoteArtifact = + packageInfo.dist?.let { + RemoteArtifact(url = it.url.orEmpty(), hash = Hash.create(it.shasum.orEmpty())) }.orEmpty() -private fun parseAuthors(packageInfo: JsonNode): Set = - packageInfo["authors"]?.mapNotNullTo(mutableSetOf()) { it["name"]?.textValue() }.orEmpty() +private fun parseAuthors(packageInfo: PackageInfo): Set = + packageInfo.authors.mapNotNullTo(mutableSetOf()) { it.name } -private fun parseDeclaredLicenses(packageInfo: JsonNode): Set = - packageInfo["license"]?.mapNotNullTo(mutableSetOf()) { it.textValue() }.orEmpty() +private fun parseDeclaredLicenses(packageInfo: PackageInfo): Set = packageInfo.license.toSet() -private fun parseVcsInfo(packageInfo: JsonNode): VcsInfo = - packageInfo["source"]?.let { +private fun parseVcsInfo(packageInfo: PackageInfo): VcsInfo = + packageInfo.source?.let { VcsInfo( - type = VcsType.forName(it["type"].textValueOrEmpty()), - url = it["url"].textValueOrEmpty(), - revision = it["reference"].textValueOrEmpty() + type = VcsType.forName(it.type.orEmpty()), + url = it.url.orEmpty(), + revision = it.reference.orEmpty() ) }.orEmpty() @@ -357,27 +338,28 @@ private fun parseVcsInfo(packageInfo: JsonNode): VcsInfo = */ private fun parseVirtualPackageNames( packages: Map, - manifest: JsonNode, - lockfile: JsonNode + projectPackageInfo: PackageInfo, + lockfile: Lockfile ): Set { val replacedNames = mutableSetOf() // The contents of the manifest file, which can also define replacements, is not included in the lockfile, so // we parse the manifest file as well. - replacedNames += parseVirtualNames(manifest) + replacedNames += parseVirtualNames(projectPackageInfo) - listOf("packages", "packages-dev").forEach { type -> - lockfile[type]?.flatMap { pkgInfo -> - parseVirtualNames(pkgInfo) - }?.let { - replacedNames += it - } + (lockfile.packages + lockfile.packagesDev).forEach { pkgInfo -> + replacedNames += parseVirtualNames(pkgInfo) } return replacedNames - packages.keys } -private fun parseVirtualNames(packageInfo: JsonNode): Set = - listOf("replace", "provide").flatMapTo(mutableSetOf()) { - packageInfo[it]?.fieldNames()?.asSequence().orEmpty() +private fun parseVirtualNames(packageInfo: PackageInfo): Set = + packageInfo.replace.keys + packageInfo.provide.keys + +private fun PackageInfo.getScopeDependencies(scopeName: String): Set = + when (scopeName) { + SCOPE_NAME_REQUIRE -> require.keys + SCOPE_NAME_REQUIRE_DEV -> requireDev.keys + else -> error("Invalid scope name: '$scopeName'.") } diff --git a/plugins/package-managers/composer/src/main/kotlin/Model.kt b/plugins/package-managers/composer/src/main/kotlin/Model.kt new file mode 100644 index 0000000000000..0acb229f40d2a --- /dev/null +++ b/plugins/package-managers/composer/src/main/kotlin/Model.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024 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 + */ + +package org.ossreviewtoolkit.plugins.packagemanagers.composer + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.module.kotlin.readValue + +import org.ossreviewtoolkit.model.jsonMapper + +@JsonIgnoreProperties(ignoreUnknown = true) +data class Lockfile( + val packages: List = emptyList(), + @JsonProperty("packages-dev") + val packagesDev: List = emptyList() +) + +@JsonIgnoreProperties(ignoreUnknown = true) +data class PackageInfo( + val name: String?, + val version: String?, + val homepage: String?, + val description: String?, + val source: Source? = null, + val authors: List = emptyList(), + val license: List = emptyList(), + val provide: Map = emptyMap(), + val replace: Map = emptyMap(), + val require: Map = emptyMap(), + @JsonProperty("require-dev") + val requireDev: Map = emptyMap(), + val dist: Dist? = null +) { + @JsonIgnoreProperties(ignoreUnknown = true) + data class Author( + val name: String? = null, + val email: String? = null, + val homepage: String? = null, + val role: String? = null + ) + + @JsonIgnoreProperties(ignoreUnknown = true) + data class Source( + val type: String? = null, + val url: String? = null, + val reference: String? = null + ) + + @JsonIgnoreProperties(ignoreUnknown = true) + data class Dist( + val type: String?, + val url: String?, + val reference: String?, + val shasum: String? + ) +} + +fun parseLockfile(json: String): Lockfile = jsonMapper.readValue(json) + +fun parsePackageInfo(json: String): PackageInfo = jsonMapper.readValue(json) From 6b92df4537e4e4e893100f8fb0a1edd0e9e04683 Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Tue, 23 Jul 2024 23:56:17 +0200 Subject: [PATCH 5/9] fix(composer): Do not use the `managerName` for packages The `managerName` is meant to be used only for the `Identifier.type` of `Project`s. Signed-off-by: Frank Viernau --- plugins/package-managers/composer/src/main/kotlin/Composer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index f295f9c07460b..a12e1a9ea823d 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -249,7 +249,7 @@ class Composer( packages[rawName] = Package( id = Identifier( - type = managerName, + type = "Composer", namespace = rawName.substringBefore('/'), name = rawName.substringAfter('/'), version = version From 18bf4edd1b0582764334fc251547fdf5f5faec71 Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Wed, 24 Jul 2024 00:00:18 +0200 Subject: [PATCH 6/9] chore(composer): Remove an uncessary log warning The warning is not necessary because it is not actionable. So, remove it to simplify an upcoming change. Signed-off-by: Frank Viernau --- .../package-managers/composer/src/main/kotlin/Composer.kt | 6 ------ plugins/package-managers/composer/src/main/kotlin/Model.kt | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index a12e1a9ea823d..fe12279d64c0a 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -241,12 +241,6 @@ class Composer( val homepageUrl = pkgInfo.homepage.orEmpty() val vcsFromPackage = parseVcsInfo(pkgInfo) - // Just warn if the version is missing as Composer itself declares it as optional, see - // https://getcomposer.org/doc/04-schema.md#version. - if (version.isEmpty()) { - logger.warn { "No version information found for package $rawName." } - } - packages[rawName] = Package( id = Identifier( type = "Composer", diff --git a/plugins/package-managers/composer/src/main/kotlin/Model.kt b/plugins/package-managers/composer/src/main/kotlin/Model.kt index 0acb229f40d2a..e67c1cdaf3497 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Model.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Model.kt @@ -35,6 +35,7 @@ data class Lockfile( @JsonIgnoreProperties(ignoreUnknown = true) data class PackageInfo( val name: String?, + // See https://getcomposer.org/doc/04-schema.md#version. val version: String?, val homepage: String?, val description: String?, From a3c8dd64e5b07f19dae095e10929df3a44ffbfb2 Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Wed, 24 Jul 2024 00:07:47 +0200 Subject: [PATCH 7/9] refactor(composer): Factor out `PackageInfo.toPackage()` Improve the readability. Signed-off-by: Frank Viernau --- .../composer/src/main/kotlin/Composer.kt | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index fe12279d64c0a..adddde04d3464 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -26,6 +26,7 @@ import org.apache.logging.log4j.kotlin.logger import org.ossreviewtoolkit.analyzer.AbstractPackageManagerFactory import org.ossreviewtoolkit.analyzer.PackageManager +import org.ossreviewtoolkit.analyzer.PackageManager.Companion.processPackageVcs import org.ossreviewtoolkit.downloader.VersionControlSystem import org.ossreviewtoolkit.model.Hash import org.ossreviewtoolkit.model.Identifier @@ -232,35 +233,11 @@ class Composer( ) } - private fun parseInstalledPackages(lockfile: Lockfile): Map { - val packages = mutableMapOf() - - (lockfile.packages + lockfile.packagesDev).forEach { pkgInfo -> - val rawName = checkNotNull(pkgInfo.name) - val version = pkgInfo.version.orEmpty() - val homepageUrl = pkgInfo.homepage.orEmpty() - val vcsFromPackage = parseVcsInfo(pkgInfo) - - packages[rawName] = Package( - id = Identifier( - type = "Composer", - namespace = rawName.substringBefore('/'), - name = rawName.substringAfter('/'), - version = version - ), - authors = parseAuthors(pkgInfo), - declaredLicenses = parseDeclaredLicenses(pkgInfo), - description = pkgInfo.description.orEmpty(), - homepageUrl = homepageUrl, - binaryArtifact = RemoteArtifact.EMPTY, - sourceArtifact = parseArtifact(pkgInfo), - vcs = vcsFromPackage, - vcsProcessed = processPackageVcs(vcsFromPackage, homepageUrl) - ) - } - - return packages - } + private fun parseInstalledPackages(lockfile: Lockfile): Map = + (lockfile.packages + lockfile.packagesDev).associateBy( + { checkNotNull(it.name) }, + { it.toPackage() } + ) private fun ensureLockfile(workingDir: File): File { val lockfile = workingDir.resolve(COMPOSER_LOCK_FILE) @@ -351,6 +328,30 @@ private fun parseVirtualPackageNames( private fun parseVirtualNames(packageInfo: PackageInfo): Set = packageInfo.replace.keys + packageInfo.provide.keys +private fun PackageInfo.toPackage(): Package { + val rawName = checkNotNull(name) + val version = version.orEmpty() + val homepageUrl = homepage.orEmpty() + val vcsFromPackage = parseVcsInfo(this) + + return Package( + id = Identifier( + type = "Composer", + namespace = rawName.substringBefore('/'), + name = rawName.substringAfter('/'), + version = version + ), + authors = parseAuthors(this), + declaredLicenses = parseDeclaredLicenses(this), + description = description.orEmpty(), + homepageUrl = homepageUrl, + binaryArtifact = RemoteArtifact.EMPTY, + sourceArtifact = parseArtifact(this), + vcs = vcsFromPackage, + vcsProcessed = processPackageVcs(vcsFromPackage, homepageUrl) + ) +} + private fun PackageInfo.getScopeDependencies(scopeName: String): Set = when (scopeName) { SCOPE_NAME_REQUIRE -> require.keys From 900d04557b2097471fad8fcb1366b319a55abfc4 Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Wed, 24 Jul 2024 00:25:30 +0200 Subject: [PATCH 8/9] refactor(composer): Simplify `parseVirtualPackageNames()` While at it, inline `ParseVirtualNames()`. Signed-off-by: Frank Viernau --- .../composer/src/main/kotlin/Composer.kt | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index adddde04d3464..569603476ec37 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -311,23 +311,17 @@ private fun parseVirtualPackageNames( packages: Map, projectPackageInfo: PackageInfo, lockfile: Lockfile -): Set { - val replacedNames = mutableSetOf() - - // The contents of the manifest file, which can also define replacements, is not included in the lockfile, so - // we parse the manifest file as well. - replacedNames += parseVirtualNames(projectPackageInfo) +): Set = + buildSet { + // The contents of the manifest file, which can also define replacements, is not included in the lockfile, so + // we parse the manifest file as well. + (lockfile.packages + lockfile.packagesDev + projectPackageInfo).flatMapTo(this) { + it.replace.keys + it.provide.keys + } - (lockfile.packages + lockfile.packagesDev).forEach { pkgInfo -> - replacedNames += parseVirtualNames(pkgInfo) + removeAll(packages.keys) } - return replacedNames - packages.keys -} - -private fun parseVirtualNames(packageInfo: PackageInfo): Set = - packageInfo.replace.keys + packageInfo.provide.keys - private fun PackageInfo.toPackage(): Package { val rawName = checkNotNull(name) val version = version.orEmpty() From caed84406da44a06241c34c8b0c7095e875536e1 Mon Sep 17 00:00:00 2001 From: Frank Viernau Date: Wed, 24 Jul 2024 00:29:38 +0200 Subject: [PATCH 9/9] refactor(composer): Inline `parseArtifact()` Signed-off-by: Frank Viernau --- .../composer/src/main/kotlin/Composer.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/package-managers/composer/src/main/kotlin/Composer.kt b/plugins/package-managers/composer/src/main/kotlin/Composer.kt index 569603476ec37..e0b9201cc77b9 100644 --- a/plugins/package-managers/composer/src/main/kotlin/Composer.kt +++ b/plugins/package-managers/composer/src/main/kotlin/Composer.kt @@ -279,11 +279,6 @@ private fun getRuntimeDependencies(packageName: String, lockfile: Lockfile): Set return emptySet() } -private fun parseArtifact(packageInfo: PackageInfo): RemoteArtifact = - packageInfo.dist?.let { - RemoteArtifact(url = it.url.orEmpty(), hash = Hash.create(it.shasum.orEmpty())) - }.orEmpty() - private fun parseAuthors(packageInfo: PackageInfo): Set = packageInfo.authors.mapNotNullTo(mutableSetOf()) { it.name } @@ -340,7 +335,12 @@ private fun PackageInfo.toPackage(): Package { description = description.orEmpty(), homepageUrl = homepageUrl, binaryArtifact = RemoteArtifact.EMPTY, - sourceArtifact = parseArtifact(this), + sourceArtifact = dist?.let { + RemoteArtifact( + url = it.url.orEmpty(), + hash = Hash.create(it.shasum.orEmpty()) + ) + }.orEmpty(), vcs = vcsFromPackage, vcsProcessed = processPackageVcs(vcsFromPackage, homepageUrl) )