Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 51 additions & 24 deletions oci/private/tarball.sh.tpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
# Produce an mtree specification file for creating a tarball in the form needed for `docker load`.
# This doesn't actually run `tar` because that large output is often not required by any other actions in the graph and causes load on the cache.

set -o pipefail -o errexit -o nounset

readonly FORMAT="{{format}}"
Expand Down Expand Up @@ -37,8 +38,8 @@ if [[ "${FORMAT}" != "docker" && "${FORMAT}" != "oci" ]]; then
echo >&2 "Unknown format: ${FORMAT}. Only support docker|oci"
exit 1
fi
if [[ "${FORMAT}" == "oci" && "${MEDIA_TYPE}" != "application/vnd.oci.image.index.v1+json" && "${MEDIA_TYPE}" != "application/vnd.docker.distribution.manifest.v2+json" ]]; then
echo >&2 "Format oci is only supported for oci_image_index targets but saw ${MEDIA_TYPE}"
if [[ "${FORMAT}" == "oci" && "${MEDIA_TYPE}" != "application/vnd.oci.image.index.v1+json" && "${MEDIA_TYPE}" != "application/vnd.oci.image.manifest.v1+json" && "${MEDIA_TYPE}" != "application/vnd.docker.distribution.manifest.v2+json" ]]; then
echo >&2 "Format oci is only supported for oci_image_index or oci_image targets but saw ${MEDIA_TYPE}"
exit 1
fi
if [[ "${FORMAT}" == "docker" && "${MEDIA_TYPE}" != "application/vnd.oci.image.manifest.v1+json" && "${MEDIA_TYPE}" != "application/vnd.docker.distribution.manifest.v2+json" ]]; then
Expand All @@ -47,43 +48,67 @@ if [[ "${FORMAT}" == "docker" && "${MEDIA_TYPE}" != "application/vnd.oci.image.m
fi

if [[ "${FORMAT}" == "oci" ]]; then
# Handle multi-architecture image indexes.
# Ideally the toolchains we rely on would output these for us, but they don't seem to.
if [[ "${MEDIA_TYPE}" != "application/vnd.oci.image.manifest.v1+json" ]]; then
# Handle oci_image_index multi-architecture image indexes.
# Ideally the toolchains we rely on would output these for us, but they don't seem to.
Comment on lines 50 to +53

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Multi-arch indexes routed through single-image branch

The new OCI branch decides whether to treat the input as an index or a single image by checking MEDIA_TYPE against application/vnd.oci.image.manifest.v1+json. MEDIA_TYPE is derived from .manifests[0].mediaType, which is also application/vnd.oci.image.manifest.v1+json for multi-architecture oci_image_index outputs. After this change such indexes now execute the single-image path, so only the first manifest’s config and layers are added and the index.json is not rewritten for additional architectures. Multi-arch tarballs will therefore be missing secondary platforms. The branch should detect indexes via the number of manifests or the top-level media type instead of a string comparison to the first manifest’s type.

Useful? React with 👍 / 👎.

add_to_tar "${IMAGE_DIR}/oci-layout" oci-layout

INDEX_FILE_MANIFEST_DIGEST=$("${JQ}" -r '.manifests[0].digest | sub(":"; "/")' "${INDEX_FILE}" | "${COREUTILS}" tr -d '"')
INDEX_FILE_MANIFEST_BLOB_PATH="${IMAGE_DIR}/blobs/${INDEX_FILE_MANIFEST_DIGEST}"

add_to_tar "${INDEX_FILE_MANIFEST_BLOB_PATH}" "blobs/${INDEX_FILE_MANIFEST_DIGEST}"

IMAGE_MANIFESTS_DIGESTS=($("${JQ}" -r '.manifests[] | .digest | sub(":"; "/")' "${INDEX_FILE_MANIFEST_BLOB_PATH}"))

add_to_tar "${IMAGE_DIR}/oci-layout" oci-layout
for IMAGE_MANIFEST_DIGEST in "${IMAGE_MANIFESTS_DIGESTS[@]}"; do
IMAGE_MANIFEST_BLOB_PATH="${IMAGE_DIR}/blobs/${IMAGE_MANIFEST_DIGEST}"
add_to_tar "${IMAGE_MANIFEST_BLOB_PATH}" "blobs/${IMAGE_MANIFEST_DIGEST}"

INDEX_FILE_MANIFEST_DIGEST=$("${JQ}" -r '.manifests[0].digest | sub(":"; "/")' "${INDEX_FILE}" | "${COREUTILS}" tr -d '"')
INDEX_FILE_MANIFEST_BLOB_PATH="${IMAGE_DIR}/blobs/${INDEX_FILE_MANIFEST_DIGEST}"
CONFIG_DIGEST=$("${JQ}" -r '.config.digest | sub(":"; "/")' ${IMAGE_MANIFEST_BLOB_PATH})
CONFIG_BLOB_PATH="${IMAGE_DIR}/blobs/${CONFIG_DIGEST}"
add_to_tar "${CONFIG_BLOB_PATH}" "blobs/${CONFIG_DIGEST}"

add_to_tar "${INDEX_FILE_MANIFEST_BLOB_PATH}" "blobs/${INDEX_FILE_MANIFEST_DIGEST}"
LAYER_DIGESTS=$("${JQ}" -r '.layers | map(.digest | sub(":"; "/"))' "${IMAGE_MANIFEST_BLOB_PATH}")
for LAYER_DIGEST in $("${JQ}" -r ".[]" <<< $LAYER_DIGESTS); do
# remove control characters; causing test failures on windows
LAYER_DIGEST=$("${COREUTILS}" tr -d '[:cntrl:]' <<< "${LAYER_DIGEST}")
add_to_tar "${IMAGE_DIR}/blobs/${LAYER_DIGEST}" blobs/${LAYER_DIGEST}
done
done

# Repeat the first manifest entry once per repo tag.
repotags="${REPOTAGS[@]+"${REPOTAGS[@]}"}"
"${JQ}" >"{{json_out}}" \
-r --arg repo_tags "$repotags" \
'.manifests[0] as $manifest | .manifests = ($repo_tags | split(" ") | map($manifest * {annotations:{"org.opencontainers.image.ref.name":.}}))' "${INDEX_FILE}"
add_to_tar "{{json_out}}" index.json

IMAGE_MANIFESTS_DIGESTS=($("${JQ}" -r '.manifests[] | .digest | sub(":"; "/")' "${INDEX_FILE_MANIFEST_BLOB_PATH}"))
else
# Handle oci_image targets with a single manifest
add_to_tar "${IMAGE_DIR}/oci-layout" oci-layout

for IMAGE_MANIFEST_DIGEST in "${IMAGE_MANIFESTS_DIGESTS[@]}"; do
IMAGE_MANIFEST_BLOB_PATH="${IMAGE_DIR}/blobs/${IMAGE_MANIFEST_DIGEST}"
add_to_tar "${IMAGE_MANIFEST_BLOB_PATH}" "blobs/${IMAGE_MANIFEST_DIGEST}"
MANIFEST_DIGEST=$(${JQ} -r '.manifests[0].digest | sub(":"; "/")' "${IMAGE_DIR}/index.json" | "${COREUTILS}" tr -d '"')
MANIFEST_BLOB_PATH="${IMAGE_DIR}/blobs/${MANIFEST_DIGEST}"
add_to_tar "${MANIFEST_BLOB_PATH}" "blobs/${MANIFEST_DIGEST}"

CONFIG_DIGEST=$("${JQ}" -r '.config.digest | sub(":"; "/")' ${IMAGE_MANIFEST_BLOB_PATH})
CONFIG_DIGEST=$(${JQ} -r '.config.digest | sub(":"; "/")' ${MANIFEST_BLOB_PATH})
CONFIG_BLOB_PATH="${IMAGE_DIR}/blobs/${CONFIG_DIGEST}"
add_to_tar "${CONFIG_BLOB_PATH}" "blobs/${CONFIG_DIGEST}"

LAYER_DIGESTS=$("${JQ}" -r '.layers | map(.digest | sub(":"; "/"))' "${IMAGE_MANIFEST_BLOB_PATH}")
for LAYER_DIGEST in $("${JQ}" -r ".[]" <<< $LAYER_DIGESTS); do
LAYERS=$(${JQ} -cr '.layers | map(.digest | sub(":"; "/"))' ${MANIFEST_BLOB_PATH})
for LAYER_DIGEST in $("${JQ}" -r ".[]" <<< $LAYERS); do
# remove control characters; causing test failures on windows
LAYER_DIGEST=$("${COREUTILS}" tr -d '[:cntrl:]' <<< "${LAYER_DIGEST}")
add_to_tar "${IMAGE_DIR}/blobs/${LAYER_DIGEST}" blobs/${LAYER_DIGEST}
done
done


# Repeat the first manifest entry once per repo tag.
repotags="${REPOTAGS[@]+"${REPOTAGS[@]}"}"
"${JQ}" >"{{json_out}}" \
-r --arg repo_tags "$repotags" \
'.manifests[0] as $manifest | .manifests = ($repo_tags | split(" ") | map($manifest * {annotations:{"org.opencontainers.image.ref.name":.}}))' "${INDEX_FILE}"
add_to_tar "{{json_out}}" index.json

add_to_tar "${IMAGE_DIR}/index.json" index.json
cp "${MANIFEST_BLOB_PATH}" "{{json_out}}"
fi
exit 0
fi

# Handle docker format
MANIFEST_DIGEST=$(${JQ} -r '.manifests[0].digest | sub(":"; "/")' "${IMAGE_DIR}/index.json" | "${COREUTILS}" tr -d '"')
MANIFEST_BLOB_PATH="${IMAGE_DIR}/blobs/${MANIFEST_DIGEST}"

Expand All @@ -95,6 +120,8 @@ LAYERS=$(${JQ} -cr '.layers | map(.digest | sub(":"; "/"))' ${MANIFEST_BLOB_PATH
add_to_tar "${CONFIG_BLOB_PATH}" "blobs/${CONFIG_DIGEST}"

for LAYER in $(${JQ} -r ".[]" <<< $LAYERS); do
# remove control characters; causing test failures on windows
LAYER=$("${COREUTILS}" tr -d '[:cntrl:]' <<< "${LAYER}")
add_to_tar "${IMAGE_DIR}/blobs/${LAYER}" "blobs/${LAYER}.tar.gz"
done

Expand Down