diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciRegistryDataTask.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciRegistryDataTask.kt deleted file mode 100644 index e78d403f..00000000 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/OciRegistryDataTask.kt +++ /dev/null @@ -1,119 +0,0 @@ -package io.github.sgtsilvio.gradle.oci - -import io.github.sgtsilvio.gradle.oci.component.ResolvedOciComponent -import io.github.sgtsilvio.gradle.oci.metadata.* -import io.github.sgtsilvio.gradle.oci.platform.Platform -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.tasks.OutputDirectory -import java.io.File -import java.io.IOException -import java.nio.file.FileAlreadyExistsException -import java.nio.file.Path -import java.nio.file.StandardOpenOption -import kotlin.io.path.* - -/** - * @author Silvio Giebl - */ -abstract class OciRegistryDataTask : OciImagesInputTask() { - - @get:OutputDirectory - val registryDataDirectory: DirectoryProperty = project.objects.directoryProperty() - - override fun run( - resolvedComponentToImageReferences: Map>, - digestToLayer: Map, - ) { - val registryDataDirectory = registryDataDirectory.get().asFile.toPath().ensureEmptyDirectory() - val blobsDirectory = registryDataDirectory.resolve("blobs").createDirectory() - val repositoriesDirectory = registryDataDirectory.resolve("repositories").createDirectory() - val layerDigests = mutableSetOf() - for ((resolvedComponent, imageReferences) in resolvedComponentToImageReferences) { - writeImage(resolvedComponent, imageReferences, blobsDirectory, repositoriesDirectory, layerDigests) - } - for (digest in layerDigests) { - blobsDirectory.resolveDigestFile(digest).createLinkPointingTo(digestToLayer[digest]!!.toPath()) - } - } - - private fun writeImage( - resolvedComponent: ResolvedOciComponent, - imageReferences: Set, - blobsDirectory: Path, - repositoriesDirectory: Path, - layerDigests: MutableSet, - ) { - val manifests = mutableListOf>() - val blobDigests = mutableSetOf() - for (platform in resolvedComponent.platforms) { - val bundlesForPlatform = resolvedComponent.collectBundlesForPlatform(platform).map { it.bundle } - for (bundle in bundlesForPlatform) { - for (layer in bundle.layers) { - layer.descriptor?.let { (_, digest) -> - layerDigests += digest - blobDigests += digest - } - } - } - val config = createConfig(platform, bundlesForPlatform) - blobsDirectory.writeDigestData(config) - blobDigests += config.digest - val manifest = createManifest(config, bundlesForPlatform) - blobsDirectory.writeDigestData(manifest) - manifests += Pair(platform, manifest) - } - val index = createIndex(manifests, resolvedComponent.component) - blobsDirectory.writeDigestData(index) - val indexDigest = index.digest - - for (imageReference in imageReferences) { - val repositoryDirectory = repositoriesDirectory.resolve(imageReference.name).createDirectories() - val repositoryBlobsDirectory = repositoryDirectory.resolve("blobs").createDirectories() - for (blobDigest in blobDigests) { - repositoryBlobsDirectory.writeDigestLink(blobDigest) - } - val manifestsDirectory = repositoryDirectory.resolve("manifests").createDirectories() - for ((_, manifestDescriptor) in manifests) { - manifestsDirectory.writeDigestLink(manifestDescriptor.digest) - } - manifestsDirectory.writeDigestLink(indexDigest) - manifestsDirectory.resolve(imageReference.tag).writeTagLink(indexDigest) - } - } - - private fun Path.resolveDigestFile(digest: OciDigest): Path = - resolve(digest.algorithm.ociPrefix).createDirectories().resolve(digest.encodedHash) - - private fun Path.writeDigestData(dataDescriptor: OciDataDescriptor) { - val digestDataFile = resolveDigestFile(dataDescriptor.digest) - try { - digestDataFile.writeBytes(dataDescriptor.data, 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()}") - } - } - } - - private fun Path.writeDigestLink(digest: OciDigest) { - resolveDigestFile(digest).writeBytes(digest.toString().toByteArray()) - } - - private fun Path.writeTagLink(digest: OciDigest) { - val digestBytes = digest.toString().toByteArray() - try { - writeBytes(digestBytes, StandardOpenOption.CREATE_NEW) - } catch (e: FileAlreadyExistsException) { - if (!digestBytes.contentEquals(readBytes())) { - throw IllegalStateException("tried to link the same image name/tag to different images") - } - } - } -} - -internal fun Path.ensureEmptyDirectory(): Path { - if (!toFile().deleteRecursively()) { - throw IOException("$this could not be deleted") - } - return createDirectories() -} diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/dsl/OciExtension.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/dsl/OciExtension.kt index e8ed6be4..536207c4 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/dsl/OciExtension.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/dsl/OciExtension.kt @@ -1,8 +1,8 @@ package io.github.sgtsilvio.gradle.oci.dsl +import io.github.sgtsilvio.gradle.oci.DistributionRegistryDataTask import io.github.sgtsilvio.gradle.oci.OciLayerTask import io.github.sgtsilvio.gradle.oci.OciPushTask -import io.github.sgtsilvio.gradle.oci.OciRegistryDataTask import io.github.sgtsilvio.gradle.oci.mapping.OciImageMapping import io.github.sgtsilvio.gradle.oci.platform.Platform import io.github.sgtsilvio.gradle.oci.platform.PlatformFilter @@ -18,7 +18,7 @@ import org.gradle.api.tasks.testing.Test interface OciExtension { val layerTaskClass get() = OciLayerTask::class val pushTaskClass get() = OciPushTask::class - val registryDataTaskClass get() = OciRegistryDataTask::class + val registryDataTaskClass get() = DistributionRegistryDataTask::class val registries: OciRegistries val imageMapping: OciImageMapping diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciExtensionImpl.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciExtensionImpl.kt index fd9cbbb3..4af8f6b7 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciExtensionImpl.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciExtensionImpl.kt @@ -1,6 +1,6 @@ package io.github.sgtsilvio.gradle.oci.internal.dsl -import io.github.sgtsilvio.gradle.oci.OciRegistryDataTask +import io.github.sgtsilvio.gradle.oci.DistributionRegistryDataTask import io.github.sgtsilvio.gradle.oci.TASK_GROUP_NAME import io.github.sgtsilvio.gradle.oci.dsl.OciExtension import io.github.sgtsilvio.gradle.oci.dsl.OciImageDefinition @@ -89,9 +89,9 @@ internal abstract class OciExtensionImpl @Inject constructor( val testTaskName = testTask.name val registryDataTaskName = "${testTaskName}OciRegistryData" val registryDataTask = if (registryDataTaskName in taskContainer.names) { - taskContainer.named(registryDataTaskName) + taskContainer.named(registryDataTaskName) } else { - val registryDataTask = taskContainer.register(registryDataTaskName) { + val registryDataTask = taskContainer.register(registryDataTaskName) { group = TASK_GROUP_NAME description = "Creates a Docker registry data directory to be used by the $testTaskName task." registryDataDirectory.set(projectLayout.buildDirectory.dir("oci/registries/$testTaskName")) diff --git a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciTestArgumentProvider.kt b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciTestArgumentProvider.kt index 21b16d93..2eac4ea1 100644 --- a/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciTestArgumentProvider.kt +++ b/src/main/kotlin/io/github/sgtsilvio/gradle/oci/internal/dsl/OciTestArgumentProvider.kt @@ -1,6 +1,6 @@ package io.github.sgtsilvio.gradle.oci.internal.dsl -import io.github.sgtsilvio.gradle.oci.OciRegistryDataTask +import io.github.sgtsilvio.gradle.oci.DistributionRegistryDataTask import org.gradle.api.file.FileTree import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Provider @@ -15,7 +15,7 @@ import org.gradle.process.CommandLineArgumentProvider */ internal class OciTestArgumentProvider( objectFactory: ObjectFactory, - registryDataTask: TaskProvider, + registryDataTask: TaskProvider, ) : CommandLineArgumentProvider { @get:InputFiles