From 8297d918c2951bce1188b03cb01fd087493c0782 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Thu, 12 Sep 2024 09:08:12 -0400 Subject: [PATCH] Add support for COPY --exclude and ADD --exclude options Fixes: https://github.com/containers/buildah/issues/5678 Signed-off-by: Daniel J Walsh --- cmd/buildah/addcopy.go | 25 +++++++++++--------- docs/buildah-add.1.md | 5 ++++ docs/buildah-copy.1.md | 7 ++++++ imagebuildah/stage_executor.go | 15 +++++------- tests/bud.bats | 8 +++++++ tests/bud/copy-exclude/.#Containerfile.bad | 1 + tests/bud/copy-exclude/Containerfile | 3 +++ tests/bud/copy-exclude/Containerfile.missing | 3 +++ tests/bud/copy-exclude/test1.txt | 0 tests/bud/copy-exclude/test2.txt | 0 tests/copy.bats | 25 ++++++++++++++++++++ 11 files changed, 72 insertions(+), 20 deletions(-) create mode 120000 tests/bud/copy-exclude/.#Containerfile.bad create mode 100644 tests/bud/copy-exclude/Containerfile create mode 100644 tests/bud/copy-exclude/Containerfile.missing create mode 100644 tests/bud/copy-exclude/test1.txt create mode 100644 tests/bud/copy-exclude/test2.txt diff --git a/cmd/buildah/addcopy.go b/cmd/buildah/addcopy.go index 962b6893389..435bba5f2fe 100644 --- a/cmd/buildah/addcopy.go +++ b/cmd/buildah/addcopy.go @@ -20,23 +20,24 @@ import ( type addCopyResults struct { addHistory bool + authfile string + blobCache string + certDir string + checksum string chmod string chown string - checksum string - quiet bool - ignoreFile string contextdir string - from string - blobCache string + creds string decryptionKeys []string + excludes []string + from string + ignoreFile string + quiet bool removeSignatures bool - signaturePolicy string - authfile string - creds string - tlsVerify bool - certDir string retry int retryDelay string + signaturePolicy string + tlsVerify bool } func createCommand(addCopy string, desc string, short string, opts *addCopyResults) *cobra.Command { @@ -78,6 +79,7 @@ func applyFlagVars(flags *pflag.FlagSet, opts *addCopyResults) { if err := flags.MarkHidden("decryption-key"); err != nil { panic(fmt.Sprintf("error marking decryption-key as hidden: %v", err)) } + flags.StringSliceVar(&opts.excludes, "exclude", nil, "exclude pattern when copying files") flags.StringVar(&opts.ignoreFile, "ignorefile", "", "path to .containerignore file") flags.StringVar(&opts.contextdir, "contextdir", "", "context directory path") flags.IntVar(&opts.retry, "retry", cli.MaxPullPushRetries, "number of times to retry in case of failure when performing pull") @@ -238,6 +240,7 @@ func addAndCopyCmd(c *cobra.Command, args []string, verb string, iopts addCopyRe Checksum: iopts.checksum, ContextDir: contextdir, IDMappingOptions: idMappingOptions, + Excludes: iopts.excludes, // These next two fields are set based on command line flags // with more generic-sounding names. CertPath: systemContext.DockerCertPath, @@ -251,7 +254,7 @@ func addAndCopyCmd(c *cobra.Command, args []string, verb string, iopts addCopyRe if err != nil { return err } - options.Excludes = excludes + options.Excludes = append(excludes, options.Excludes...) } if iopts.retryDelay != "" { retryDelay, err := time.ParseDuration(iopts.retryDelay) diff --git a/docs/buildah-add.1.md b/docs/buildah-add.1.md index 632bb485c23..647842c8610 100644 --- a/docs/buildah-add.1.md +++ b/docs/buildah-add.1.md @@ -49,6 +49,11 @@ Build context directory. Specifying a context directory causes Buildah to chroot into that context directory. This means copying files pointed at by symbolic links outside of the chroot will fail. +**--exclude** *pattern* + +Exclude coping files mattching the specified pattern. Option can be specified +multiple times. + **--from** *containerOrImage* Use the root directory of the specified working container or image as the root diff --git a/docs/buildah-copy.1.md b/docs/buildah-copy.1.md index ee8aba62955..1c6bbed7677 100644 --- a/docs/buildah-copy.1.md +++ b/docs/buildah-copy.1.md @@ -48,6 +48,11 @@ Build context directory. Specifying a context directory causes Buildah to chroot into the context directory. This means copying files pointed at by symbolic links outside of the chroot will fail. +**--exclude** *pattern* + +Exclude coping files mattching the specified pattern. Option can be specified +multiple times. + **--from** *containerOrImage* Use the root directory of the specified working container or image as the root @@ -86,6 +91,8 @@ talking to an insecure registry. buildah copy containerID '/myapp/app.conf' '/myapp/app.conf' +buildah copy --exclude=**/*.md docs containerID 'docs' '/docs' + buildah copy --chown myuser:mygroup containerID '/myapp/app.conf' '/myapp/app.conf' buildah copy --chmod 660 containerID '/myapp/app.conf' '/myapp/app.conf' diff --git a/imagebuildah/stage_executor.go b/imagebuildah/stage_executor.go index 60d5a9a9ead..20adaff704d 100644 --- a/imagebuildah/stage_executor.go +++ b/imagebuildah/stage_executor.go @@ -393,10 +393,7 @@ func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) err return errors.New("COPY --parents is not supported") } if len(cp.Excludes) > 0 { - if cp.Download { - return errors.New("ADD --excludes is not supported") - } - return errors.New("COPY --excludes is not supported") + excludes = append(excludes, cp.Excludes...) } } s.builder.ContentDigester.Restart() @@ -1344,12 +1341,12 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string, // Also check the chmod and the chown flags for validity. for _, flag := range step.Flags { command := strings.ToUpper(step.Command) - // chmod, chown and from flags should have an '=' sign, '--chmod=', '--chown=' or '--from=' - if command == "COPY" && (flag == "--chmod" || flag == "--chown" || flag == "--from") { - return "", nil, false, fmt.Errorf("COPY only supports the --chmod= --chown= and the --from= flags") + // chmod, chown and from flags should have an '=' sign, '--chmod=', '--chown=' or '--from=' or '--exclude=' + if command == "COPY" && (flag == "--chmod" || flag == "--chown" || flag == "--from" || flag == "--exclude") { + return "", nil, false, fmt.Errorf("COPY only supports the --chmod= --chown= and the --from= --exclude= flags") } - if command == "ADD" && (flag == "--chmod" || flag == "--chown" || flag == "--checksum") { - return "", nil, false, fmt.Errorf("ADD only supports the --chmod=, --chown=, and --checksum= flags") + if command == "ADD" && (flag == "--chmod" || flag == "--chown" || flag == "--checksum" || flag == "--exclude") { + return "", nil, false, fmt.Errorf("ADD only supports the --chmod=, --chown=, and --checksum= --exclude= flags") } if strings.Contains(flag, "--from") && command == "COPY" { arr := strings.Split(flag, "=") diff --git a/tests/bud.bats b/tests/bud.bats index 16a1e641ffb..445470c8b4a 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -5907,6 +5907,14 @@ _EOF expect_output --substring 'building.*"COPY \*foo /testdir".*no such file or directory' } +@test "bud with copy --exclude" { + run_buildah build -t test $WITH_POLICY_JSON $BUDFILES/copy-exclude + assert "$output" !~ "test1.txt" + + run_buildah build -t test2 -f Containerfile.missing $WITH_POLICY_JSON $BUDFILES/copy-exclude + assert "$output" !~ "test2.txt" +} + @test "bud with containerfile secret" { _prefetch alpine mytmpdir=${TEST_SCRATCH_DIR}/my-dir1 diff --git a/tests/bud/copy-exclude/.#Containerfile.bad b/tests/bud/copy-exclude/.#Containerfile.bad new file mode 120000 index 00000000000..374d829f6ec --- /dev/null +++ b/tests/bud/copy-exclude/.#Containerfile.bad @@ -0,0 +1 @@ +dwalsh@fedora.1237894:1723721444 \ No newline at end of file diff --git a/tests/bud/copy-exclude/Containerfile b/tests/bud/copy-exclude/Containerfile new file mode 100644 index 00000000000..5c9aa5e241e --- /dev/null +++ b/tests/bud/copy-exclude/Containerfile @@ -0,0 +1,3 @@ +FROM alpine +COPY --exclude=*txt . /testdir +run ls /testdir diff --git a/tests/bud/copy-exclude/Containerfile.missing b/tests/bud/copy-exclude/Containerfile.missing new file mode 100644 index 00000000000..d6dd8147490 --- /dev/null +++ b/tests/bud/copy-exclude/Containerfile.missing @@ -0,0 +1,3 @@ +FROM alpine +COPY --exclude=*foo --exclude=test*.txt . /testdir +run ls /testdir diff --git a/tests/bud/copy-exclude/test1.txt b/tests/bud/copy-exclude/test1.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/bud/copy-exclude/test2.txt b/tests/bud/copy-exclude/test2.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/copy.bats b/tests/copy.bats index 9afc50e6f65..4314edcd07f 100644 --- a/tests/copy.bats +++ b/tests/copy.bats @@ -359,6 +359,31 @@ stuff/mystuff" expect_output --from="$filelist" "$expect" "container file list" } +@test "copy --exclude" { + mytest=${TEST_SCRATCH_DIR}/mytest + mkdir -p ${mytest} + touch ${mytest}/mystuff + touch ${mytest}/source.go + mkdir -p ${mytest}/notmystuff + touch ${mytest}/notmystuff/notmystuff + +expect=" +stuff +stuff/mystuff" + + run_buildah from $WITH_POLICY_JSON scratch + cid=$output + + run_buildah copy --exclude=**/*.go --exclude=.ignore --exclude=**/notmystuff $cid ${mytest} /stuff + + run_buildah mount $cid + mnt=$output + run find $mnt -printf "%P\n" + filelist=$(LC_ALL=C sort <<<"$output") + run_buildah umount $cid + expect_output --from="$filelist" "$expect" "container file list" +} + @test "copy-quiet" { createrandom ${TEST_SCRATCH_DIR}/randomfile _prefetch alpine