diff --git a/scanner/src/funTest/kotlin/provenance/DefaultPackageProvenanceResolverFunTest.kt b/scanner/src/funTest/kotlin/provenance/DefaultPackageProvenanceResolverFunTest.kt index cf97ee68d7794..fc9da19864296 100644 --- a/scanner/src/funTest/kotlin/provenance/DefaultPackageProvenanceResolverFunTest.kt +++ b/scanner/src/funTest/kotlin/provenance/DefaultPackageProvenanceResolverFunTest.kt @@ -211,4 +211,6 @@ internal class DummyProvenanceStorage : PackageProvenanceStorage { sourceArtifact: RemoteArtifact, result: PackageProvenanceResolutionResult ) { /* no-op */ } + + override fun deleteProvenances(id: Identifier) { /* no-op */ } } diff --git a/scanner/src/main/kotlin/provenance/FileBasedPackageProvenanceStorage.kt b/scanner/src/main/kotlin/provenance/FileBasedPackageProvenanceStorage.kt index e94409c83aed2..af9379377af09 100644 --- a/scanner/src/main/kotlin/provenance/FileBasedPackageProvenanceStorage.kt +++ b/scanner/src/main/kotlin/provenance/FileBasedPackageProvenanceStorage.kt @@ -112,6 +112,13 @@ class FileBasedPackageProvenanceStorage(val backend: FileStorage) : PackageProve } } } + + override fun deleteProvenances(id: Identifier) { + val path = storagePath(id) + if (!backend.delete(path)) { + logger.warn { "Could not delete resolved provenances for '${id.toCoordinates()}' at path '$path'." } + } + } } private const val FILE_NAME = "resolved_provenance.yml" diff --git a/scanner/src/main/kotlin/provenance/PackageProvenanceStorage.kt b/scanner/src/main/kotlin/provenance/PackageProvenanceStorage.kt index 689b5f0c32063..f03a6a3b11f1d 100644 --- a/scanner/src/main/kotlin/provenance/PackageProvenanceStorage.kt +++ b/scanner/src/main/kotlin/provenance/PackageProvenanceStorage.kt @@ -87,6 +87,11 @@ interface PackageProvenanceStorage { * for [id] and [vcs] it is overwritten. */ fun writeProvenance(id: Identifier, vcs: VcsInfo, result: PackageProvenanceResolutionResult) + + /** + * Delete all [PackageProvenanceResolutionResult]s for the [id]. + */ + fun deleteProvenances(id: Identifier) } /** diff --git a/scanner/src/main/kotlin/provenance/PostgresPackageProvenanceStorage.kt b/scanner/src/main/kotlin/provenance/PostgresPackageProvenanceStorage.kt index 83e03801b7b50..1e2907e6d758b 100644 --- a/scanner/src/main/kotlin/provenance/PostgresPackageProvenanceStorage.kt +++ b/scanner/src/main/kotlin/provenance/PostgresPackageProvenanceStorage.kt @@ -134,6 +134,14 @@ class PostgresPackageProvenanceStorage( } } } + + override fun deleteProvenances(id: Identifier) { + database.transaction { + table.deleteWhere { + table.identifier eq id.toCoordinates() + } + } + } } private class PackageProvenances(tableName: String) : IntIdTable(tableName) { diff --git a/utils/ort/src/main/kotlin/storage/FileStorage.kt b/utils/ort/src/main/kotlin/storage/FileStorage.kt index 71a2d8f05b33f..634426e097e5c 100644 --- a/utils/ort/src/main/kotlin/storage/FileStorage.kt +++ b/utils/ort/src/main/kotlin/storage/FileStorage.kt @@ -41,4 +41,9 @@ interface FileStorage { * provided [inputStream] is closed after writing it to the file. */ fun write(path: String, inputStream: InputStream) + + /** + * Delete the file at the given [path] and return whether the operation was successful. + */ + fun delete(path: String): Boolean } diff --git a/utils/ort/src/main/kotlin/storage/HttpFileStorage.kt b/utils/ort/src/main/kotlin/storage/HttpFileStorage.kt index 0cb0f87406396..b4c0d933732d6 100644 --- a/utils/ort/src/main/kotlin/storage/HttpFileStorage.kt +++ b/utils/ort/src/main/kotlin/storage/HttpFileStorage.kt @@ -136,4 +136,16 @@ class HttpFileStorage( } private fun urlForPath(path: String) = "$url/$path$query" + + override fun delete(path: String): Boolean { + val request = requestBuilder() + .delete() + .url(urlForPath(path)) + .build() + + logger.debug { "Deleting file from storage: ${request.url}" } + + val response = httpClient.execute(request) + return response.isSuccessful + } } diff --git a/utils/ort/src/main/kotlin/storage/LocalFileStorage.kt b/utils/ort/src/main/kotlin/storage/LocalFileStorage.kt index b6c0c307e7f59..bc1564316f1c4 100644 --- a/utils/ort/src/main/kotlin/storage/LocalFileStorage.kt +++ b/utils/ort/src/main/kotlin/storage/LocalFileStorage.kt @@ -76,4 +76,7 @@ open class LocalFileStorage( inputStream.use { it.copyTo(outputStream) } } } + + @Synchronized + override fun delete(path: String): Boolean = directory.resolve(path).delete() } diff --git a/utils/ort/src/main/kotlin/storage/S3FileStorage.kt b/utils/ort/src/main/kotlin/storage/S3FileStorage.kt index 46860cf180263..d8e4454e4a713 100644 --- a/utils/ort/src/main/kotlin/storage/S3FileStorage.kt +++ b/utils/ort/src/main/kotlin/storage/S3FileStorage.kt @@ -34,6 +34,7 @@ import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider import software.amazon.awssdk.core.sync.RequestBody import software.amazon.awssdk.regions.Region import software.amazon.awssdk.services.s3.S3Client +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest import software.amazon.awssdk.services.s3.model.GetObjectRequest import software.amazon.awssdk.services.s3.model.HeadObjectRequest import software.amazon.awssdk.services.s3.model.NoSuchKeyException @@ -136,4 +137,14 @@ class S3FileStorage( if (exception is S3Exception) logger.warn { "Can not write '$path' to S3 bucket '$bucketName'." } } } + + override fun delete(path: String): Boolean { + val request = DeleteObjectRequest.builder() + .key(path) + .bucket(bucketName) + .build() + + val response = s3Client.deleteObject(request) + return response.sdkHttpResponse().isSuccessful + } }