Skip to content

Commit 41e87db

Browse files
committed
feat(Provenance): Add DirectoryProvenance as a LocalProvenance
In contrast to the previously added `RemoteProvenance` stands the `LocalProvenance`, which has no remote source, but instead references a local input of some kind. The `DirectoryProvenance` references a local project directory, which is lacking supported (remote) version control. It is defined by its canonical path only. Since ORT needs further refactoring until `DirectoryProvenance` can be fully utilized, the new class can not be used right now. However the presence of a new `KnownProvenance` class results in `when` conditional cases not being exhaustive anymore. To circumvent this issue, the following changes were made: 1. Wherever possible `RemoteProvenance` is used as parameter type instead of `KnownProvenance`. 2. When necessary `KnownProvenance`s are cast to `RemoteProvenance`. 3. If `Provenance` is expected, `DirectoryProvenance` is handled like `UnknownProvenance`. For instances of `Package` the new default data structure should be `RemoteProvenance`, as a `Package` by definition requires a remote. The exception being `hash` and `storageKey`, which both required a default value, which was set to the `canonicalPath`. However, since the rest of the code does not handle `DirectoryProvenance`, this should remain unused for now. See [1] for more context on the new provenance hierarchy. [1]: #8803 (comment) Signed-off-by: Jens Keim <[email protected]>
1 parent d47c9ac commit 41e87db

File tree

14 files changed

+60
-23
lines changed

14 files changed

+60
-23
lines changed

model/src/main/kotlin/Provenance.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize
2626
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
2727
import com.fasterxml.jackson.module.kotlin.treeToValue
2828

29+
import java.io.File
30+
2931
/**
3032
* Provenance information about the origin of source code.
3133
*/
@@ -45,6 +47,8 @@ sealed interface KnownProvenance : Provenance
4547

4648
sealed interface RemoteProvenance : KnownProvenance
4749

50+
sealed interface LocalProvenance : KnownProvenance
51+
4852
/**
4953
* Provenance information for a source artifact.
5054
*/
@@ -83,6 +87,19 @@ data class RepositoryProvenance(
8387
override fun matches(pkg: Package): Boolean = vcsInfo == pkg.vcsProcessed
8488
}
8589

90+
/**
91+
* Provenance information for a local directory path.
92+
*/
93+
data class DirectoryProvenance(
94+
val canonicalPath: File
95+
) : LocalProvenance {
96+
/**
97+
* Return false for any [pkg] as a [Package] by definition is coming from a remote, and is not stored in a local
98+
* directory path (which would be a [Project]).
99+
*/
100+
override fun matches(pkg: Package): Boolean = false
101+
}
102+
86103
/**
87104
* A custom deserializer for polymorphic deserialization of [Provenance] without requiring type information.
88105
*/

model/src/main/kotlin/ProvenanceResolutionResult.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ data class ProvenanceResolutionResult(
3737
* The resolved provenance of the package. Can only be null if a [packageProvenanceResolutionIssue] occurred.
3838
*/
3939
@JsonInclude(JsonInclude.Include.NON_NULL)
40-
val packageProvenance: KnownProvenance? = null,
40+
val packageProvenance: RemoteProvenance? = null,
4141

4242
/**
4343
* The (recursive) sub-repositories of [packageProvenance]. The map can only be empty if a

model/src/main/kotlin/utils/FileProvenanceFileStorage.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import java.io.InputStream
2424
import org.apache.logging.log4j.kotlin.logger
2525

2626
import org.ossreviewtoolkit.model.ArtifactProvenance
27+
import org.ossreviewtoolkit.model.DirectoryProvenance
2728
import org.ossreviewtoolkit.model.HashAlgorithm
2829
import org.ossreviewtoolkit.model.KnownProvenance
2930
import org.ossreviewtoolkit.model.RepositoryProvenance
@@ -81,6 +82,7 @@ private fun KnownProvenance.hash(): String {
8182
val key = when (this) {
8283
is ArtifactProvenance -> "${sourceArtifact.url}${sourceArtifact.hash.value}"
8384
is RepositoryProvenance -> "${vcsInfo.type}${vcsInfo.url}$resolvedRevision"
85+
is DirectoryProvenance -> "$canonicalPath"
8486
}
8587

8688
return HashAlgorithm.SHA1.calculate(key.toByteArray())

model/src/main/kotlin/utils/PostgresProvenanceFileStorage.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import org.jetbrains.exposed.sql.insert
3636
import org.jetbrains.exposed.sql.selectAll
3737

3838
import org.ossreviewtoolkit.model.ArtifactProvenance
39+
import org.ossreviewtoolkit.model.DirectoryProvenance
3940
import org.ossreviewtoolkit.model.KnownProvenance
4041
import org.ossreviewtoolkit.model.RepositoryProvenance
4142
import org.ossreviewtoolkit.model.utils.DatabaseUtils.checkDatabaseEncoding
@@ -121,4 +122,5 @@ private fun KnownProvenance.storageKey(): String =
121122
is ArtifactProvenance -> "source-artifact|${sourceArtifact.url}|${sourceArtifact.hash}"
122123
// The trailing "|" is kept for backward compatibility because there used to be an additional parameter.
123124
is RepositoryProvenance -> "vcs|${vcsInfo.type}|${vcsInfo.url}|$resolvedRevision|"
125+
is DirectoryProvenance -> "directory|$canonicalPath"
124126
}

model/src/main/kotlin/utils/PurlExtensions.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import org.ossreviewtoolkit.model.Identifier
2727
import org.ossreviewtoolkit.model.Package
2828
import org.ossreviewtoolkit.model.Provenance
2929
import org.ossreviewtoolkit.model.RemoteArtifact
30+
import org.ossreviewtoolkit.model.RemoteProvenance
3031
import org.ossreviewtoolkit.model.RepositoryProvenance
3132
import org.ossreviewtoolkit.model.UnknownProvenance
3233
import org.ossreviewtoolkit.model.VcsInfo
@@ -101,7 +102,11 @@ fun Provenance.toPurlExtras(): PurlExtras =
101102
)
102103
}
103104

104-
is UnknownProvenance -> PurlExtras()
105+
/**
106+
* Purls refer to packages that have been published and thus always have a remove provenance. So just return
107+
* empty extras in all other cases.
108+
*/
109+
!is RemoteProvenance -> PurlExtras()
105110
}
106111

107112
/**

scanner/src/main/kotlin/ScanController.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import org.ossreviewtoolkit.model.Issue
2424
import org.ossreviewtoolkit.model.KnownProvenance
2525
import org.ossreviewtoolkit.model.Package
2626
import org.ossreviewtoolkit.model.Provenance
27+
import org.ossreviewtoolkit.model.RemoteProvenance
2728
import org.ossreviewtoolkit.model.RepositoryProvenance
2829
import org.ossreviewtoolkit.model.ScanResult
2930
import org.ossreviewtoolkit.model.ScanSummary
@@ -79,7 +80,7 @@ internal class ScanController(
7980
* A map of package [Identifier]s to their resolved [KnownProvenance]s. These provenances are used to filter the
8081
* scan results for a package based on the VCS path.
8182
*/
82-
private val packageProvenances = mutableMapOf<Identifier, KnownProvenance>()
83+
private val packageProvenances = mutableMapOf<Identifier, RemoteProvenance>()
8384

8485
/**
8586
* A map of package [Identifier]s to their resolved [KnownProvenance]s with the VCS path removed. These provenances
@@ -130,7 +131,7 @@ internal class ScanController(
130131
/**
131132
* Set the [provenance] for the package denoted by [id], overwriting any existing values.
132133
*/
133-
fun putPackageProvenance(id: Identifier, provenance: KnownProvenance) {
134+
fun putPackageProvenance(id: Identifier, provenance: RemoteProvenance) {
134135
packageProvenances[id] = provenance
135136
packageProvenancesWithoutVcsPath[id] = when (provenance) {
136137
is RepositoryProvenance -> provenance.copy(vcsInfo = provenance.vcsInfo.copy(path = ""))
@@ -267,7 +268,7 @@ internal class ScanController(
267268
fun getPackagesForProvenanceWithoutVcsPath(provenance: KnownProvenance): Set<Identifier> =
268269
packageProvenancesWithoutVcsPath.filter { (_, packageProvenance) -> packageProvenance == provenance }.keys
269270

270-
fun getPackageProvenance(id: Identifier): KnownProvenance? = packageProvenances[id]
271+
fun getPackageProvenance(id: Identifier): RemoteProvenance? = packageProvenances[id]
271272

272273
/**
273274
* Return the package provenanceResolutionIssue associated with the given [id].

scanner/src/main/kotlin/Scanner.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import org.ossreviewtoolkit.model.OrtResult
4444
import org.ossreviewtoolkit.model.Package
4545
import org.ossreviewtoolkit.model.PackageType
4646
import org.ossreviewtoolkit.model.ProvenanceResolutionResult
47+
import org.ossreviewtoolkit.model.RemoteProvenance
4748
import org.ossreviewtoolkit.model.ScanResult
4849
import org.ossreviewtoolkit.model.ScannerRun
4950
import org.ossreviewtoolkit.model.TextLocation
@@ -235,7 +236,7 @@ class Scanner(
235236
}.awaitAll()
236237
}.forEach { (pkg, result) ->
237238
result.onSuccess { provenance ->
238-
controller.putPackageProvenance(pkg.id, provenance)
239+
controller.putPackageProvenance(pkg.id, provenance as RemoteProvenance)
239240
}.onFailure {
240241
controller.putPackageProvenanceResolutionIssue(
241242
pkg.id,
@@ -256,7 +257,7 @@ class Scanner(
256257
controller.getPackageProvenancesWithoutVcsPath().map { provenance ->
257258
async {
258259
provenance to runCatching {
259-
nestedProvenanceResolver.resolveNestedProvenance(provenance)
260+
nestedProvenanceResolver.resolveNestedProvenance(provenance as RemoteProvenance)
260261
}.onFailure {
261262
if (it is CancellationException) currentCoroutineContext().ensureActive()
262263
}
@@ -591,7 +592,7 @@ class Scanner(
591592
controller: ScanController
592593
): Map<PathScannerWrapper, ScanResult> {
593594
val downloadDir = try {
594-
provenanceDownloader.download(provenance)
595+
provenanceDownloader.download(provenance as RemoteProvenance)
595596
} catch (e: DownloadException) {
596597
val issue = createAndLogIssue(
597598
"Downloader", "Could not download provenance $provenance: ${e.collectMessages()}"

scanner/src/main/kotlin/provenance/NestedProvenanceResolver.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import org.apache.logging.log4j.kotlin.logger
2323

2424
import org.ossreviewtoolkit.downloader.WorkingTreeCache
2525
import org.ossreviewtoolkit.model.ArtifactProvenance
26-
import org.ossreviewtoolkit.model.KnownProvenance
2726
import org.ossreviewtoolkit.model.Provenance
27+
import org.ossreviewtoolkit.model.RemoteProvenance
2828
import org.ossreviewtoolkit.model.RepositoryProvenance
2929

3030
/**
@@ -36,7 +36,7 @@ interface NestedProvenanceResolver {
3636
* [NestedProvenance] always contains only the provided [ArtifactProvenance]. For a [RepositoryProvenance] the
3737
* resolver looks for nested repositories, for example Git submodules or Mercurial subrepositories.
3838
*/
39-
suspend fun resolveNestedProvenance(provenance: KnownProvenance): NestedProvenance
39+
suspend fun resolveNestedProvenance(provenance: RemoteProvenance): NestedProvenance
4040
}
4141

4242
/**
@@ -46,7 +46,7 @@ class DefaultNestedProvenanceResolver(
4646
private val storage: NestedProvenanceStorage,
4747
private val workingTreeCache: WorkingTreeCache
4848
) : NestedProvenanceResolver {
49-
override suspend fun resolveNestedProvenance(provenance: KnownProvenance): NestedProvenance {
49+
override suspend fun resolveNestedProvenance(provenance: RemoteProvenance): NestedProvenance {
5050
return when (provenance) {
5151
is ArtifactProvenance -> NestedProvenance(root = provenance, subRepositories = emptyMap())
5252
is RepositoryProvenance -> resolveNestedRepository(provenance)

scanner/src/main/kotlin/provenance/ProvenanceDownloader.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ import org.ossreviewtoolkit.downloader.DownloadException
3232
import org.ossreviewtoolkit.downloader.Downloader
3333
import org.ossreviewtoolkit.downloader.WorkingTreeCache
3434
import org.ossreviewtoolkit.model.ArtifactProvenance
35-
import org.ossreviewtoolkit.model.KnownProvenance
3635
import org.ossreviewtoolkit.model.Package
36+
import org.ossreviewtoolkit.model.RemoteProvenance
3737
import org.ossreviewtoolkit.model.RepositoryProvenance
3838
import org.ossreviewtoolkit.model.config.DownloaderConfiguration
3939
import org.ossreviewtoolkit.utils.common.safeDeleteRecursively
@@ -51,7 +51,7 @@ fun interface ProvenanceDownloader {
5151
*
5252
* Throws a [DownloadException] if the download fails.
5353
*/
54-
fun download(provenance: KnownProvenance): File
54+
fun download(provenance: RemoteProvenance): File
5555

5656
/**
5757
* Download the source code specified by the provided [nestedProvenance] incl. sub-repositories and return the path
@@ -64,7 +64,7 @@ fun interface ProvenanceDownloader {
6464
// Use the provenanceDownloader to download each provenance from nestedProvenance separately, because they are
6565
// likely already cached if a path scanner wrapper is used.
6666

67-
val root = download(nestedProvenance.root)
67+
val root = download(nestedProvenance.root as RemoteProvenance)
6868

6969
nestedProvenance.subRepositories.forEach { (path, provenance) ->
7070
val tempDir = download(provenance)
@@ -86,7 +86,7 @@ class DefaultProvenanceDownloader(
8686
) : ProvenanceDownloader {
8787
private val downloader = Downloader(config)
8888

89-
override fun download(provenance: KnownProvenance): File {
89+
override fun download(provenance: RemoteProvenance): File {
9090
val downloadDir = createOrtTempDir()
9191

9292
when (provenance) {

scanner/src/main/kotlin/storages/ProvenanceBasedFileStorage.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.apache.logging.log4j.kotlin.logger
2929

3030
import org.ossreviewtoolkit.model.ArtifactProvenance
3131
import org.ossreviewtoolkit.model.KnownProvenance
32+
import org.ossreviewtoolkit.model.RemoteProvenance
3233
import org.ossreviewtoolkit.model.RepositoryProvenance
3334
import org.ossreviewtoolkit.model.ScanResult
3435
import org.ossreviewtoolkit.model.yamlMapper
@@ -45,7 +46,7 @@ class ProvenanceBasedFileStorage(private val backend: FileStorage) : ProvenanceB
4546
override fun read(provenance: KnownProvenance, scannerMatcher: ScannerMatcher?): List<ScanResult> {
4647
requireEmptyVcsPath(provenance)
4748

48-
val path = storagePath(provenance)
49+
val path = storagePath(provenance as RemoteProvenance)
4950

5051
return runCatching {
5152
backend.read(path).use { input ->
@@ -97,7 +98,7 @@ class ProvenanceBasedFileStorage(private val backend: FileStorage) : ProvenanceB
9798

9899
val scanResults = existingScanResults + scanResult
99100

100-
val path = storagePath(provenance)
101+
val path = storagePath(provenance as RemoteProvenance)
101102
val yamlBytes = yamlMapper.writeValueAsBytes(scanResults)
102103
val input = ByteArrayInputStream(yamlBytes)
103104

@@ -123,7 +124,7 @@ class ProvenanceBasedFileStorage(private val backend: FileStorage) : ProvenanceB
123124
}
124125
}
125126

126-
private fun storagePath(provenance: KnownProvenance) =
127+
private fun storagePath(provenance: RemoteProvenance) =
127128
when (provenance) {
128129
is ArtifactProvenance -> "artifact/${provenance.sourceArtifact.url.fileSystemEncode()}/$SCAN_RESULTS_FILE_NAME"
129130
is RepositoryProvenance -> {

0 commit comments

Comments
 (0)