diff --git a/sources/org.osbuild.skopeo b/sources/org.osbuild.skopeo index 52a75f0fb9..8f2988f055 100755 --- a/sources/org.osbuild.skopeo +++ b/sources/org.osbuild.skopeo @@ -86,6 +86,8 @@ class SkopeoSource(sources.SourceService): # direct serialisation of the registry data. dir_name = "container-dir" destination = f"dir:{archive_dir}/{dir_name}" + dest_path = os.path.join(archive_dir, dir_name) + destination = f"dir:{dest_path}" extra_args = [] if not tls_verify: @@ -104,6 +106,9 @@ class SkopeoSource(sources.SourceService): raise RuntimeError( f"Downloaded image {imagename}@{digest} has a id of {downloaded_id}, but expected {image_id}") + # fetch the manifest and merge it into the archive + self.merge_manifest(source, dest_path, extra_args) + # Atomically move download archive into place on successful download with ctx.suppress_oserror(errno.ENOTEMPTY, errno.EEXIST): os.makedirs(f"{self.cache}/{image_id}", exist_ok=True) @@ -112,6 +117,25 @@ class SkopeoSource(sources.SourceService): def exists(self, checksum, _desc): return os.path.exists(f"{self.cache}/{checksum}/container-dir") + def merge_manifest(self, source, destination, extra_args): + with tempfile.TemporaryDirectory(prefix="tmp-download-", dir=self.cache) as indexdir: + # download the manifest(s) to a temporary directory + subprocess.run(["skopeo", "copy", "--multi-arch=index-only", *extra_args, source, f"dir:{indexdir}"], + encoding="utf-8", check=True) + + # calculate the checksum of the manifest of the container image in the destination + manifest_path = os.path.join(destination, "manifest.json") + manifest_checksum = subprocess.check_output(["skopeo", "manifest-digest", manifest_path]).decode().strip() + parts = manifest_checksum.split(":") + assert len(parts) == 2, f"unexpected output for skopeo manifest-digest: {manifest_checksum}" + manifest_checksum = parts[1] + + # rename the manifest to its checksum + os.rename(manifest_path, os.path.join(destination, manifest_checksum + ".manifest.json")) + + # move the index manifest into the destination + os.rename(os.path.join(indexdir, "manifest.json"), manifest_path) + def main(): service = SkopeoSource.from_args(sys.argv[1:])