Skip to content

Commit

Permalink
refactor(pub): Port the lockfile parsing to KxS
Browse files Browse the repository at this point in the history
Signed-off-by: Frank Viernau <frank_viernau@epam.com>
Signed-off-by: Sebastian Schuberth <sebastian@doubleopen.org>
  • Loading branch information
sschuberth committed Oct 15, 2024
1 parent 0d99de2 commit 831b113
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 30 deletions.
3 changes: 0 additions & 3 deletions plugins/package-managers/pub/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ dependencies {
implementation(projects.utils.ortUtils)
implementation(projects.utils.spdxUtils)

implementation(libs.jackson.databind)
implementation(libs.jackson.dataformat.yaml)
implementation(libs.jackson.module.kotlin)
implementation(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.yaml)

Expand Down
67 changes: 46 additions & 21 deletions plugins/package-managers/pub/src/main/kotlin/Lockfile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,59 +19,84 @@

package org.ossreviewtoolkit.plugins.packagemanagers.pub

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.module.kotlin.readValue
import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import com.charleskorn.kaml.YamlInput
import com.charleskorn.kaml.YamlScalar

import java.io.File

import org.ossreviewtoolkit.model.yamlMapper
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.KeepGeneratedSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.SerialKind
import kotlinx.serialization.descriptors.buildSerialDescriptor
import kotlinx.serialization.encoding.Decoder

import org.ossreviewtoolkit.plugins.packagemanagers.pub.PackageInfo.Description

internal fun parseLockfile(lockfile: File) = yamlMapper.readValue<Lockfile>(lockfile)
private val YAML = Yaml(configuration = YamlConfiguration(strictMode = false))

internal fun parseLockfile(lockfile: File) = YAML.decodeFromString<Lockfile>(lockfile.readText())

/**
* See https://github.com/dart-lang/pub/blob/d86e3c979a3889fed61b68dae9f9156d0891704d/lib/src/lock_file.dart#L18.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@Serializable
internal data class Lockfile(
val packages: Map<String, PackageInfo> = emptyMap()
)

/**
* See https://github.com/dart-lang/pub/blob/d86e3c979a3889fed61b68dae9f9156d0891704d/lib/src/package_name.dart#L73.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@Serializable
internal data class PackageInfo(
val dependency: String,
@JsonDeserialize(using = DescriptionDeserializer::class)
val description: Description,
val source: String? = null,
val version: String? = null
) {
@JsonIgnoreProperties(ignoreUnknown = true)
@KeepGeneratedSerializer
@Serializable(DescriptionDeserializer::class)
data class Description(
val name: String? = null,
val url: String? = null,
val path: String? = null,
@JsonProperty("resolved-ref")
@SerialName("resolved-ref")
val resolvedRef: String? = null,
val relative: Boolean? = null,
val sha256: String? = null
)
}

internal class DescriptionDeserializer : StdDeserializer<Description>(Description::class.java) {
override fun deserialize(parser: JsonParser, context: DeserializationContext): Description {
val node = context.readTree(parser)
return if (node.isTextual) {
Description(name = node.textValue())
} else {
parser.codec.readValue(node.traverse(), Description::class.java)
private class DescriptionDeserializer : KSerializer<Description> by Description.generatedSerializer() {
@OptIn(InternalSerializationApi::class)
override val descriptor: SerialDescriptor by lazy {
val serialName = checkNotNull(Description::class.qualifiedName)

buildSerialDescriptor(serialName, SerialKind.CONTEXTUAL) {
element("object", Description.generatedSerializer().descriptor)
element("string", PrimitiveSerialDescriptor("description", PrimitiveKind.STRING))
}
}

override fun deserialize(decoder: Decoder): Description {
val input = decoder.beginStructure(descriptor) as YamlInput

val result = when (val node = input.node) {
is YamlScalar -> Description(name = node.content)
else -> Description.generatedSerializer().deserialize(decoder)
}

input.endStructure(descriptor)

return result
}
}
10 changes: 4 additions & 6 deletions plugins/package-managers/pub/src/main/kotlin/Pub.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

package org.ossreviewtoolkit.plugins.packagemanagers.pub

import com.fasterxml.jackson.dataformat.yaml.JacksonYAMLParseException

import java.io.File
import java.io.IOException

Expand Down Expand Up @@ -535,7 +533,7 @@ class Pub(
var containsFlutter = false

lockfile.packages.forEach { (packageName, packageInfo) ->
try {
runCatching {
val version = packageInfo.version.orEmpty()
var description = ""
var rawName = ""
Expand Down Expand Up @@ -646,14 +644,14 @@ class Pub(
vcs = vcs,
vcsProcessed = processPackageVcs(vcs, homepageUrl)
)
} catch (e: JacksonYAMLParseException) {
e.showStackTrace()
}.onFailure {
it.showStackTrace()

val packageVersion = packageInfo.version
issues += createAndLogIssue(
source = managerName,
message = "Failed to parse $PUBSPEC_YAML for package $packageName:$packageVersion: " +
e.collectMessages()
it.collectMessages()
)
}
}
Expand Down

0 comments on commit 831b113

Please sign in to comment.