diff --git a/packages/by-name/ociImageConfig/package.nix b/packages/by-name/ociImageConfig/package.nix new file mode 100644 index 0000000000..20914adf30 --- /dev/null +++ b/packages/by-name/ociImageConfig/package.nix @@ -0,0 +1,28 @@ +# application/vnd.oci.image.config.v1+json +{ runCommand, writers, lib, pkgs }: +{ layers ? [ ] +, extraConfig ? { } +}: +let + diffIDs = lib.lists.map (layer: builtins.readFile (layer + "/DiffID")) layers; + config = { + architecture = "amd64"; + os = "linux"; + } // extraConfig // { + rootfs = { type = "layers"; diff_ids = diffIDs; }; + }; + configJSON = writers.writeJSON "image-config.json" config; +in +runCommand "oci-image-config" +{ + buildInputs = [ pkgs.nix ]; + platformJSON = builtins.toJSON { inherit (config) architecture; inherit (config) os; }; + inherit configJSON; +} '' + mkdir -p $out/blobs/sha256 + sha256=$(nix-hash --type sha256 --flat $configJSON) + cp $configJSON "$out/blobs/sha256/$sha256" + ln -s "$out/blobs/sha256/$sha256" "$out/image-config.json" + echo "$platformJSON" > "$out/platform.json" + echo -n "{\"mediaType\": \"application/vnd.oci.image.config.v1+json\", \"size\": $(stat -c %s $configJSON), \"digest\": \"sha256:$sha256\"}" > $out/media-descriptor.json +'' diff --git a/packages/by-name/ociImageLayout/package.nix b/packages/by-name/ociImageLayout/package.nix new file mode 100644 index 0000000000..32e2b9c8e7 --- /dev/null +++ b/packages/by-name/ociImageLayout/package.nix @@ -0,0 +1,36 @@ +# OCI image layout. Can be pushed to a registry or used as a local image. +{ runCommand +, writers +, lib +, pkgs +}: +{ manifests ? [ ] +, extraIndex ? { } +}: +let + manifestDescriptors = lib.lists.map (manifest: builtins.fromJSON (builtins.readFile (manifest + "/media-descriptor.json"))) manifests; + index = writers.writeJSON "index.json" ( + { + schemaVersion = 2; + mediaType = "application/vnd.oci.image.index.v1+json"; + } // extraIndex // { + manifests = manifestDescriptors; + } + ); +in +runCommand "oci-image-layout" +{ + buildInputs = [ pkgs.nix ]; + blobDirs = lib.lists.map (manifest: manifest + "/blobs/sha256") manifests; + inherit index; +} '' + srcs=($blobDirs) + mkdir -p $out/blobs/sha256 + cp $index $out/index.json + echo '{"imageLayoutVersion": "1.0.0"}' > $out/image-layout + for src in $srcs; do + for blob in $(ls $src); do + ln -s "$(realpath $src/$blob)" "$out/blobs/sha256/$blob" + done + done +'' diff --git a/packages/by-name/ociImageManifest/package.nix b/packages/by-name/ociImageManifest/package.nix new file mode 100644 index 0000000000..e8e9d22e4e --- /dev/null +++ b/packages/by-name/ociImageManifest/package.nix @@ -0,0 +1,44 @@ +# application/vnd.oci.image.manifest.v1+json +{ ociImageConfig +, runCommand +, writers +, lib +, pkgs +}: +{ layers ? [ ] +, extraConfig ? { } +, extraManifest ? { } +}: +let + config = ociImageConfig { inherit layers extraConfig; }; + configDescriptor = builtins.fromJSON (builtins.readFile (config + "/media-descriptor.json")); + configPlatform = builtins.fromJSON (builtins.readFile (config + "/platform.json")); + layerDescriptors = lib.lists.map (layer: builtins.fromJSON (builtins.readFile (layer + "/media-descriptor.json"))) layers; + manifest = writers.writeJSON "image-manifest.json" ( + { + schemaVersion = 2; + mediaType = "application/vnd.oci.image.manifest.v1+json"; + } // extraManifest // { + config = configDescriptor; + layers = layerDescriptors; + } + ); +in +runCommand "oci-image-manifest" +{ + blobDirs = lib.lists.map (layer: layer + "/blobs/sha256") (layers ++ [ config ]); + platformJSON = builtins.toJSON configPlatform; + buildInputs = [ pkgs.nix ]; + inherit manifest; +} '' + mkdir -p $out/blobs/sha256 + sha256=$(nix-hash --type sha256 --flat $manifest) + cp $manifest "$out/blobs/sha256/$sha256" + ln -s "$out/blobs/sha256/$sha256" "$out/image-manifest.json" + echo -n "{\"mediaType\": \"application/vnd.oci.image.manifest.v1+json\", \"size\": $(stat -c %s $manifest), \"digest\": \"sha256:$sha256\", \"platform\": $platformJSON}" > $out/media-descriptor.json + for src in $blobDirs; do + for blob in $(ls $src); do + ln -s "$src/$blob" "$out/blobs/sha256/$blob" + done + done +'' diff --git a/packages/by-name/ociLayerTar/package.nix b/packages/by-name/ociLayerTar/package.nix new file mode 100644 index 0000000000..4cfce9fbb3 --- /dev/null +++ b/packages/by-name/ociLayerTar/package.nix @@ -0,0 +1,42 @@ +# application/vnd.oci.image.layer.v1.tar +# application/vnd.oci.image.layer.v1.tar+gzip +# application/vnd.oci.image.layer.v1.tar+zstd +{ runCommand, lib, pkgs }: +{ files ? [ ] +, compression ? "gzip" +}: +runCommand "ociLayer" +{ + fileSources = lib.lists.map (file: file.source) files; + fileDestinations = lib.lists.map (file: file.destination or file.source) files; + outPath = "layer" + (if compression == "gzip" then ".tar.gz" else if compression == "zstd" then ".tar.zst" else ".tar"); + mediaType = "application/vnd.oci.image.layer.v1.tar" + (if compression == "" then "" else "+" + compression); + buildInputs = [ pkgs.nix ] ++ lib.optional (compression == "gzip") pkgs.gzip ++ lib.optional (compression == "zstd") pkgs.zstd; + inherit compression; +} '' + set -o pipefail + srcs=($fileSources) + dests=($fileDestinations) + mkdir -p $out/root + for i in ''${!srcs[@]}; do + mkdir -p "$out/root/$(dirname ''${dests[$i]})" + cp -rT "''${srcs[i]}" "$out/root/''${dests[$i]}" + done + tar --sort=name --owner=root:0 --group=root:0 --mode=544 --mtime='UTC 1970-01-01' -cC $out/root -f $out/layer.tar . + diffID=$(nix-hash --type sha256 --flat $out/layer.tar) + if [ "$compression" = "gzip" ]; then + gzip -c $out/layer.tar > $out/$outPath + elif [ "$compression" = "zstd" ]; then + zstd -T0 -q -c $out/layer.tar > $out/$outPath + else + mv $out/layer.tar $out/$outPath + fi + rm -f $out/layer.tar + sha256=$(nix-hash --type sha256 --flat $out/$outPath) + echo -n "{\"mediaType\": \"$mediaType\", \"size\": $(stat -c %s $out/$outPath), \"digest\": \"sha256:$sha256\"}" > $out/media-descriptor.json + echo -n "sha256:$diffID" > $out/DiffID + mkdir -p $out/blobs/sha256 + mv $out/$outPath $out/blobs/sha256/$sha256 + ln -s $out/blobs/sha256/$sha256 $out/$outPath + rm -rf $out/root +''