Skip to content

Commit

Permalink
refactor(conan): Simplify the parsing of Conandata
Browse files Browse the repository at this point in the history
Signed-off-by: Frank Viernau <[email protected]>
  • Loading branch information
fviernau committed Jul 18, 2024
1 parent f7ff51a commit 078c153
Showing 1 changed file with 35 additions and 37 deletions.
72 changes: 35 additions & 37 deletions plugins/package-managers/conan/src/main/kotlin/Conan.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package org.ossreviewtoolkit.plugins.packagemanagers.conan

import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlList
import com.charleskorn.kaml.YamlMap
import com.charleskorn.kaml.YamlNode
import com.charleskorn.kaml.YamlScalar
import com.charleskorn.kaml.yamlList
Expand Down Expand Up @@ -303,7 +305,7 @@ class Conan(
val homepageUrl = pkgInfo.homepage.orEmpty()

val id = parsePackageId(pkgInfo, workingDir)
val conanData = readConanData(id)
val conanData = readConanData(id.name, id.version, conanStoragePath)

return Package(
id = id,
Expand All @@ -314,7 +316,7 @@ class Conan(
binaryArtifact = RemoteArtifact.EMPTY, // TODO: implement me!
sourceArtifact = parseSourceArtifact(conanData),
vcs = processPackageVcs(VcsInfo.EMPTY, homepageUrl),
isModified = "patches" in conanData
isModified = conanData.hasPatches
)
}

Expand Down Expand Up @@ -372,46 +374,17 @@ class Conan(
private fun parsePackageField(pkgInfo: PackageInfo, workingDir: File, field: String): String =
inspectField(pkgInfo.displayName, workingDir, field)

/**
* Return the generic map of Conan data for the [id].
*/
private fun readConanData(id: Identifier): Map<String, YamlNode> {
val conanDataFile = conanStoragePath.resolve("${id.name}/${id.version}/_/_/export/conandata.yml")

return runCatching {
val conanData = Yaml.default.parseToYamlNode(conanDataFile.readText()).yamlMap.entries.mapKeys {
it.key.content
}

// Replace metadata for all version with metadata for this specific version for convenient access.
conanData.mapNotNull { (key, value) ->
key to when (key) {
"patches", "sources" -> value.yamlMap[id.version] ?: return@mapNotNull null
else -> value
}
}.toMap()
}.getOrDefault(emptyMap())
}

/**
* Return the source artifact contained in [conanData], or [RemoteArtifact.EMPTY] if no source artifact is
* available.
*/
private fun parseSourceArtifact(conanData: Map<String, YamlNode>): RemoteArtifact =
runCatching {
val artifactEntry = conanData.getValue("sources").yamlMap

val url = checkNotNull(artifactEntry.get("url")).let { urlNode ->
urlNode.takeIf { it is YamlScalar } ?: urlNode.yamlList.items.first()
}.yamlScalar.content
private fun parseSourceArtifact(conanData: ConanData): RemoteArtifact {
val url = conanData.url ?: return RemoteArtifact.EMPTY
val hashValue = conanData.sha256.orEmpty()
val hash = Hash.NONE.takeIf { hashValue.isEmpty() } ?: Hash.create(hashValue, HashAlgorithm.SHA256.name)

val hashValue = artifactEntry.get<YamlScalar>("sha256")?.content.orEmpty()
val hash = Hash.create(hashValue, HashAlgorithm.SHA256.name)

RemoteArtifact(url, hash)
}.getOrElse {
RemoteArtifact.EMPTY
}
return RemoteArtifact(url, hash)
}

/**
* Return a [Package] containing project-level information from [pkgInfo] and [definitionFile] using the
Expand Down Expand Up @@ -450,3 +423,28 @@ class Conan(
private fun parseAuthors(pkgInfo: PackageInfo): Set<String> =
setOfNotNull(parseAuthorString(pkgInfo.author.orEmpty(), '<', '('))
}

private data class ConanData(
val url: String?,
val sha256: String?,
val hasPatches: Boolean
)

private fun readConanData(name: String, version: String, conanStorageDir: File): ConanData {
val conanDataFile = conanStorageDir.resolve("$name/$version/_/_/export/conandata.yml")

val root = Yaml.default.parseToYamlNode(conanDataFile.readText()).yamlMap
val sourceForVersion = root.get<YamlMap>("sources")?.get<YamlMap>(version)
val patchesForVersion = root.get<YamlMap>("patches")?.get<YamlList>(version)

val sha256 = sourceForVersion?.get<YamlScalar>("sha256")?.content
val hasPatches = patchesForVersion?.items.orEmpty().isNotEmpty()
val url = sourceForVersion?.get<YamlNode>("url")?.let {
when {
it is YamlList -> it.yamlList.items.firstOrNull()?.yamlScalar?.content
else -> it.yamlScalar.content
}
}

return ConanData(url, sha256, hasPatches)
}

0 comments on commit 078c153

Please sign in to comment.