From d4f90f3b84414de02b2e4722f7d932af1d388130 Mon Sep 17 00:00:00 2001 From: Lucas Caudill Date: Mon, 15 Jul 2024 20:25:27 +0000 Subject: [PATCH] add cache validation test --- lib/build.py | 72 +++++++++++++++++++++------------------- lib/modify.py | 9 +++-- test/build/55_cache.bats | 42 +++++++++++++++++++++++ 3 files changed, 84 insertions(+), 39 deletions(-) diff --git a/lib/build.py b/lib/build.py index e5f0c3e8b..de1819ec0 100644 --- a/lib/build.py +++ b/lib/build.py @@ -127,6 +127,8 @@ def main(cli_): global cli cli = cli_ + cli_process_common(cli) + # Process CLI. Make appropriate modifications to “cli” instance and return # Dockerfile text. text = cli_process(cli) @@ -144,40 +146,6 @@ def main(cli_): # reference, so changes made to mutable objects (which “cli” is) will persist in # the scope of the caller.' def cli_process(cli): - # --force and friends. - if (cli.force_cmd and cli.force == ch.Force_Mode.FAKEROOT): - ch.FATAL("--force-cmd and --force=fakeroot are incompatible") - if (not cli.force_cmd): - cli.force_cmd = force.FORCE_CMD_DEFAULT - else: - cli.force = ch.Force_Mode.SECCOMP - # convert cli.force_cmd to parsed dict - force_cmd = dict() - for line in cli.force_cmd: - (cmd, args) = force.force_cmd_parse(line) - force_cmd[cmd] = args - cli.force_cmd = force_cmd - ch.VERBOSE("force mode: %s" % cli.force) - if (cli.force == ch.Force_Mode.SECCOMP): - for (cmd, args) in cli.force_cmd.items(): - ch.VERBOSE("force command: %s" % ch.argv_to_string([cmd] + args)) - if ( cli.force == ch.Force_Mode.SECCOMP - and ch.cmd([ch.CH_BIN + "/ch-run", "--feature=seccomp"], - fail_ok=True) != 0): - ch.FATAL("ch-run was not built with seccomp(2) support") - - # Deal with build arguments. - def build_arg_get(arg): - kv = arg.split("=") - if (len(kv) == 2): - return kv - else: - v = os.getenv(kv[0]) - if (v is None): - ch.FATAL("--build-arg: %s: no value and not in environment" % kv[0]) - return (kv[0], v) - cli.build_arg = dict( build_arg_get(i) for i in cli.build_arg ) - # Infer input file if needed. if (cli.file is None): cli.file = cli.context + "/Dockerfile" @@ -234,6 +202,42 @@ def build_arg_get(arg): return text +# Process common opts between modify and build. +def cli_process_common(cli): + # --force and friends. + if (cli.force_cmd and cli.force == ch.Force_Mode.FAKEROOT): + ch.FATAL("--force-cmd and --force=fakeroot are incompatible") + if (not cli.force_cmd): + cli.force_cmd = force.FORCE_CMD_DEFAULT + else: + cli.force = ch.Force_Mode.SECCOMP + # convert cli.force_cmd to parsed dict + force_cmd = dict() + for line in cli.force_cmd: + (cmd, args) = force.force_cmd_parse(line) + force_cmd[cmd] = args + cli.force_cmd = force_cmd + ch.VERBOSE("force mode: %s" % cli.force) + if (cli.force == ch.Force_Mode.SECCOMP): + for (cmd, args) in cli.force_cmd.items(): + ch.VERBOSE("force command: %s" % ch.argv_to_string([cmd] + args)) + if ( cli.force == ch.Force_Mode.SECCOMP + and ch.cmd([ch.CH_BIN + "/ch-run", "--feature=seccomp"], + fail_ok=True) != 0): + ch.FATAL("ch-run was not built with seccomp(2) support") + + # Deal with build arguments. + def build_arg_get(arg): + kv = arg.split("=") + if (len(kv) == 2): + return kv + else: + v = os.getenv(kv[0]) + if (v is None): + ch.FATAL("--build-arg: %s: no value and not in environment" % kv[0]) + return (kv[0], v) + cli.build_arg = dict( build_arg_get(i) for i in cli.build_arg ) + def parse_dockerfile(text): # Parse it. parser = lark.Lark(im.GRAMMAR_DOCKERFILE, parser="earley", diff --git a/lib/modify.py b/lib/modify.py index 7d16f6825..443ad7af9 100644 --- a/lib/modify.py +++ b/lib/modify.py @@ -30,16 +30,15 @@ def main(cli_): global cli cli = cli_ - # This file assumes that global cli comes from the “build” function. If we + # build.py assumes that global cli comes from the “build” function. If we # don’t assign these values, the program will fail after trying to access # them. FIXME: Can partially fix this by adding command line opts. cli.parse_only = False - #cli.force = ch.Force_Mode.SECCOMP - cli.force_cmd = force.FORCE_CMD_DEFAULT - #cli.bind = [] - #cli.build_arg = [] + #cli.force_cmd = force.FORCE_CMD_DEFAULT cli.context = os.path.abspath(os.sep) + build.cli_process_common(cli) + commands = [] # “Flatten” commands array for c in cli.c: diff --git a/test/build/55_cache.bats b/test/build/55_cache.bats index 2c125484a..5fd480eaa 100644 --- a/test/build/55_cache.bats +++ b/test/build/55_cache.bats @@ -1580,3 +1580,45 @@ EOF [[ $status -eq 0 ]] [[ $output != *'image erroneously marked cached, fixing'* ]] } + +@test "${tag}: modify" { + ch-image build-cache --reset + + ch-image pull alpine:3.17 + ch-image modify -c "echo foo" -c "echo bar" -- alpine:3.17 tmpimg + + blessed_out=$(cat << 'EOF' +* (tmpimg) RUN.S echo bar +* RUN.S echo foo +* SHELL ['/bin/sh', '-c'] +* (alpine+3.17) PULL alpine:3.17 +* (root) ROOT +EOF +) + + run ch-image build-cache --tree + echo "$output" + [[ $status -eq 0 ]] + diff -u <(echo "$blessed_out") <(echo "$output" | treeonly) + + echo "touch /home/bar" >> "${BATS_TMPDIR}/script.sh" + chmod 755 "${BATS_TMPDIR}/script.sh" + ch-image modify alpine:3.17 tmpimg "${BATS_TMPDIR}/script.sh" + + blessed_out=$(cat < '/ch/script.sh' +| * RUN.S echo bar +| * RUN.S echo foo +|/ +* SHELL ['/bin/sh', '-c'] +* (alpine+3.17) PULL alpine:3.17 +* (root) ROOT +EOF +) + + run ch-image build-cache --tree + echo "$output" + [[ $status -eq 0 ]] + diff -u <(echo "$blessed_out") <(echo "$output" | treeonly) +}