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") }' \