diff --git a/docs/image.md b/docs/image.md
index e5e0cc01..9011d8ab 100644
--- a/docs/image.md
+++ b/docs/image.md
@@ -75,7 +75,7 @@ oci_image(
| architecture | The CPU architecture which the binaries in this image are built to run on. eg: arm64
, arm
, amd64
, s390x
. See $GOARCH documentation for possible values: https://go.dev/doc/install/source#environment | String | optional | ""
|
| base | Label to an oci_image target to use as the base. | Label | optional | None
|
| cmd | A file containing a comma separated list to be used as the command & args
of the container. These values act as defaults and may be replaced by any specified when creating a container. | Label | optional | None
|
-| entrypoint | A file containing a comma separated list to be used as the entrypoint
to execute when the container starts. These values act as defaults and may be replaced by an entrypoint specified when creating a container. | Label | optional | None
|
+| entrypoint | A file containing a comma separated list to be used as the entrypoint
to execute when the container starts. These values act as defaults and may be replaced by an entrypoint specified when creating a container. NOTE: Setting this attribute will reset the cmd
attribute | Label | optional | None
|
| env | A file containing the default values for the environment variables of the container. These values act as defaults and are merged with any specified when creating a container. Entries replace the base environment variables if any of the entries has conflicting keys. To merge entries with keys specified in the base, ${KEY}
or $KEY
syntax may be used. | Label | optional | None
|
| exposed_ports | A file containing a comma separated list of exposed ports. (e.g. 2000/tcp, 3000/udp or 4000. No protocol defaults to tcp). | Label | optional | None
|
| labels | A file containing a dictionary of labels. Each line should be in the form name=value
. | Label | optional | None
|
diff --git a/examples/assert.bzl b/examples/assert.bzl
index f68dab94..ba4161ac 100644
--- a/examples/assert.bzl
+++ b/examples/assert.bzl
@@ -16,12 +16,14 @@ config_digest=$$($(JQ_BIN) -r '.config.digest | sub(":"; "/")' $$image_path/blob
$(JQ_BIN) 'def pick(p): . as $$v | reduce path(p) as $$p ({{}}; setpath($$p; $$v | getpath($$p))); pick({keys})' "$$image_path/blobs/$$config_digest" > $@
"""
+_DEFAULT_ = {"____I_WILL_NOT_MATCH_ANYTHING__": True}
+
# buildifier: disable=function-docstring-args
def assert_oci_config(
name,
image,
- entrypoint_eq = None,
- cmd_eq = None,
+ entrypoint_eq = _DEFAULT_,
+ cmd_eq = _DEFAULT_,
env_eq = None,
exposed_ports_eq = None,
volumes_eq = None,
@@ -37,9 +39,9 @@ def assert_oci_config(
config = {}
# .config
- if entrypoint_eq:
+ if entrypoint_eq != _DEFAULT_:
config["Entrypoint"] = entrypoint_eq
- if cmd_eq:
+ if cmd_eq != _DEFAULT_:
config["Cmd"] = cmd_eq
if env_eq:
config["Env"] = ["=".join(e) for e in env_eq.items()]
diff --git a/examples/assertion/BUILD.bazel b/examples/assertion/BUILD.bazel
index 6ed05a5a..a79014c9 100644
--- a/examples/assertion/BUILD.bazel
+++ b/examples/assertion/BUILD.bazel
@@ -385,6 +385,55 @@ sh_test(
data = [":case12"],
)
+# Case 15: Setting entrypoint resets cmd
+oci_image(
+ name = "case15_base",
+ architecture = "arm64",
+ cmd = [
+ "-c",
+ "test",
+ ],
+ os = "linux",
+)
+
+assert_oci_config(
+ name = "test_case15_base",
+ cmd_eq = [
+ "-c",
+ "test",
+ ],
+ image = ":case15_base",
+)
+
+oci_image(
+ name = "case15",
+ base = ":case15_base",
+ entrypoint = ["/custom_bin"],
+)
+
+assert_oci_config(
+ name = "test_case15",
+ cmd_eq = None, # cmd should not exist
+ entrypoint_eq = [
+ "/custom_bin",
+ ],
+ image = ":case15",
+)
+
+oci_image(
+ name = "case15_cmd",
+ base = ":case15_base",
+ cmd = ["--arg"],
+ entrypoint = ["/custom_bin"],
+)
+
+assert_oci_config(
+ name = "test_case15_cmd",
+ cmd_eq = ["--arg"],
+ entrypoint_eq = ["/custom_bin"],
+ image = ":case15_cmd",
+)
+
# build them as test.
build_test(
name = "test",
diff --git a/examples/dockerfile/BUILD.bazel b/examples/dockerfile/BUILD.bazel
index 1dc00b1f..887476d4 100644
--- a/examples/dockerfile/BUILD.bazel
+++ b/examples/dockerfile/BUILD.bazel
@@ -40,7 +40,7 @@ oci_image(
assert_oci_config(
name = "assert_metadata",
cmd_eq = ["/app/say.py"],
- entrypoint_eq = [],
+ entrypoint_eq = None,
image = ":image",
)
@@ -50,8 +50,8 @@ assert_oci_image_command(
"jq",
"--version",
],
- image = ":image",
exit_code_eq = 0,
+ image = ":image",
output_eq = "jq-1.6\n",
)
@@ -61,8 +61,8 @@ assert_oci_image_command(
"file",
"/var/lib/apt/lists",
],
- image = ":image",
exit_code_eq = 0,
+ image = ":image",
output_eq = "/var/lib/apt/lists: directory\n",
)
@@ -72,8 +72,8 @@ assert_oci_image_command(
"python",
"/app/say.py",
],
- image = ":image",
exit_code_eq = 0,
+ image = ":image",
output_eq = """\
____
| moo! |
diff --git a/oci/private/image.bzl b/oci/private/image.bzl
index 19b58431..29ee0ec6 100644
--- a/oci/private/image.bzl
+++ b/oci/private/image.bzl
@@ -69,7 +69,7 @@ _attrs = {
The authors recommend [dive](https://github.com/wagoodman/dive) to explore the layering of the resulting image.
"""),
# See: https://github.com/opencontainers/image-spec/blob/main/config.md#properties
- "entrypoint": attr.label(doc = "A file containing a comma separated list to be used as the `entrypoint` to execute when the container starts. These values act as defaults and may be replaced by an entrypoint specified when creating a container.", allow_single_file = True),
+ "entrypoint": attr.label(doc = "A file containing a comma separated list to be used as the `entrypoint` to execute when the container starts. These values act as defaults and may be replaced by an entrypoint specified when creating a container. NOTE: Setting this attribute will reset the `cmd` attribute", allow_single_file = True),
"cmd": attr.label(doc = "A file containing a comma separated list to be used as the `command & args` of the container. These values act as defaults and may be replaced by any specified when creating a container.", allow_single_file = True),
"env": attr.label(doc = """\
A file containing the default values for the environment variables of the container. These values act as defaults and are merged with any specified when creating a container. Entries replace the base environment variables if any of the entries has conflicting keys.
@@ -191,10 +191,17 @@ def _oci_image_impl(ctx):
# tars are already added as input above.
args.add_joined([layer, descriptor], join_with = "=", format_joined = "--layer=%s")
+ # WARNING: entrypoint should always be added before the cmd argument.
+ # This due to implicit behavior which setting entrypoint deletes `cmd`.
+ # See: https://github.com/bazel-contrib/rules_oci/issues/649
if ctx.attr.entrypoint:
args.add(ctx.file.entrypoint.path, format = "--entrypoint=%s")
inputs.append(ctx.file.entrypoint)
+ if ctx.attr.cmd:
+ args.add(ctx.file.cmd.path, format = "--cmd=%s")
+ inputs.append(ctx.file.cmd)
+
if ctx.attr.exposed_ports:
args.add(ctx.file.exposed_ports.path, format = "--exposed-ports=%s")
inputs.append(ctx.file.exposed_ports)
@@ -203,10 +210,6 @@ def _oci_image_impl(ctx):
args.add(ctx.file.volumes.path, format = "--volumes=%s")
inputs.append(ctx.file.volumes)
- if ctx.attr.cmd:
- args.add(ctx.file.cmd.path, format = "--cmd=%s")
- inputs.append(ctx.file.cmd)
-
if ctx.attr.env:
args.add(ctx.file.env.path, format = "--env=%s")
inputs.append(ctx.file.env)
diff --git a/oci/private/image.sh b/oci/private/image.sh
index c5397399..adb60e56 100644
--- a/oci/private/image.sh
+++ b/oci/private/image.sh
@@ -149,7 +149,10 @@ for ARG in "$@"; do
CONFIG=$(jq --rawfile cmd "${ARG#--cmd=}" '.config.Cmd = ($cmd | split(",|\n"; "") | map(select(. | length > 0)))' <<<"$CONFIG")
;;
--entrypoint=*)
- CONFIG=$(jq --rawfile entrypoint "${ARG#--entrypoint=}" '.config.Entrypoint = ($entrypoint | split(",|\n"; "") | map(select(. | length > 0)))' <<<"$CONFIG")
+ # NOTE: setting entrypoint deletes `.config.Cmd` which is consistent with crane and Dockerfile behavior.
+ # See: https://github.com/bazel-contrib/rules_oci/issues/649
+ # See: https://github.com/google/go-containerregistry/blob/c3d1dcc932076c15b65b8b9acfff1d47ded2ebf9/cmd/crane/cmd/mutate.go#L107
+ CONFIG=$(jq --rawfile entrypoint "${ARG#--entrypoint=}" '.config.Cmd = null | .config.Entrypoint = ($entrypoint | split(",|\n"; "") | map(select(. | length > 0)))' <<<"$CONFIG")
;;
--exposed-ports=*)
CONFIG=$(jq --rawfile ep "${ARG#--exposed-ports=}" '.config.ExposedPorts = ($ep | split(",") | map({key: ., value: {}}) | from_entries)' <<<"$CONFIG")
@@ -179,6 +182,6 @@ for ARG in "$@"; do
esac
done
-get_config | jq --argjson config "$CONFIG" '. *= $config' | update_config >/dev/null
+get_config | jq --argjson config "$CONFIG" '. *= $config | del(.config.Cmd|nulls)' | update_config >/dev/null
## TODO: container structure is broken
(JSON="$(coreutils cat "$OUTPUT/index.json")" && jq "del(.manifests[].annotations)" >"$OUTPUT/index.json" <<<"$JSON")