Skip to content

Commit

Permalink
refactor(opossum reporter): adjust file structure
Browse files Browse the repository at this point in the history
Put public method at the top, put caller above callees
etc.

Signed-off-by: alexzurbonsen <[email protected]>
  • Loading branch information
alexzurbonsen committed Nov 21, 2024
1 parent 474621b commit 98ee401
Showing 1 changed file with 151 additions and 147 deletions.
298 changes: 151 additions & 147 deletions plugins/reporters/opossum/src/main/kotlin/OpossumReporter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -107,142 +107,35 @@ class OpossumReporter(
override val descriptor: PluginDescriptor = OpossumReporterFactory.descriptor,
private val config: OpossumReporterConfig
) : Reporter {
@Serializable
internal data class OpossumSignal(
@Transient
val uuid: UUID = UUID.randomUUID(),
val source: OpossumSignalSource,
val attributionConfidence: Int = 80,
val packageType: String?,
val packageNamespace: String?,
val packageName: String?,
val packageVersion: String?,
val copyright: String?,
val licenseName: String?,
val url: String?,
val preSelected: Boolean,
val followUp: OpossumFollowUp?,
val excludeFromNotice: Boolean,
val comment: String?
) {
companion object {
fun create(
source: String,
id: Identifier? = null,
url: String? = null,
license: SpdxExpression? = null,
copyright: String? = null,
comment: String? = null,
preSelected: Boolean = false,
followUp: Boolean = false,
excludeFromNotice: Boolean = false
): OpossumSignal {
return OpossumSignal(
source = OpossumSignalSource(name = source),
packageType = id?.getPurlType(),
packageNamespace = id?.namespace,
packageName = id?.name,
packageVersion = id?.version,
copyright = copyright,
licenseName = license?.toString(),
url = url,
preSelected = preSelected,
followUp = OpossumFollowUp.FOLLOW_UP.takeIf { followUp },
excludeFromNotice = excludeFromNotice,
comment = comment,
)
override fun generateReport(input: ReporterInput, outputDir: File): List<Result<File>> {
val reportFileResult = runCatching {
val opossumInput = createOpossumInput(input, config.maxDepth)

outputDir.resolve("report.opossum").also {
writeReport(it, opossumInput)
}
}

fun matches(other: OpossumSignal): Boolean =
source == other.source
&& packageType == other.packageType
&& packageNamespace == other.packageNamespace
&& packageName == other.packageName
&& packageVersion == other.packageVersion
&& copyright == other.copyright
&& licenseName == other.licenseName
&& url == other.url
&& preSelected == other.preSelected
&& comment == other.comment
return listOf(reportFileResult)
}

@Serializable
internal data class OpossumSignalSource(
val name: String,
val documentConfidence: Int = 80,
)

@Serializable
internal enum class OpossumFollowUp {
FOLLOW_UP,
private fun createOpossumInput(input: ReporterInput, maxDepth: Int = Int.MAX_VALUE): OpossumInput {
return OpossumInputCreator().create(input, maxDepth)
}

@Serializable(with = OpossumResourcesSerializer::class)
internal data class OpossumResources(
val tree: MutableMap<String, OpossumResources> = mutableMapOf()
) {
private fun addResource(pathPieces: List<String>) {
if (pathPieces.isEmpty()) return

val head = pathPieces.first()
val tail = pathPieces.drop(1)

if (head !in tree) tree[head] = OpossumResources()
tree.getValue(head).addResource(tail)
}

fun addResource(path: String) {
val pathPieces = path.split("/").filter { it.isNotEmpty() }

addResource(pathPieces)
}

fun isFile() = tree.isEmpty()

fun isPathAFile(path: String): Boolean {
val pathPieces = path.split("/").filter { it.isNotEmpty() }

return isPathAFile(pathPieces)
}

private fun isPathAFile(pathPieces: List<String>): Boolean {
if (pathPieces.isEmpty()) return isFile()

val head = pathPieces.first()
val tail = pathPieces.drop(1)

return head !in tree || tree.getValue(head).isPathAFile(tail)
private fun writeReport(outputFile: File, opossumInput: OpossumInput) {
val jsonFile = createOrtTempDir().resolve("input.json")
val json = Json {
explicitNulls = false
encodeDefaults = true
}

fun toFileList(): Set<String> =
tree.flatMapTo(mutableSetOf()) { (key, value) ->
value.toFileList().map { resolvePath(key, it, isDirectory = false) }
}.plus("/")
}
jsonFile.writeText(json.encodeToString(OpossumInput.serializer(), opossumInput))

@Serializable
internal data class OpossumFrequentLicense(
val shortName: String,
val fullName: String?,
val defaultText: String?
) : Comparable<OpossumFrequentLicense> {
override fun compareTo(other: OpossumFrequentLicense) =
compareValuesBy(
this,
other,
{ it.shortName },
{ it.fullName },
{ it.defaultText }
)
jsonFile.packZip(outputFile)
jsonFile.delete()
}

@Serializable
internal data class OpossumExternalAttributionSource(
val name: String,
val priority: Int
)

@Serializable

Check warning

Code scanning / detekt

The more parameters a function has the more complex it is. Long parameter lists are often used to control complex algorithms and violate the Single Responsibility Principle. Prefer functions with short parameter lists. Warning

The function create(source: String, id: Identifier?, url: String?, license: SpdxExpression?, copyright: String?, comment: String?, preSelected: Boolean, followUp: Boolean, excludeFromNotice: Boolean) has too many parameters. The current threshold is set to 8.
internal data class OpossumInput(
val metadata: OpossumInputMetadata = OpossumInputMetadata(),
Expand All @@ -253,7 +146,7 @@ class OpossumReporter(
val filesWithChildren: Set<String>,
val frequentLicenses: Set<OpossumFrequentLicense>,
val baseUrlsForSources: Map<String, String>,
val externalAttributionSources: Map<String, OpossumExternalAttributionSource>,
val externalAttributionSources: Map<String, OpossumExternalAttributionSource>
) {
internal fun getSignalsForFile(file: String): List<OpossumSignal> =
resourcesToAttributions[file].orEmpty().mapNotNull { uuid -> externalAttributions[uuid] }
Expand All @@ -268,7 +161,7 @@ class OpossumReporter(
val filesWithChildren: SortedSet<String> = sortedSetOf(),
val frequentLicenses: SortedSet<OpossumFrequentLicense> = sortedSetOf(),
val baseUrlsForSources: SortedMap<String, String> = sortedMapOf(),
val externalAttributionSources: SortedMap<String, OpossumExternalAttributionSource> = sortedMapOf(),
val externalAttributionSources: SortedMap<String, OpossumExternalAttributionSource> = sortedMapOf()
) {
internal fun create(input: ReporterInput, maxDepth: Int = Int.MAX_VALUE): OpossumInput {
addBaseUrl("/", input.ortResult.repository.vcs)
Expand Down Expand Up @@ -374,8 +267,11 @@ class OpossumReporter(
}

paths.forEach { path ->
logger.debug { "add signal ${signal.packageName} ${signal.packageVersion} with namespace " +
"${signal.packageNamespace} of of source ${signal.source} to $path" }
logger.debug {
"add signal ${signal.packageName} ${signal.packageVersion} with namespace " +
"${signal.packageNamespace} of of source ${signal.source} to $path"
}

resources.addResource(path)
pathToSignals.getOrPut(resolvePath(path)) { sortedSetOf() } += uuidOfSignal
}
Expand Down Expand Up @@ -579,33 +475,141 @@ class OpossumReporter(
val fileCreationDate: String = LocalDateTime.now().toString()
)

private fun writeReport(outputFile: File, opossumInput: OpossumInput) {
val jsonFile = createOrtTempDir().resolve("input.json")
val json = Json {
explicitNulls = false
encodeDefaults = true
@Serializable(with = OpossumResourcesSerializer::class)
internal data class OpossumResources(
val tree: MutableMap<String, OpossumResources> = mutableMapOf()
) {
private fun addResource(pathPieces: List<String>) {
if (pathPieces.isEmpty()) return

val head = pathPieces.first()
val tail = pathPieces.drop(1)

if (head !in tree) tree[head] = OpossumResources()
tree.getValue(head).addResource(tail)
}
jsonFile.writeText(json.encodeToString(OpossumInput.serializer(), opossumInput))

jsonFile.packZip(outputFile)
jsonFile.delete()
}
fun addResource(path: String) {
val pathPieces = path.split("/").filter { it.isNotEmpty() }

internal fun createOpossumInput(input: ReporterInput, maxDepth: Int = Int.MAX_VALUE): OpossumInput {
return OpossumInputCreator().create(input, maxDepth)
}
addResource(pathPieces)
}

override fun generateReport(input: ReporterInput, outputDir: File): List<Result<File>> {
val reportFileResult = runCatching {
val opossumInput = createOpossumInput(input, config.maxDepth)
fun isFile() = tree.isEmpty()

outputDir.resolve("report.opossum").also {
writeReport(it, opossumInput)
fun isPathAFile(path: String): Boolean {
val pathPieces = path.split("/").filter { it.isNotEmpty() }

return isPathAFile(pathPieces)
}

private fun isPathAFile(pathPieces: List<String>): Boolean {
if (pathPieces.isEmpty()) return isFile()

val head = pathPieces.first()
val tail = pathPieces.drop(1)

return head !in tree || tree.getValue(head).isPathAFile(tail)
}

fun toFileList(): Set<String> =
tree.flatMapTo(mutableSetOf()) { (key, value) ->
value.toFileList().map { resolvePath(key, it, isDirectory = false) }
}.plus("/")
}

@Serializable
internal data class OpossumSignal(
@Transient
val uuid: UUID = UUID.randomUUID(),
val source: OpossumSignalSource,
val attributionConfidence: Int = 80,
val packageType: String?,
val packageNamespace: String?,
val packageName: String?,
val packageVersion: String?,
val copyright: String?,
val licenseName: String?,
val url: String?,
val preSelected: Boolean,
val followUp: OpossumFollowUp?,
val excludeFromNotice: Boolean,
val comment: String?
) {
companion object {
fun create(
source: String,
id: Identifier? = null,
url: String? = null,
license: SpdxExpression? = null,
copyright: String? = null,
comment: String? = null,
preSelected: Boolean = false,
followUp: Boolean = false,
excludeFromNotice: Boolean = false
): OpossumSignal {
return OpossumSignal(
source = OpossumSignalSource(name = source),
packageType = id?.getPurlType(),
packageNamespace = id?.namespace,
packageName = id?.name,
packageVersion = id?.version,
copyright = copyright,
licenseName = license?.toString(),
url = url,
preSelected = preSelected,
followUp = OpossumFollowUp.FOLLOW_UP.takeIf { followUp },
excludeFromNotice = excludeFromNotice,
comment = comment
)
}
}

return listOf(reportFileResult)
fun matches(other: OpossumSignal): Boolean =
source == other.source
&& packageType == other.packageType
&& packageNamespace == other.packageNamespace
&& packageName == other.packageName
&& packageVersion == other.packageVersion
&& copyright == other.copyright
&& licenseName == other.licenseName
&& url == other.url
&& preSelected == other.preSelected
&& comment == other.comment
}

@Serializable
internal data class OpossumSignalSource(
val name: String,
val documentConfidence: Int = 80
)

@Serializable
internal enum class OpossumFollowUp {
FOLLOW_UP
}

@Serializable
internal data class OpossumFrequentLicense(
val shortName: String,
val fullName: String?,
val defaultText: String?
) : Comparable<OpossumFrequentLicense> {
override fun compareTo(other: OpossumFrequentLicense) =
compareValuesBy(
this,
other,
{ it.shortName },
{ it.fullName },
{ it.defaultText }
)
}

@Serializable
internal data class OpossumExternalAttributionSource(
val name: String,
val priority: Int
)
}

private fun DependencyNode.getDependencies(): List<DependencyNode> =
Expand All @@ -627,7 +631,7 @@ private object UUIDSerializer : KSerializer<UUID> {
}
}

private object OpossumResourcesSerializer: KSerializer<OpossumReporter.OpossumResources> {
private object OpossumResourcesSerializer : KSerializer<OpossumReporter.OpossumResources> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Resource")

override fun serialize(encoder: Encoder, value: OpossumReporter.OpossumResources) {
Expand Down

0 comments on commit 98ee401

Please sign in to comment.