From 82d5b6ab077f689485d9631c4744b424be30b7d2 Mon Sep 17 00:00:00 2001 From: Joseph Glanville Date: Thu, 27 Apr 2023 01:50:25 +0700 Subject: [PATCH] feat: Allow stampable repotags for oci_tarball (#185) Co-authored-by: Alex Eagle --- docs/tarball.md | 2 +- oci/defs.bzl | 30 +++++++++++++++++++++++++++++- oci/private/tarball.bzl | 28 +++++++++++++++++++--------- oci/private/tarball.sh.tpl | 9 +++++++-- 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/docs/tarball.md b/docs/tarball.md index 50f854eb..7b51bb7c 100644 --- a/docs/tarball.md +++ b/docs/tarball.md @@ -41,6 +41,6 @@ Passing anything other than oci_image to the image attribute will lead to build | :------------- | :------------- | :------------- | :------------- | :------------- | | name | A unique name for this target. | Name | required | | | image | Label of a directory containing an OCI layout, typically oci_image | Label | required | | -| repotags | List of repository+tags to apply to the loaded image | List of strings | required | | +| repotags | a file containing repotags, one per line. | Label | optional | None | diff --git a/oci/defs.bzl b/oci/defs.bzl index 5312908b..8fba4f14 100644 --- a/oci/defs.bzl +++ b/oci/defs.bzl @@ -8,7 +8,7 @@ load("//oci/private:structure_test.bzl", _structure_test = "structure_test") load("@bazel_skylib//lib:types.bzl", "types") load("@bazel_skylib//rules:write_file.bzl", "write_file") -oci_tarball = _oci_tarball +oci_tarball_rule = _oci_tarball oci_image_rule = _oci_image oci_image_index = _oci_image_index oci_push_rule = _oci_push @@ -82,3 +82,31 @@ def oci_push(name, repotags = None, **kwargs): repotags = repotags, **kwargs ) + +def oci_tarball(name, repotags = None, **kwargs): + """Macro wrapper around [oci_tarball_rule](#oci_tarball_rule). + + Allows the repotags attribute to be a list of strings in addition to a text file. + + Args: + name: name of resulting oci_tarball_rule + repotags: a list of repository:tag to specify when loading the image, + or a label of a file containing tags one-per-line. + See [stamped_tags](https://github.com/bazel-contrib/rules_oci/blob/main/examples/push/stamp_tags.bzl) + as one example of a way to produce such a file. + **kwargs: other named arguments to [oci_tarball_rule](#oci_tarball_rule). + """ + if types.is_list(repotags): + tags_label = "_{}_write_tags".format(name) + write_file( + name = tags_label, + out = "_{}.tags.txt".format(name), + content = repotags, + ) + repotags = tags_label + + oci_tarball_rule( + name = name, + repotags = repotags, + **kwargs + ) diff --git a/oci/private/tarball.bzl b/oci/private/tarball.bzl index b8f62453..442ada64 100644 --- a/oci/private/tarball.bzl +++ b/oci/private/tarball.bzl @@ -34,7 +34,12 @@ Passing anything other than oci_image to the image attribute will lead to build attrs = { "image": attr.label(mandatory = True, allow_single_file = True, doc = "Label of a directory containing an OCI layout, typically `oci_image`"), - "repotags": attr.string_list(mandatory = True, doc = "List of repository+tags to apply to the loaded image"), + "repotags": attr.label( + doc = """\ + a file containing repotags, one per line. + """, + allow_single_file = [".txt"], + ), "_tarball_sh": attr.label(allow_single_file = True, default = "//oci/private:tarball.sh.tpl"), "_build_tar": attr.label( default = Label("@rules_pkg//pkg/private/tar:build_tar"), @@ -75,22 +80,27 @@ def _tarball_impl(ctx): yq_bin = ctx.toolchains["@aspect_bazel_lib//lib:yq_toolchain_type"].yqinfo.bin executable = ctx.actions.declare_file("{}/tarball.sh".format(ctx.label.name)) + + substitutions = { + "{{yq}}": yq_bin.path, + "{{image_dir}}": image.path, + "{{blobs_dir}}": blobs.path, + "{{manifest_path}}": manifest.path, + } + + if ctx.attr.repotags: + substitutions["{{tags}}"] = ctx.file.repotags.path + ctx.actions.expand_template( template = ctx.file._tarball_sh, output = executable, is_executable = True, - substitutions = { - "{{yq}}": yq_bin.path, - "{{image_dir}}": image.path, - "{{blobs_dir}}": blobs.path, - "{{manifest_path}}": manifest.path, - "{{repotags}}": json.encode(ctx.attr.repotags), - }, + substitutions = substitutions, ) ctx.actions.run( executable = executable, - inputs = [image], + inputs = [image, ctx.file.repotags], outputs = [manifest, blobs], tools = [yq_bin], mnemonic = "OCITarball", diff --git a/oci/private/tarball.sh.tpl b/oci/private/tarball.sh.tpl index 515e8e79..e66ab520 100644 --- a/oci/private/tarball.sh.tpl +++ b/oci/private/tarball.sh.tpl @@ -4,9 +4,14 @@ set -o pipefail -o errexit -o nounset readonly YQ="{{yq}}" readonly IMAGE_DIR="{{image_dir}}" readonly BLOBS_DIR="{{blobs_dir}}" -readonly REPOTAGS='{{repotags}}' +readonly TAGS_FILE="{{tags}}" readonly TARBALL_MANIFEST_PATH="{{manifest_path}}" +REPOTAGS=() +# read repotags file as array and prepend it to REPOTAGS array. +IFS=$'\n' REPOTAGSFILE=($(cat "$TAGS_FILE")) +REPOTAGS=(${REPOTAGSFILE[@]+"${REPOTAGSFILE[@]}"} ${REPOTAGS[@]+"${REPOTAGS[@]}"}) + MANIFEST_DIGEST=$(${YQ} eval '.manifests[0].digest | sub(":"; "/")' "${IMAGE_DIR}/index.json") MANIFEST_BLOB_PATH="${IMAGE_DIR}/blobs/${MANIFEST_DIGEST}" @@ -23,7 +28,7 @@ for LAYER in $(${YQ} ".[]" <<< $LAYERS); do done config="blobs/${CONFIG_DIGEST}" \ -repotags="${REPOTAGS}" \ +repotags="${REPOTAGS:-[]}" \ layers="${LAYERS}" \ "${YQ}" eval \ --null-input '.[0] = {"Config": env(config), "RepoTags": env(repotags), "Layers": env(layers) | map( "blobs/" + . + ".tar.gz") }' \