19
19
20
20
package org.ossreviewtoolkit.plugins.reporters.opossum
21
21
22
- import kotlinx.serialization.KSerializer
23
- import kotlinx.serialization.builtins.MapSerializer
24
- import kotlinx.serialization.builtins.serializer
25
- import kotlinx.serialization.encoding.Decoder
26
- import kotlinx.serialization.encoding.Encoder
27
- import kotlinx.serialization.Serializable
28
- import kotlinx.serialization.Transient
29
- import kotlinx.serialization.descriptors.PrimitiveKind
30
- import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
31
- import kotlinx.serialization.descriptors.SerialDescriptor
32
- import kotlinx.serialization.descriptors.buildClassSerialDescriptor
33
- import kotlinx.serialization.json.Json
22
+ import io.ks3.java.typealiases.LocalDateTimeAsString
23
+ import io.ks3.java.typealiases.UuidAsString
34
24
35
25
import java.io.File
36
26
import java.time.LocalDateTime
37
27
import java.util.UUID
38
28
39
29
import kotlin.math.min
40
30
31
+ import kotlinx.serialization.builtins.MapSerializer
32
+ import kotlinx.serialization.builtins.serializer
33
+ import kotlinx.serialization.descriptors.buildClassSerialDescriptor
34
+ import kotlinx.serialization.descriptors.SerialDescriptor
35
+ import kotlinx.serialization.encoding.Decoder
36
+ import kotlinx.serialization.encoding.Encoder
37
+ import kotlinx.serialization.json.encodeToStream
38
+ import kotlinx.serialization.json.Json
39
+ import kotlinx.serialization.KSerializer
40
+ import kotlinx.serialization.Serializable
41
+
41
42
import org.apache.logging.log4j.kotlin.logger
42
43
43
44
import org.ossreviewtoolkit.downloader.VcsHost
@@ -49,9 +50,9 @@ import org.ossreviewtoolkit.model.OrtResult
49
50
import org.ossreviewtoolkit.model.Package
50
51
import org.ossreviewtoolkit.model.Project
51
52
import org.ossreviewtoolkit.model.ScanResult
52
- import org.ossreviewtoolkit.model.VcsInfo
53
53
import org.ossreviewtoolkit.model.utils.getPurlType
54
54
import org.ossreviewtoolkit.model.utils.toPurl
55
+ import org.ossreviewtoolkit.model.VcsInfo
55
56
import org.ossreviewtoolkit.plugins.api.OrtPlugin
56
57
import org.ossreviewtoolkit.plugins.api.OrtPluginOption
57
58
import org.ossreviewtoolkit.plugins.api.PluginDescriptor
@@ -104,6 +105,13 @@ class OpossumReporter(
104
105
override val descriptor : PluginDescriptor = OpossumReporterFactory .descriptor,
105
106
private val config : OpossumReporterConfig
106
107
) : Reporter {
108
+ companion object {
109
+ internal val JSON = Json {
110
+ explicitNulls = false
111
+ encodeDefaults = true
112
+ }
113
+ }
114
+
107
115
override fun generateReport (input : ReporterInput , outputDir : File ): List <Result <File >> {
108
116
val reportFileResult = runCatching {
109
117
val opossumInput = createOpossumInput(input, config.maxDepth)
@@ -116,42 +124,40 @@ class OpossumReporter(
116
124
return listOf (reportFileResult)
117
125
}
118
126
119
- internal fun createOpossumInput (input : ReporterInput , maxDepth : Int = Int .MAX_VALUE ): OpossumInput {
120
- return OpossumInputCreator ().create(input, maxDepth)
121
- }
127
+ internal fun createOpossumInput (input : ReporterInput , maxDepth : Int = Int .MAX_VALUE ): OpossumInput =
128
+ OpossumInputCreator ().create(input, maxDepth)
122
129
123
130
private fun writeReport (outputFile : File , opossumInput : OpossumInput ) {
124
- val jsonFile = createOrtTempDir().resolve(" input.json" )
125
- val json = Json {
126
- explicitNulls = false
127
- encodeDefaults = true
128
- }
131
+ val inputJson = createOrtTempDir().resolve(" input.json" )
129
132
130
- jsonFile.writeText(json.encodeToString( OpossumInput .serializer(), opossumInput) )
133
+ inputJson.writeReport( opossumInput)
131
134
132
- jsonFile .packZip(outputFile)
133
- jsonFile .delete()
135
+ inputJson .packZip(outputFile)
136
+ inputJson .delete()
134
137
}
135
138
139
+ private fun File.writeReport (opossumInput : OpossumInput ): File =
140
+ apply { outputStream().use { JSON .encodeToStream(opossumInput, it) } }
141
+
136
142
@Serializable
137
- internal data class OpossumInput (
143
+ data class OpossumInput (
138
144
val metadata : OpossumInputMetadata = OpossumInputMetadata (),
139
145
val resources : OpossumResources ,
140
- val externalAttributions : Map <@Serializable( UUIDSerializer :: class ) UUID , OpossumSignal >,
141
- val resourcesToAttributions : Map <String , Set <@Serializable( UUIDSerializer :: class ) UUID >>,
146
+ val externalAttributions : Map <UuidAsString , OpossumSignalFlat >,
147
+ val resourcesToAttributions : Map <String , Set <UuidAsString >>,
142
148
val attributionBreakpoints : Set <String >,
143
149
val filesWithChildren : Set <String >,
144
150
val frequentLicenses : Set <OpossumFrequentLicense >,
145
151
val baseUrlsForSources : Map <String , String >,
146
152
val externalAttributionSources : Map <String , OpossumExternalAttributionSource >
147
153
) {
148
- internal fun getSignalsForFile (file : String ): List <OpossumSignal > =
154
+ internal fun getSignalsForFile (file : String ): List <OpossumSignalFlat > =
149
155
resourcesToAttributions[file].orEmpty().mapNotNull { uuid -> externalAttributions[uuid] }
150
156
}
151
157
152
- internal class OpossumInputCreator {
158
+ class OpossumInputCreator {
153
159
private val resources: OpossumResources = OpossumResources ()
154
- private val signals : MutableList < OpossumSignal > = mutableListOf ()
160
+ private val uuidToSignals : MutableMap < UUID , OpossumSignal > = mutableMapOf ()
155
161
private val pathToSignals: MutableMap <String , MutableSet <UUID >> = mutableMapOf ()
156
162
private val packageToRoot: MutableMap <Identifier , MutableMap <String , Int >> = mutableMapOf ()
157
163
private val attributionBreakpoints: MutableSet <String > = mutableSetOf ()
@@ -192,7 +198,7 @@ class OpossumReporter(
192
198
addScannerResults(id, results, maxDepth)
193
199
}
194
200
195
- val externalAttributions = signals.associateBy { it.uuid }
201
+ val externalAttributions = uuidToSignals.mapValues { OpossumSignalFlat .create( it.value) }
196
202
val resourcesToAttributions = pathToSignals.mapKeys {
197
203
val trailingSlash = if (resources.isPathAFile(it.key)) " " else " /"
198
204
resolvePath(" ${it.key}$trailingSlash " )
@@ -254,19 +260,21 @@ class OpossumReporter(
254
260
private fun addSignal (signal : OpossumSignal , paths : Set <String >) {
255
261
if (paths.isEmpty()) return
256
262
257
- val matchingSignal = signals. find { it.matches(signal) }
263
+ val signalEntry = uuidToSignals.entries. find { it.value .matches(signal) }
258
264
259
- val uuidOfSignal = if (matchingSignal == null ) {
260
- signals + = signal
261
- signal.uuid
265
+ val matchingUuid = signalEntry?.key
266
+ val uuidOfSignal = if (matchingUuid == null ) {
267
+ val uuid = UUID .randomUUID()
268
+ uuidToSignals[uuid] = signal
269
+ uuid
262
270
} else {
263
- matchingSignal.uuid
271
+ matchingUuid
264
272
}
265
273
266
274
paths.forEach { path ->
267
275
logger.debug {
268
- " add signal ${signal.packageName} ${signal.packageVersion} with namespace " +
269
- " ${signal.packageNamespace} of of source ${signal.source} to $path "
276
+ " Add signal ${signal.base. packageName} ${signal.base .packageVersion} with namespace " +
277
+ " ${signal.base. packageNamespace} of of source ${signal.base. source} to $path . "
270
278
}
271
279
272
280
resources.addResource(path)
@@ -467,13 +475,13 @@ class OpossumReporter(
467
475
}
468
476
469
477
@Serializable
470
- internal data class OpossumInputMetadata (
478
+ data class OpossumInputMetadata (
471
479
val projectId : String = " 0" ,
472
- val fileCreationDate : String = LocalDateTime .now().toString ()
480
+ val fileCreationDate : LocalDateTimeAsString = LocalDateTime .now()
473
481
)
474
482
475
483
@Serializable(with = OpossumResourcesSerializer ::class )
476
- internal data class OpossumResources (
484
+ data class OpossumResources (
477
485
val tree : MutableMap <String , OpossumResources > = mutableMapOf()
478
486
) {
479
487
private fun addResource (pathPieces : List <String >) {
@@ -523,9 +531,7 @@ class OpossumReporter(
523
531
}
524
532
525
533
@Serializable
526
- internal data class OpossumSignal (
527
- @Transient
528
- val uuid : UUID = UUID .randomUUID(),
534
+ data class OpossumSignalFlat (
529
535
val source : OpossumSignalSource ,
530
536
val attributionConfidence : Int = 80 ,
531
537
val packageType : String? ,
@@ -541,6 +547,33 @@ class OpossumReporter(
541
547
val comment : String?
542
548
) {
543
549
companion object {
550
+ fun create (signal : OpossumSignal ): OpossumSignalFlat =
551
+ OpossumSignalFlat (
552
+ source = signal.base.source,
553
+ attributionConfidence = signal.attributionConfidence,
554
+ packageType = signal.base.packageType,
555
+ packageNamespace = signal.base.packageNamespace,
556
+ packageName = signal.base.packageName,
557
+ packageVersion = signal.base.packageVersion,
558
+ copyright = signal.base.copyright,
559
+ licenseName = signal.base.licenseName,
560
+ url = signal.base.url,
561
+ preSelected = signal.base.preSelected,
562
+ followUp = signal.followUp,
563
+ excludeFromNotice = signal.excludeFromNotice,
564
+ comment = signal.base.comment
565
+ )
566
+ }
567
+ }
568
+
569
+ data class OpossumSignal (
570
+ val base : OpossumSignalBase ,
571
+ val attributionConfidence : Int = 80 ,
572
+ val followUp : OpossumFollowUp ? ,
573
+ val excludeFromNotice : Boolean
574
+ ) {
575
+ companion object {
576
+ @Suppress(" LongParameterList" )
544
577
fun create (
545
578
source : String ,
546
579
id : Identifier ? = null,
@@ -551,50 +584,54 @@ class OpossumReporter(
551
584
preSelected : Boolean = false,
552
585
followUp : Boolean = false,
553
586
excludeFromNotice : Boolean = false
554
- ): OpossumSignal {
555
- return OpossumSignal (
556
- source = OpossumSignalSource (name = source),
557
- packageType = id?.getPurlType(),
558
- packageNamespace = id?.namespace,
559
- packageName = id?.name,
560
- packageVersion = id?.version,
561
- copyright = copyright,
562
- licenseName = license?.toString(),
563
- url = url,
564
- preSelected = preSelected,
587
+ ): OpossumSignal =
588
+ OpossumSignal (
589
+ base = OpossumSignalBase (
590
+ source = OpossumSignalSource (name = source),
591
+ packageType = id?.getPurlType().toString(),
592
+ packageNamespace = id?.namespace,
593
+ packageName = id?.name,
594
+ packageVersion = id?.version,
595
+ copyright = copyright,
596
+ licenseName = license?.toString(),
597
+ url = url,
598
+ preSelected = preSelected,
599
+ comment = comment
600
+ ),
565
601
followUp = OpossumFollowUp .FOLLOW_UP .takeIf { followUp },
566
- excludeFromNotice = excludeFromNotice,
567
- comment = comment
602
+ excludeFromNotice = excludeFromNotice
568
603
)
569
- }
570
604
}
571
605
572
- fun matches (other : OpossumSignal ): Boolean =
573
- source == other.source
574
- && packageType == other.packageType
575
- && packageNamespace == other.packageNamespace
576
- && packageName == other.packageName
577
- && packageVersion == other.packageVersion
578
- && copyright == other.copyright
579
- && licenseName == other.licenseName
580
- && url == other.url
581
- && preSelected == other.preSelected
582
- && comment == other.comment
606
+ data class OpossumSignalBase (
607
+ val source : OpossumSignalSource ,
608
+ val packageType : String? ,
609
+ val packageNamespace : String? ,
610
+ val packageName : String? ,
611
+ val packageVersion : String? ,
612
+ val copyright : String? ,
613
+ val licenseName : String? ,
614
+ val url : String? ,
615
+ val preSelected : Boolean ,
616
+ val comment : String?
617
+ )
618
+
619
+ fun matches (other : OpossumSignal ): Boolean = base == other.base
583
620
}
584
621
585
622
@Serializable
586
- internal data class OpossumSignalSource (
623
+ data class OpossumSignalSource (
587
624
val name : String ,
588
625
val documentConfidence : Int = 80
589
626
)
590
627
591
628
@Serializable
592
- internal enum class OpossumFollowUp {
629
+ enum class OpossumFollowUp {
593
630
FOLLOW_UP
594
631
}
595
632
596
633
@Serializable
597
- internal data class OpossumFrequentLicense (
634
+ data class OpossumFrequentLicense (
598
635
val shortName : String ,
599
636
val fullName : String? ,
600
637
val defaultText : String?
@@ -610,7 +647,7 @@ class OpossumReporter(
610
647
}
611
648
612
649
@Serializable
613
- internal data class OpossumExternalAttributionSource (
650
+ data class OpossumExternalAttributionSource (
614
651
val name : String ,
615
652
val priority : Int
616
653
)
@@ -623,18 +660,6 @@ private fun DependencyNode.getDependencies(): List<DependencyNode> =
623
660
}
624
661
}
625
662
626
- private object UUIDSerializer : KSerializer<UUID> {
627
- override val descriptor = PrimitiveSerialDescriptor (" UUID" , PrimitiveKind .STRING )
628
-
629
- override fun serialize (encoder : Encoder , value : UUID ) {
630
- encoder.encodeString(value.toString())
631
- }
632
-
633
- override fun deserialize (decoder : Decoder ): UUID {
634
- return UUID .fromString(decoder.decodeString())
635
- }
636
- }
637
-
638
663
private object OpossumResourcesSerializer : KSerializer<OpossumReporter.OpossumResources> {
639
664
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(" Resource" )
640
665
0 commit comments