From 1e2a7f4ea67e5df9c500b161c871e4003ad3b22d Mon Sep 17 00:00:00 2001 From: Silvio Giebl Date: Wed, 10 Jul 2024 12:33:20 +0200 Subject: [PATCH] Add OciData Replace OciRegistryApi.Metadata with OciData Refactor OciDataDescriptor --- .../sgtsilvio/gradle/oci/OciImagesInput.kt | 4 ++-- .../github/sgtsilvio/gradle/oci/OciPushTask.kt | 15 ++++++++------- .../sgtsilvio/gradle/oci/OciRegistryDataTask.kt | 16 ++++++++-------- .../internal/registry/OciMetadataRegistry.kt | 16 ++++++++-------- .../oci/internal/registry/OciRegistryApi.kt | 12 +++++------- .../gradle/oci/metadata/OciDescriptor.kt | 17 ++++++++++++----- .../gradle/oci/metadata/OciMetadataFiles.kt | 12 ++++-------- 7 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciImagesInput.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciImagesInput.kt index 98168704..63c221b6 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciImagesInput.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciImagesInput.kt @@ -46,7 +46,7 @@ internal val DEFAULT_OCI_REFERENCE_SPEC = OciImageReferenceSpec(null, null) internal class OciLayer( // TODO internal? val descriptor: OciMetadata.Layer.Descriptor, - val file: File + val file: File, ) internal class OciVariant( @@ -61,7 +61,7 @@ internal class OciImage( ) internal class OciMultiArchImage( - val index: OciDataDescriptor, + val index: OciData, val platformToImage: Map, ) diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciPushTask.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciPushTask.kt index 4ee3f5eb..321ed365 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciPushTask.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciPushTask.kt @@ -140,10 +140,10 @@ abstract class OciPushTask @Inject constructor( val configDigest = config.digest val sourceBlob = blobs[configDigest] blobFutures += if (sourceBlob == null) { - val size = config.data.size.toLong() - val sender: NettyOutbound.() -> Publisher = { sendByteArray(config.data.toMono()) } + val bytes = config.data.bytes + val sender: NettyOutbound.() -> Publisher = { sendByteArray(bytes.toMono()) } val future = CompletableFuture() - blobs[configDigest] = Blob(configDigest, size, sender, imageName, imageName, future) + blobs[configDigest] = Blob(configDigest, config.size, sender, imageName, imageName, future) future } else if (sourceBlob.imageName == imageName) { sourceBlob.future @@ -161,7 +161,7 @@ abstract class OciPushTask @Inject constructor( val manifest = image.manifest val manifestDigest = manifest.digest val manifestMediaType = manifest.mediaType - val manifestData = manifest.data + val manifestBytes = manifest.data.bytes val manifestFuture = CompletableFuture() manifestFutures += manifestFuture CompletableFuture.allOf(*blobFutures.toTypedArray()).thenRun { @@ -170,7 +170,7 @@ abstract class OciPushTask @Inject constructor( imageName, manifestDigest.toString(), manifestMediaType, - manifestData, + manifestBytes, manifestFuture, ) } @@ -178,9 +178,10 @@ abstract class OciPushTask @Inject constructor( val index = multiArchImage.index for (tag in tags) { val indexMediaType = index.mediaType - val indexData = index.data + val indexBytes = index.bytes CompletableFuture.allOf(*manifestFutures.toTypedArray()).thenRun { - context.pushService.get().pushManifest(context, imageName, tag, indexMediaType, indexData, null) + context.pushService.get() + .pushManifest(context, imageName, tag, indexMediaType, indexBytes, null) } } } diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciRegistryDataTask.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciRegistryDataTask.kt index 0123d08c..26b8e175 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciRegistryDataTask.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciRegistryDataTask.kt @@ -1,6 +1,6 @@ package io.github.sgtsilvio.gradle.oci -import io.github.sgtsilvio.gradle.oci.metadata.OciDataDescriptor +import io.github.sgtsilvio.gradle.oci.metadata.OciData import io.github.sgtsilvio.gradle.oci.metadata.OciDigest import io.github.sgtsilvio.gradle.oci.metadata.OciImageReference import org.gradle.api.file.DirectoryProperty @@ -32,8 +32,8 @@ abstract class OciRegistryDataTask : OciImagesInputTask() { blobsDirectory.resolveDigestDataFile(digest).createLinkPointingTo(layerFile.toPath()) } for (image in images) { - blobsDirectory.writeDigestData(image.config) - blobsDirectory.writeDigestData(image.manifest) + blobsDirectory.writeDigestData(image.config.data) + blobsDirectory.writeDigestData(image.manifest.data) } for ((multiArchImage, imageReferences) in multiArchImageAndReferencesPairs) { blobsDirectory.writeDigestData(multiArchImage.index) @@ -74,13 +74,13 @@ abstract class OciRegistryDataTask : OciImagesInputTask() { .resolve("data") } - private fun Path.writeDigestData(dataDescriptor: OciDataDescriptor) { - val digestDataFile = resolveDigestDataFile(dataDescriptor.digest) + private fun Path.writeDigestData(data: OciData) { + val digestDataFile = resolveDigestDataFile(data.digest) try { - digestDataFile.writeBytes(dataDescriptor.data, StandardOpenOption.CREATE_NEW) + digestDataFile.writeBytes(data.bytes, StandardOpenOption.CREATE_NEW) } catch (e: FileAlreadyExistsException) { - if (!dataDescriptor.data.contentEquals(digestDataFile.readBytes())) { - throw IllegalStateException("hash collision for digest ${dataDescriptor.digest}: expected file content of $digestDataFile to be the same as ${dataDescriptor.data.contentToString()}") + if (!data.bytes.contentEquals(digestDataFile.readBytes())) { + throw IllegalStateException("hash collision for digest ${data.digest}: expected file content of $digestDataFile to be the same as ${data.bytes.contentToString()}") } } } diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciMetadataRegistry.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciMetadataRegistry.kt index 8797f18a..b4d1f8e3 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciMetadataRegistry.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciMetadataRegistry.kt @@ -32,7 +32,7 @@ internal class OciMetadataRegistry(val registryApi: OciRegistryApi) { ): Mono> = registryApi.pullManifest(registry, imageReference.name, digest, size, credentials) .transformToMetadataList(registry, imageReference, credentials) - private fun Mono.transformToMetadataList( + private fun Mono.transformToMetadataList( registry: String, imageReference: OciImageReference, credentials: Credentials?, @@ -43,7 +43,7 @@ internal class OciMetadataRegistry(val registryApi: OciRegistryApi) { private fun transformToMetadataList( registry: String, imageReference: OciImageReference, - manifest: OciRegistryApi.Manifest, + manifest: OciData, credentials: Credentials?, ): Mono> = when (manifest.mediaType) { INDEX_MEDIA_TYPE -> transformIndexToMetadataList( @@ -90,13 +90,13 @@ internal class OciMetadataRegistry(val registryApi: OciRegistryApi) { private fun transformIndexToMetadataList( registry: String, imageReference: OciImageReference, - index: OciRegistryApi.Manifest, + index: OciData, credentials: Credentials?, manifestMediaType: String, configMediaType: String, layerMediaTypePrefix: String, ): Mono> { - val indexJsonObject = jsonObject(String(index.data)) + val indexJsonObject = jsonObject(String(index.bytes)) val indexAnnotations = indexJsonObject.getStringMapOrEmpty("annotations") val metadataMonoList = indexJsonObject.get("manifests") { asArray().toList { @@ -142,7 +142,7 @@ internal class OciMetadataRegistry(val registryApi: OciRegistryApi) { private fun transformManifestToMetadataList( registry: String, imageReference: OciImageReference, - manifest: OciRegistryApi.Manifest, + manifest: OciData, credentials: Credentials?, configMediaType: String, layerMediaTypePrefix: String, @@ -160,14 +160,14 @@ internal class OciMetadataRegistry(val registryApi: OciRegistryApi) { private fun transformManifestToMetadata( registry: String, imageReference: OciImageReference, - manifest: OciRegistryApi.Manifest, + manifest: OciData, manifestDescriptorAnnotations: SortedMap, indexAnnotations: SortedMap, credentials: Credentials?, configMediaType: String, layerMediaTypePrefix: String, ): Mono { - val manifestJsonObject = jsonObject(String(manifest.data)) + val manifestJsonObject = jsonObject(String(manifest.bytes)) val manifestAnnotations = manifestJsonObject.getStringMapOrEmpty("annotations") val configDescriptor = manifestJsonObject.get("config") { asObject().decodeOciDescriptor() } val layerDescriptors = @@ -294,7 +294,7 @@ internal class OciMetadataRegistry(val registryApi: OciRegistryApi) { ), Platform(os, architecture, variant, osVersion, osFeatures), manifest.digest, - manifest.data.size, + manifest.bytes.size, ) } } diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRegistryApi.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRegistryApi.kt index c330f6e1..7fdc8ac7 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRegistryApi.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/registry/OciRegistryApi.kt @@ -98,14 +98,12 @@ internal class OciRegistryApi(httpClient: HttpClient) { ) = currentDuration } - class Manifest(val mediaType: String, val data: ByteArray, val digest: OciDigest) - private fun pullManifestInternal( registry: String, imageName: String, reference: String, credentials: Credentials?, - ): Mono { + ): Mono { return send( registry, imageName, @@ -125,7 +123,7 @@ internal class OciRegistryApi(httpClient: HttpClient) { val digestAlgorithm = response.responseHeaders()["docker-content-digest"]?.toOciDigest()?.algorithm ?: OciDigestAlgorithm.SHA_256 - Manifest(contentType, data, data.calculateOciDigest(digestAlgorithm)) + OciData(contentType, data, digestAlgorithm) } } ?: createError(response, body.aggregate()) @@ -139,7 +137,7 @@ internal class OciRegistryApi(httpClient: HttpClient) { imageName: String, reference: String, credentials: Credentials?, - ): Mono = when { + ): Mono = when { ':' in reference -> pullManifest(registry, imageName, reference.toOciDigest(), -1, credentials) else -> pullManifestInternal(registry, imageName, reference, credentials) } @@ -150,8 +148,8 @@ internal class OciRegistryApi(httpClient: HttpClient) { digest: OciDigest, size: Int, credentials: Credentials?, - ): Mono = pullManifestInternal(registry, imageName, digest.toString(), credentials).map { manifest -> - val manifestBytes = manifest.data + ): Mono = pullManifestInternal(registry, imageName, digest.toString(), credentials).map { manifest -> + val manifestBytes = manifest.bytes if ((size != -1) && (size != manifestBytes.size)) { throw sizeMismatchException(size.toLong(), manifestBytes.size.toLong()) } diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciDescriptor.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciDescriptor.kt index b2691997..15ea55dc 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciDescriptor.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciDescriptor.kt @@ -19,12 +19,19 @@ internal data class OciDescriptorImpl( override val annotations: SortedMap, ) : OciDescriptor -internal class OciDataDescriptor( - override val mediaType: String, - val data: ByteArray, +internal class OciData( + val mediaType: String, + val bytes: ByteArray, digestAlgorithm: OciDigestAlgorithm, +) { + val digest = bytes.calculateOciDigest(digestAlgorithm) +} + +internal class OciDataDescriptor( + val data: OciData, override val annotations: SortedMap, ) : OciDescriptor { - override val digest = data.calculateOciDigest(digestAlgorithm) - override val size get() = data.size.toLong() + override val mediaType get() = data.mediaType + override val digest get() = data.digest + override val size get() = data.bytes.size.toLong() } diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciMetadataFiles.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciMetadataFiles.kt index c784c748..11fc4d5d 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciMetadataFiles.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/metadata/OciMetadataFiles.kt @@ -82,9 +82,7 @@ internal fun createConfig(platform: Platform, variants: List): OciDa addStringIfNotEmpty("variant", platform.variant) }.toByteArray() return OciDataDescriptor( - CONFIG_MEDIA_TYPE, - data, - OciDigestAlgorithm.SHA_256, + OciData(CONFIG_MEDIA_TYPE, data, OciDigestAlgorithm.SHA_256), lastVariantMetadata.configDescriptorAnnotations, // TODO lastVariantMetadata? ) } @@ -106,14 +104,12 @@ internal fun createManifest(configDescriptor: OciDescriptor, variants: List): OciDataDescriptor { +internal fun createIndex(platformToImage: Map): OciData { val indexAnnotations = TreeMap() val images = platformToImage.values if (images.isNotEmpty()) { @@ -134,7 +130,7 @@ internal fun createIndex(platformToImage: Map): OciDataDescr addString("mediaType", INDEX_MEDIA_TYPE) addNumber("schemaVersion", 2) }.toByteArray() - return OciDataDescriptor(INDEX_MEDIA_TYPE, data, OciDigestAlgorithm.SHA_256, TreeMap()) + return OciData(INDEX_MEDIA_TYPE, data, OciDigestAlgorithm.SHA_256) } private fun JsonObjectStringBuilder.encodeOciDescriptor(descriptor: OciDescriptor) {