-
Notifications
You must be signed in to change notification settings - Fork 326
/
Copy pathFilePackageCurationProvider.kt
138 lines (115 loc) · 5.21 KB
/
FilePackageCurationProvider.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* Copyright (C) 2017 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* 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.analyzer.curation
import java.io.File
import java.io.IOException
import org.apache.logging.log4j.kotlin.Logging
import org.ossreviewtoolkit.analyzer.PackageCurationProviderFactory
import org.ossreviewtoolkit.model.FileFormat
import org.ossreviewtoolkit.model.PackageCuration
import org.ossreviewtoolkit.model.readValue
import org.ossreviewtoolkit.model.utils.PackageCurationProvider
import org.ossreviewtoolkit.utils.common.getDuplicates
import org.ossreviewtoolkit.utils.ort.ORT_PACKAGE_CURATIONS_DIRNAME
import org.ossreviewtoolkit.utils.ort.ORT_PACKAGE_CURATIONS_FILENAME
import org.ossreviewtoolkit.utils.ort.ortConfigDirectory
class FilePackageCurationProviderConfig(
/**
* The path of the package curation file or directory.
*/
val path: File,
/**
* A flag to denote whether the path is required to exist.
*/
val mustExist: Boolean
)
open class FilePackageCurationProviderFactory : PackageCurationProviderFactory<FilePackageCurationProviderConfig> {
override val type = "File"
override fun create(config: FilePackageCurationProviderConfig) =
FilePackageCurationProvider(config)
override fun parseConfig(config: Map<String, String>) =
FilePackageCurationProviderConfig(
path = File(config.getValue("path")),
mustExist = config["mustExist"]?.toBooleanStrict() ?: true,
)
}
class DefaultFilePackageCurationProviderFactory : FilePackageCurationProviderFactory() {
override val type = "DefaultFile"
override fun parseConfig(config: Map<String, String>) =
FilePackageCurationProviderConfig(
path = ortConfigDirectory.resolve(ORT_PACKAGE_CURATIONS_FILENAME),
mustExist = false
)
}
class DefaultDirPackageCurationProviderFactory : FilePackageCurationProviderFactory() {
override val type = "DefaultDir"
override fun parseConfig(config: Map<String, String>) =
FilePackageCurationProviderConfig(
path = ortConfigDirectory.resolve(ORT_PACKAGE_CURATIONS_DIRNAME),
mustExist = false
)
}
/**
* A [PackageCurationProvider] that loads [PackageCuration]s from all given curation files. Supports all file formats
* specified in [FileFormat].
*/
class FilePackageCurationProvider(
vararg paths: File?
) : SimplePackageCurationProvider(readCurationFiles(paths.filterNotNull())) {
constructor(config: FilePackageCurationProviderConfig) : this(
config.path.takeUnless { !it.exists() && !config.mustExist }
)
companion object : Logging {
/**
* Read a list of [PackageCuration]s from existing [paths], which can either point to files or directories. In
* the latter case, the directory is searched recursively for deserializable files (according to their
* extension), which then are assumed to be curation files.
*/
fun readCurationFiles(paths: Collection<File>): List<PackageCuration> {
val allCurations = mutableListOf<Pair<PackageCuration, File>>()
val curationFiles = paths.flatMap {
require(it.exists()) {
"The path '$it' does not exist."
}
if (it.isDirectory) FileFormat.findFilesWithKnownExtensions(it) else listOf(it)
}.filterNot { it.length() == 0L }
curationFiles.map { curationFile ->
val curations = runCatching {
curationFile.readValue<List<PackageCuration>>()
}.getOrElse {
throw IOException("Failed parsing package curation(s) from '${curationFile.absolutePath}'.", it)
}
curations.mapTo(allCurations) { it to curationFile }
}
val duplicates = allCurations.getDuplicates { it.first }
if (duplicates.isNotEmpty()) {
val duplicatesInfo = buildString {
duplicates.forEach { (curation, origins) ->
appendLine("Curation for '${curation.id.toCoordinates()}' found in all of:")
val files = origins.joinToString(separator = "\n") { (_, file) -> file.absolutePath }
appendLine(files.prependIndent())
}
}
throw DuplicatedCurationException("Duplicate curations found:\n${duplicatesInfo.prependIndent()}")
}
return allCurations.unzip().first
}
}
}
private class DuplicatedCurationException(message: String?) : Exception(message)