From fde2597af81a023392d283d7461d020262b32715 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Thu, 19 Nov 2020 08:14:58 -0500 Subject: [PATCH] Add --ignorefile flag to use alternate .dockerignore flags Allow users to override location of the .dockerignore file. If user specified an --ignorefile flag, buildah will read the file and pass in the exclude lines based on the .dockerignore contents. Also add a --contextdir flag to buildah copy and buildah add to specify where the context directory is located. For these two commands the --ignorefile flag requires the --contextdir flag. When the --ignorefile flag is passed in, the .dockerignore files in the context directory will be ignored. Signed-off-by: Daniel J Walsh --- cmd/buildah/addcopy.go | 37 +++++++++++++++++++++++++++++++- cmd/buildah/bud.go | 7 ++++++ contrib/completions/bash/buildah | 5 +++++ docs/buildah-add.md | 20 ++++++++++++----- docs/buildah-bud.md | 11 +++++++--- docs/buildah-copy.md | 20 ++++++++++++----- imagebuildah/build.go | 2 ++ imagebuildah/executor.go | 9 +++++--- pkg/cli/common.go | 3 +++ tests/add.bats | 33 ++++++++++++++++++++++++++++ tests/bud.bats | 24 +++++++++++++++++++++ tests/copy.bats | 33 ++++++++++++++++++++++++++++ 12 files changed, 187 insertions(+), 17 deletions(-) diff --git a/cmd/buildah/addcopy.go b/cmd/buildah/addcopy.go index 41be1193396..1520e885d0c 100644 --- a/cmd/buildah/addcopy.go +++ b/cmd/buildah/addcopy.go @@ -2,6 +2,8 @@ package main import ( "fmt" + "io/ioutil" + "strings" "github.com/containers/buildah" buildahcli "github.com/containers/buildah/pkg/cli" @@ -13,6 +15,8 @@ type addCopyResults struct { addHistory bool chown string quiet bool + ignoreFile string + contextdir string } func init() { @@ -52,6 +56,8 @@ func init() { addFlags.SetInterspersed(false) addFlags.BoolVar(&addOpts.addHistory, "add-history", false, "add an entry for this operation to the image's history. Use BUILDAH_HISTORY environment variable to override. (default false)") addFlags.StringVar(&addOpts.chown, "chown", "", "set the user and group ownership of the destination content") + addFlags.StringVar(&addOpts.contextdir, "contextdir", "", "context directory path") + addFlags.StringVar(&addOpts.ignoreFile, "ignorefile", "", "path to .dockerignore file") addFlags.BoolVarP(&addOpts.quiet, "quiet", "q", false, "don't output a digest of the newly-added/copied content") // TODO We could avoid some duplication here if need-be; given it is small, leaving as is @@ -59,6 +65,8 @@ func init() { copyFlags.SetInterspersed(false) copyFlags.BoolVar(©Opts.addHistory, "add-history", false, "add an entry for this operation to the image's history. Use BUILDAH_HISTORY environment variable to override. (default false)") copyFlags.StringVar(©Opts.chown, "chown", "", "set the user and group ownership of the destination content") + copyFlags.StringVar(©Opts.ignoreFile, "ignorefile", "", "path to .dockerignore file") + copyFlags.StringVar(©Opts.contextdir, "contextdir", "", "context directory path") copyFlags.BoolVarP(©Opts.quiet, "quiet", "q", false, "don't output a digest of the newly-added/copied content") rootCmd.AddCommand(addCommand) @@ -100,7 +108,19 @@ func addAndCopyCmd(c *cobra.Command, args []string, verb string, extractLocalArc builder.ContentDigester.Restart() options := buildah.AddAndCopyOptions{ - Chown: iopts.chown, + Chown: iopts.chown, + ContextDir: iopts.contextdir, + } + if iopts.ignoreFile != "" { + if iopts.contextdir == "" { + return errors.Errorf("--ignore options requires that you specify a context dir using --contextdir") + } + + excludes, err := parseDockerignore(iopts.ignoreFile) + if err != nil { + return err + } + options.Excludes = excludes } err = builder.Add(dest, extractLocalArchives, options, args...) @@ -126,3 +146,18 @@ func addCmd(c *cobra.Command, args []string, iopts addCopyResults) error { func copyCmd(c *cobra.Command, args []string, iopts addCopyResults) error { return addAndCopyCmd(c, args, "COPY", false, iopts) } + +func parseDockerignore(ignoreFile string) ([]string, error) { + var excludes []string + ignore, err := ioutil.ReadFile(ignoreFile) + if err != nil { + return excludes, err + } + for _, e := range strings.Split(string(ignore), "\n") { + if len(e) == 0 || e[0] == '#' { + continue + } + excludes = append(excludes, e) + } + return excludes, nil +} diff --git a/cmd/buildah/bud.go b/cmd/buildah/bud.go index 17ced9a1ee3..8cc00dd390e 100644 --- a/cmd/buildah/bud.go +++ b/cmd/buildah/bud.go @@ -347,6 +347,13 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error { Jobs: &iopts.Jobs, LogRusage: iopts.LogRusage, } + if iopts.IgnoreFile != "" { + excludes, err := parseDockerignore(iopts.IgnoreFile) + if err != nil { + return err + } + options.Excludes = excludes + } if c.Flag("timestamp").Changed { timestamp := time.Unix(iopts.Timestamp, 0).UTC() options.Timestamp = ×tamp diff --git a/contrib/completions/bash/buildah b/contrib/completions/bash/buildah index f24d403a9c8..291abb78b5e 100644 --- a/contrib/completions/bash/buildah +++ b/contrib/completions/bash/buildah @@ -418,6 +418,7 @@ return 1 --file --format --http-proxy + --ignorefile --iidfile --isolation --ipc @@ -536,6 +537,8 @@ return 1 local options_with_args=" --chown + --contextdir + --ignorefile " local all_options="$options_with_args $boolean_options" @@ -558,6 +561,8 @@ return 1 local options_with_args=" -chown + --contextdir + --ignorefile " local all_options="$options_with_args $boolean_options" diff --git a/docs/buildah-add.md b/docs/buildah-add.md index b61e9541c4e..bc61547a953 100644 --- a/docs/buildah-add.md +++ b/docs/buildah-add.md @@ -27,6 +27,16 @@ BUILDAH\_HISTORY environment variable. `export BUILDAH_HISTORY=true` Sets the user and group ownership of the destination content. +**--contextdir** + +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. + +**--ignorefile** + +Path to an alternative .dockerignore file. Requires --contextdir be specified. + **--quiet**, **-q** Refrain from printing a digest of the added content. @@ -49,13 +59,13 @@ buildah add containerID 'passwd' 'certs.d' /etc ## FILES -### `.dockerignore` +### .dockerignore -If the file .dockerignore exists in the context directory, `buildah copy` reads -its contents. Buildah uses the content to exclude files and directories from -the context directory, when copying content into the image. +When the \fB\fC\-\-ignorefile\fR option is specified Buildah reads the +content to exclude files and directories from the source directory, when +copying content into the image. -Users can specify a series of Unix shell globals in a .dockerignore file to +Users can specify a series of Unix shell globals in a inore file to identify files/directories to exclude. Buildah supports a special wildcard string `**` which matches any number of diff --git a/docs/buildah-bud.md b/docs/buildah-bud.md index cf670c858a3..216d6af8c51 100644 --- a/docs/buildah-bud.md +++ b/docs/buildah-bud.md @@ -280,6 +280,10 @@ those. Write the image ID to the file. +**--ignorefile** + +Path to an alternative .dockerignore file. + **--ipc** *how* Sets the configuration for IPC namespaces when handling `RUN` instructions. @@ -733,9 +737,10 @@ are stored while pulling and pushing images. Defaults to '/var/tmp'. ### `.dockerignore` -If the file .dockerignore exists in the context directory, `buildah bud` reads -its contents. Buildah uses the content to exclude files and directories from -the context directory, when executing COPY and ADD directives in the +If the file .dockerignore exists in the context directory, `buildah copy` reads +its contents. Use `--ignorefile` flag to overide .dockerignore path location. +Buildah uses the content to exclude files and directories from the context +directory, when executing COPY and ADD directives in the Containerfile/Dockerfile Users can specify a series of Unix shell globals in a .dockerignore file to diff --git a/docs/buildah-copy.md b/docs/buildah-copy.md index 89f24833928..a6a4484b9d3 100644 --- a/docs/buildah-copy.md +++ b/docs/buildah-copy.md @@ -25,6 +25,16 @@ BUILDAH\_HISTORY environment variable. `export BUILDAH_HISTORY=true` Sets the user and group ownership of the destination content. +**--contextdir** + +Build context directory. Specifying a context directory causes Buildah to +chroot into a the context directory. This means copying files pointed at +by symbolic links outside of the chroot will fail. + +**--ignorefile** + +Path to an alternative .dockerignore file. Requires --contextdir be specified. + **--quiet**, **-q** Refrain from printing a digest of the copied content. @@ -47,13 +57,13 @@ buildah copy containerID 'passwd' 'certs.d' /etc ## FILES -### `.dockerignore` +### .dockerignore -If the file .dockerignore exists in the context directory, `buildah copy` reads -its contents. Buildah uses the content to exclude files and directories from -the context directory, when copying content into the image. +When the \fB\fC\-\-ignorefile\fR option is specified Buildah reads the +content to exclude files and directories from the source directory, when +copying content into the image. -Users can specify a series of Unix shell globals in a .dockerignore file to +Users can specify a series of Unix shell globals in a inore file to identify files/directories to exclude. Buildah supports a special wildcard string `**` which matches any number of diff --git a/imagebuildah/build.go b/imagebuildah/build.go index a97a403b372..1ec21e7860b 100644 --- a/imagebuildah/build.go +++ b/imagebuildah/build.go @@ -185,6 +185,8 @@ type BuildOptions struct { Jobs *int // LogRusage logs resource usage for each step. LogRusage bool + // Excludes is a list of excludes to be used instead of the .dockerignore file. + Excludes []string } // BuildDockerfiles parses a set of one or more Dockerfiles (which may be diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index 8c96b4e6703..3c41ec1d2d5 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -130,9 +130,12 @@ func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Nod return nil, errors.Wrapf(err, "failed to get container config") } - excludes, err := imagebuilder.ParseDockerignore(options.ContextDirectory) - if err != nil { - return nil, err + excludes := options.Excludes + if len(excludes) == 0 { + excludes, err = imagebuilder.ParseDockerignore(options.ContextDirectory) + if err != nil { + return nil, err + } } capabilities, err := defaultContainerConfig.Capabilities("", options.AddCapabilities, options.DropCapabilities) if err != nil { diff --git a/pkg/cli/common.go b/pkg/cli/common.go index 62a328de05a..123548d97bc 100644 --- a/pkg/cli/common.go +++ b/pkg/cli/common.go @@ -59,6 +59,7 @@ type BudResults struct { Creds string DisableCompression bool DisableContentTrust bool + IgnoreFile string File []string Format string Iidfile string @@ -185,6 +186,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet { fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry") fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", true, "don't compress layers by default") fs.BoolVar(&flags.DisableContentTrust, "disable-content-trust", false, "This is a Docker specific option and is a NOOP") + fs.StringVar(&flags.IgnoreFile, "ignorefile", "", "path to an alternate .dockerignore file") fs.StringSliceVarP(&flags.File, "file", "f", []string{}, "`pathname or URL` of a Dockerfile") fs.StringVar(&flags.Format, "format", DefaultFormat(), "`format` of the built image's manifest and metadata. Use BUILDAH_FORMAT environment variable to override.") fs.StringVar(&flags.Iidfile, "iidfile", "", "`file` to write the image ID to") @@ -231,6 +233,7 @@ func GetBudFlagsCompletions() commonComp.FlagCompletions { flagCompletion["creds"] = commonComp.AutocompleteNone flagCompletion["file"] = commonComp.AutocompleteDefault flagCompletion["format"] = commonComp.AutocompleteNone + flagCompletion["ignorefile"] = commonComp.AutocompleteDefault flagCompletion["iidfile"] = commonComp.AutocompleteDefault flagCompletion["jobs"] = commonComp.AutocompleteNone flagCompletion["label"] = commonComp.AutocompleteNone diff --git a/tests/add.bats b/tests/add.bats index 19dc6ab8d56..8a3c7588066 100644 --- a/tests/add.bats +++ b/tests/add.bats @@ -188,3 +188,36 @@ load helpers run_buildah add $cid tools/Makefile / run_buildah run $cid ls /Makefile } + +@test "add --ignore" { + mytest=${TESTDIR}/mytest + mkdir -p ${mytest} + touch ${mytest}/mystuff + touch ${mytest}/source.go + mkdir -p ${mytest}/notmystuff + touch ${mytest}/notmystuff/notmystuff + cat > ${mytest}/.ignore << _EOF +*.go +.ignore +notmystuff +_EOF + +expect=" +stuff +stuff/mystuff" + + run_buildah from --signature-policy ${TESTSDIR}/policy.json scratch + cid=$output + + run_buildah 125 copy --ignorefile ${mytest}/.ignore $cid ${mytest} /stuff + expect_output -- "--ignore options requires that you specify a context dir using --contextdir" "container file list" + + run_buildah add --contextdir=${mytest} --ignorefile ${mytest}/.ignore $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" +} diff --git a/tests/bud.bats b/tests/bud.bats index ee70c02ecf0..ed016f46aa9 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -2388,3 +2388,27 @@ EOF @test "bud-terminal" { run_buildah bud ${TESTSDIR}/bud/terminal } + +@test "bud --ignore containerignore" { + _prefetch alpine busybox + + CONTEXTDIR=${TESTDIR}/dockerignore + cp -r ${TESTSDIR}/bud/dockerignore ${CONTEXTDIR} + mv ${CONTEXTDIR}/.dockerignore ${TESTDIR}/containerignore + + run_buildah bud -t testbud --signature-policy ${TESTSDIR}/policy.json -f ${CONTEXTDIR}/Dockerfile.succeed --ignorefile ${TESTDIR}/containerignore ${CONTEXTDIR} + + run_buildah from --name myctr testbud + + run_buildah 1 run myctr ls -l test1.txt + + run_buildah run myctr ls -l test2.txt + + run_buildah 1 run myctr ls -l sub1.txt + + run_buildah 1 run myctr ls -l sub2.txt + + run_buildah run myctr ls -l subdir/sub1.txt + + run_buildah 1 run myctr ls -l subdir/sub2.txt +} diff --git a/tests/copy.bats b/tests/copy.bats index 326f47166f3..2aa2e5431a1 100644 --- a/tests/copy.bats +++ b/tests/copy.bats @@ -250,3 +250,36 @@ load helpers run_buildah 125 build-using-dockerfile --signature-policy ${TESTSDIR}/policy.json ${TESTDIR} expect_output --substring "no such file or directory" } + +@test "copy --ignore" { + mytest=${TESTDIR}/mytest + mkdir -p ${mytest} + touch ${mytest}/mystuff + touch ${mytest}/source.go + mkdir -p ${mytest}/notmystuff + touch ${mytest}/notmystuff/notmystuff + cat > ${mytest}/.ignore << _EOF +*.go +.ignore +notmystuff +_EOF + +expect=" +stuff +stuff/mystuff" + + run_buildah from --signature-policy ${TESTSDIR}/policy.json scratch + cid=$output + + run_buildah 125 copy --ignorefile ${mytest}/.ignore $cid ${mytest} /stuff + expect_output -- "--ignore options requires that you specify a context dir using --contextdir" "container file list" + + run_buildah copy --contextdir=${mytest} --ignorefile ${mytest}/.ignore $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" +}