From a572774bbe9b0aac0da29228682cd16fe88938f3 Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Fri, 12 Oct 2018 11:55:09 -0700 Subject: [PATCH 1/5] Add --ignore flag Added a --ignore flag to ignore packages and files in the build context. This should mimic the .dockerignore file. Before starting the build, we go through and delete ignored files from the build context. --- README.md | 4 ++ cmd/executor/cmd/root.go | 33 +++++++++++ .../dockerfiles/Dockerfile_test_ignore | 2 + integration/images.go | 59 ++++++++++++++++++- pkg/config/options.go | 1 + 5 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 integration/dockerfiles/Dockerfile_test_ignore diff --git a/README.md b/README.md index 39c24e310..de8116141 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,10 @@ _This flag must be used in conjunction with the `--cache=true` flag._ Set this flag to cleanup the filesystem at the end, leaving a clean kaniko container (if you want to build multiple images in the same container, using the debug kaniko image) +#### --ignore + +Set this flag to ignore files in your build context. For examples, set `--ignore pkg/*` to ignore all files in the `pkg` directory. + ### Debug Image The kaniko executor image is based off of scratch and doesn't contain a shell. diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index 55d256f28..089378442 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -61,6 +61,9 @@ var RootCmd = &cobra.Command{ if err := resolveSourceContext(); err != nil { return errors.Wrap(err, "error resolving source context") } + if err := removeIgnoredFiles(); err != nil { + return errors.Wrap(err, "error removing ignored files from build context") + } return resolveDockerfilePath() }, Run: func(cmd *cobra.Command, args []string) { @@ -91,6 +94,7 @@ func addKanikoOptionsFlags(cmd *cobra.Command) { RootCmd.PersistentFlags().VarP(&opts.Destinations, "destination", "d", "Registry the final image should be pushed to. Set it repeatedly for multiple destinations.") RootCmd.PersistentFlags().StringVarP(&opts.SnapshotMode, "snapshotMode", "", "full", "Change the file attributes inspected during snapshotting") RootCmd.PersistentFlags().VarP(&opts.BuildArgs, "build-arg", "", "This flag allows you to pass in ARG values at build time. Set it repeatedly for multiple values.") + RootCmd.PersistentFlags().VarP(&opts.Ignore, "ignore", "", "Set this flag to ignore files in the build context. Set it repeatedly for multiple values.") RootCmd.PersistentFlags().BoolVarP(&opts.InsecurePush, "insecure", "", false, "Push to insecure registry using plain HTTP") RootCmd.PersistentFlags().BoolVarP(&opts.SkipTLSVerify, "skip-tls-verify", "", false, "Push to insecure registry ignoring TLS verify") RootCmd.PersistentFlags().StringVarP(&opts.TarPath, "tarPath", "", "", "Path to save the image in as a tarball instead of pushing") @@ -182,6 +186,35 @@ func resolveSourceContext() error { return nil } +func removeIgnoredFiles() error { + logrus.Infof("Removing ignored files from build context: %s", opts.Ignore) + for r, i := range opts.Ignore { + opts.Ignore[r] = filepath.Clean(filepath.Join(opts.SrcContext, i)) + } + err := filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { + if ignoreFile(path) { + if err := os.RemoveAll(path); err != nil { + logrus.Debugf("error removing %s from buildcontext", path) + } + } + return nil + }) + return err +} + +func ignoreFile(path string) bool { + for _, i := range opts.Ignore { + matched, err := filepath.Match(i, path) + if err != nil { + return false + } + if matched { + return true + } + } + return false +} + func exit(err error) { fmt.Println(err) os.Exit(1) diff --git a/integration/dockerfiles/Dockerfile_test_ignore b/integration/dockerfiles/Dockerfile_test_ignore new file mode 100644 index 000000000..04fdc2701 --- /dev/null +++ b/integration/dockerfiles/Dockerfile_test_ignore @@ -0,0 +1,2 @@ +FROM scratch +COPY . . diff --git a/integration/images.go b/integration/images.go index 464db8cc8..daeeca24b 100644 --- a/integration/images.go +++ b/integration/images.go @@ -54,6 +54,16 @@ var argsMap = map[string][]string{ "Dockerfile_test_multistage": {"file=/foo2"}, } +var filesToIgnore = []string{"context/bar/*", "context/tars/"} + +func ignoreFlags() []string { + var f []string + for _, i := range filesToIgnore { + f = append(f, fmt.Sprintf("--ignore=%s", i)) + } + return f +} + // Arguments to build Dockerfiles with when building with docker var additionalDockerFlagsMap = map[string][]string{ "Dockerfile_test_target": {"--target=second"}, @@ -64,6 +74,7 @@ var additionalKanikoFlagsMap = map[string][]string{ "Dockerfile_test_add": {"--single-snapshot"}, "Dockerfile_test_scratch": {"--single-snapshot"}, "Dockerfile_test_target": {"--target=second"}, + "Dockerfile_test_ignore": ignoreFlags(), } var bucketContextTests = []string{"Dockerfile_test_copy_bucket"} @@ -110,9 +121,10 @@ func FindDockerFiles(dockerfilesPath string) ([]string, error) { // keeps track of which files have been built. type DockerFileBuilder struct { // Holds all available docker files and whether or not they've been built - FilesBuilt map[string]bool - DockerfilesToIgnore map[string]struct{} - TestCacheDockerfiles map[string]struct{} + FilesBuilt map[string]bool + DockerfilesToIgnore map[string]struct{} + TestCacheDockerfiles map[string]struct{} + TestIgnoreDockerfiles map[string]struct{} } // NewDockerFileBuilder will create a DockerFileBuilder initialized with dockerfiles, which @@ -130,6 +142,9 @@ func NewDockerFileBuilder(dockerfiles []string) *DockerFileBuilder { "Dockerfile_test_cache": {}, "Dockerfile_test_cache_install": {}, } + d.TestIgnoreDockerfiles = map[string]struct{}{ + "Dockerfile_test_ignore": {}, + } return &d } @@ -158,11 +173,23 @@ func (d *DockerFileBuilder) BuildImage(imageRepo, gcsBucket, dockerfilesPath, do "."}, additionalFlags...)..., ) + if d.includeDockerIgnore(dockerfile) { + if err := generateDockerIgnore(); err != nil { + return err + } + } + _, err := RunCommandWithoutTest(dockerCmd) if err != nil { return fmt.Errorf("Failed to build image %s with docker command \"%s\": %s", dockerImage, dockerCmd.Args, err) } + if d.includeDockerIgnore(dockerfilesPath) { + if err := deleteDockerIgnore(); err != nil { + return err + } + } + contextFlag := "-c" contextPath := buildContextPath for _, d := range bucketContextTests { @@ -252,3 +279,29 @@ func (d *DockerFileBuilder) buildCachedImages(imageRepo, cacheRepo, dockerfilesP } return nil } + +func (d *DockerFileBuilder) includeDockerIgnore(dockerfile string) bool { + for i := range d.TestIgnoreDockerfiles { + if i == dockerfile { + return true + } + } + return false +} + +func generateDockerIgnore() error { + f, err := os.Create(".dockerignore") + if err != nil { + return err + } + defer f.Close() + contents := strings.Join(filesToIgnore, "\n") + if _, err := f.Write([]byte(contents)); err != nil { + return err + } + return nil +} + +func deleteDockerIgnore() error { + return os.Remove(".dockerignore") +} diff --git a/pkg/config/options.go b/pkg/config/options.go index fc15c1f21..2c9195598 100644 --- a/pkg/config/options.go +++ b/pkg/config/options.go @@ -28,6 +28,7 @@ type KanikoOptions struct { CacheDir string Destinations multiArg BuildArgs multiArg + Ignore multiArg InsecurePush bool SkipTLSVerify bool SingleSnapshot bool From adac8d495d0a8fd3ab0b21f30d684a7569346243 Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Fri, 12 Oct 2018 12:48:16 -0700 Subject: [PATCH 2/5] Add test dir for ignore files It seems like .dockerignore deletes files containeed within the file locally upon docker build, so I created a temporary test dir to make sure the --ignore flag works. We make sure it exists before building docker and kaniko for Dockerfile_test_ignore, and then delete it after the builds have completed. --- integration/images.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/integration/images.go b/integration/images.go index daeeca24b..b190e61f6 100644 --- a/integration/images.go +++ b/integration/images.go @@ -37,6 +37,7 @@ const ( buildContextPath = "/workspace" cacheDir = "/workspace/cache" baseImageToCache = "gcr.io/google-appengine/debian9@sha256:1d6a9a6d106bd795098f60f4abb7083626354fa6735e81743c7f8cfca11259f0" + testDirPath = "test/dir/path" ) // Arguments to build Dockerfiles with, used for both docker and kaniko builds @@ -54,7 +55,7 @@ var argsMap = map[string][]string{ "Dockerfile_test_multistage": {"file=/foo2"}, } -var filesToIgnore = []string{"context/bar/*", "context/tars/"} +var filesToIgnore = []string{"test/*"} func ignoreFlags() []string { var f []string @@ -174,6 +175,9 @@ func (d *DockerFileBuilder) BuildImage(imageRepo, gcsBucket, dockerfilesPath, do additionalFlags...)..., ) if d.includeDockerIgnore(dockerfile) { + if err := setupTestDir(); err != nil { + return err + } if err := generateDockerIgnore(); err != nil { return err } @@ -188,7 +192,11 @@ func (d *DockerFileBuilder) BuildImage(imageRepo, gcsBucket, dockerfilesPath, do if err := deleteDockerIgnore(); err != nil { return err } + if err := setupTestDir(); err != nil { + return err + } } + defer removeTestDir() contextFlag := "-c" contextPath := buildContextPath @@ -289,6 +297,14 @@ func (d *DockerFileBuilder) includeDockerIgnore(dockerfile string) bool { return false } +func setupTestDir() error { + return os.MkdirAll(testDirPath, 0644) +} + +func removeTestDir() error { + return os.RemoveAll(testDirPath) +} + func generateDockerIgnore() error { f, err := os.Create(".dockerignore") if err != nil { From 3fc43f4c736ad47488d594e9effdde4a7e3b391c Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Fri, 19 Oct 2018 09:54:49 -0700 Subject: [PATCH 3/5] Add support for .dockerignore file --- README.md | 4 --- cmd/executor/cmd/root.go | 29 +++++++++++------ integration/images.go | 61 ++++++++---------------------------- pkg/config/options.go | 1 - pkg/dockerfile/dockerfile.go | 21 +++++++++++++ 5 files changed, 54 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index de8116141..39c24e310 100644 --- a/README.md +++ b/README.md @@ -321,10 +321,6 @@ _This flag must be used in conjunction with the `--cache=true` flag._ Set this flag to cleanup the filesystem at the end, leaving a clean kaniko container (if you want to build multiple images in the same container, using the debug kaniko image) -#### --ignore - -Set this flag to ignore files in your build context. For examples, set `--ignore pkg/*` to ignore all files in the `pkg` directory. - ### Debug Image The kaniko executor image is based off of scratch and doesn't contain a shell. diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index 089378442..5bdeb0c87 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -25,6 +25,7 @@ import ( "github.com/GoogleContainerTools/kaniko/pkg/buildcontext" "github.com/GoogleContainerTools/kaniko/pkg/config" "github.com/GoogleContainerTools/kaniko/pkg/constants" + "github.com/GoogleContainerTools/kaniko/pkg/dockerfile" "github.com/GoogleContainerTools/kaniko/pkg/executor" "github.com/GoogleContainerTools/kaniko/pkg/util" "github.com/genuinetools/amicontained/container" @@ -94,7 +95,6 @@ func addKanikoOptionsFlags(cmd *cobra.Command) { RootCmd.PersistentFlags().VarP(&opts.Destinations, "destination", "d", "Registry the final image should be pushed to. Set it repeatedly for multiple destinations.") RootCmd.PersistentFlags().StringVarP(&opts.SnapshotMode, "snapshotMode", "", "full", "Change the file attributes inspected during snapshotting") RootCmd.PersistentFlags().VarP(&opts.BuildArgs, "build-arg", "", "This flag allows you to pass in ARG values at build time. Set it repeatedly for multiple values.") - RootCmd.PersistentFlags().VarP(&opts.Ignore, "ignore", "", "Set this flag to ignore files in the build context. Set it repeatedly for multiple values.") RootCmd.PersistentFlags().BoolVarP(&opts.InsecurePush, "insecure", "", false, "Push to insecure registry using plain HTTP") RootCmd.PersistentFlags().BoolVarP(&opts.SkipTLSVerify, "skip-tls-verify", "", false, "Push to insecure registry ignoring TLS verify") RootCmd.PersistentFlags().StringVarP(&opts.TarPath, "tarPath", "", "", "Path to save the image in as a tarball instead of pushing") @@ -187,23 +187,34 @@ func resolveSourceContext() error { } func removeIgnoredFiles() error { - logrus.Infof("Removing ignored files from build context: %s", opts.Ignore) - for r, i := range opts.Ignore { - opts.Ignore[r] = filepath.Clean(filepath.Join(opts.SrcContext, i)) + if !dockerfile.DockerignoreExists(opts) { + return nil } - err := filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { - if ignoreFile(path) { + ignore, err := dockerfile.ParseDockerignore(opts) + if err != nil { + return err + } + logrus.Infof("Removing ignored files from build context: %s", ignore) + for r, i := range ignore { + ignore[r] = filepath.Clean(filepath.Join(opts.SrcContext, i)) + } + err = filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { + if ignoreFile(path, ignore) { if err := os.RemoveAll(path); err != nil { logrus.Debugf("error removing %s from buildcontext", path) } } return nil }) - return err + if err != nil { + return err + } + path := filepath.Join(opts.SrcContext, ".dockerignore") + return os.Remove(path) } -func ignoreFile(path string) bool { - for _, i := range opts.Ignore { +func ignoreFile(path string, ignore []string) bool { + for _, i := range ignore { matched, err := filepath.Match(i, path) if err != nil { return false diff --git a/integration/images.go b/integration/images.go index b190e61f6..19d7a91d2 100644 --- a/integration/images.go +++ b/integration/images.go @@ -57,14 +57,6 @@ var argsMap = map[string][]string{ var filesToIgnore = []string{"test/*"} -func ignoreFlags() []string { - var f []string - for _, i := range filesToIgnore { - f = append(f, fmt.Sprintf("--ignore=%s", i)) - } - return f -} - // Arguments to build Dockerfiles with when building with docker var additionalDockerFlagsMap = map[string][]string{ "Dockerfile_test_target": {"--target=second"}, @@ -75,7 +67,6 @@ var additionalKanikoFlagsMap = map[string][]string{ "Dockerfile_test_add": {"--single-snapshot"}, "Dockerfile_test_scratch": {"--single-snapshot"}, "Dockerfile_test_target": {"--target=second"}, - "Dockerfile_test_ignore": ignoreFlags(), } var bucketContextTests = []string{"Dockerfile_test_copy_bucket"} @@ -122,10 +113,9 @@ func FindDockerFiles(dockerfilesPath string) ([]string, error) { // keeps track of which files have been built. type DockerFileBuilder struct { // Holds all available docker files and whether or not they've been built - FilesBuilt map[string]bool - DockerfilesToIgnore map[string]struct{} - TestCacheDockerfiles map[string]struct{} - TestIgnoreDockerfiles map[string]struct{} + FilesBuilt map[string]bool + DockerfilesToIgnore map[string]struct{} + TestCacheDockerfiles map[string]struct{} } // NewDockerFileBuilder will create a DockerFileBuilder initialized with dockerfiles, which @@ -143,9 +133,6 @@ func NewDockerFileBuilder(dockerfiles []string) *DockerFileBuilder { "Dockerfile_test_cache": {}, "Dockerfile_test_cache_install": {}, } - d.TestIgnoreDockerfiles = map[string]struct{}{ - "Dockerfile_test_ignore": {}, - } return &d } @@ -174,13 +161,11 @@ func (d *DockerFileBuilder) BuildImage(imageRepo, gcsBucket, dockerfilesPath, do "."}, additionalFlags...)..., ) - if d.includeDockerIgnore(dockerfile) { - if err := setupTestDir(); err != nil { - return err - } - if err := generateDockerIgnore(); err != nil { - return err - } + if err := setupTestDir(); err != nil { + return err + } + if err := generateDockerIgnore(); err != nil { + return err } _, err := RunCommandWithoutTest(dockerCmd) @@ -188,15 +173,12 @@ func (d *DockerFileBuilder) BuildImage(imageRepo, gcsBucket, dockerfilesPath, do return fmt.Errorf("Failed to build image %s with docker command \"%s\": %s", dockerImage, dockerCmd.Args, err) } - if d.includeDockerIgnore(dockerfilesPath) { - if err := deleteDockerIgnore(); err != nil { - return err - } - if err := setupTestDir(); err != nil { - return err - } + if err := setupTestDir(); err != nil { + return err + } + if err := generateDockerIgnore(); err != nil { + return err } - defer removeTestDir() contextFlag := "-c" contextPath := buildContextPath @@ -288,23 +270,10 @@ func (d *DockerFileBuilder) buildCachedImages(imageRepo, cacheRepo, dockerfilesP return nil } -func (d *DockerFileBuilder) includeDockerIgnore(dockerfile string) bool { - for i := range d.TestIgnoreDockerfiles { - if i == dockerfile { - return true - } - } - return false -} - func setupTestDir() error { return os.MkdirAll(testDirPath, 0644) } -func removeTestDir() error { - return os.RemoveAll(testDirPath) -} - func generateDockerIgnore() error { f, err := os.Create(".dockerignore") if err != nil { @@ -317,7 +286,3 @@ func generateDockerIgnore() error { } return nil } - -func deleteDockerIgnore() error { - return os.Remove(".dockerignore") -} diff --git a/pkg/config/options.go b/pkg/config/options.go index 2c9195598..fc15c1f21 100644 --- a/pkg/config/options.go +++ b/pkg/config/options.go @@ -28,7 +28,6 @@ type KanikoOptions struct { CacheDir string Destinations multiArg BuildArgs multiArg - Ignore multiArg InsecurePush bool SkipTLSVerify bool SingleSnapshot bool diff --git a/pkg/dockerfile/dockerfile.go b/pkg/dockerfile/dockerfile.go index 8b06985b6..c2eb9bff7 100644 --- a/pkg/dockerfile/dockerfile.go +++ b/pkg/dockerfile/dockerfile.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "io/ioutil" + "path/filepath" "strconv" "strings" @@ -168,3 +169,23 @@ func saveStage(index int, stages []instructions.Stage) bool { } return false } + +// DockerignoreExists returns true if .dockerignore exists in the source context +func DockerignoreExists(opts *config.KanikoOptions) bool { + path := filepath.Join(opts.SrcContext, ".dockerignore") + return util.FilepathExists(path) +} + +// ParseDockerignore returns a list of all paths in .dockerignore +func ParseDockerignore(opts *config.KanikoOptions) ([]string, error) { + path := filepath.Join(opts.SrcContext, ".dockerignore") + contents, err := ioutil.ReadFile(path) + if err != nil { + return nil, errors.Wrap(err, "parsing .dockerignore") + } + return strings.FieldsFunc(string(contents), split), nil +} + +func split(r rune) bool { + return r == '\n' || r == ' ' +} From cb0a5e0a18283bb0807ec6714585809b510f90e7 Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Fri, 19 Oct 2018 14:55:56 -0700 Subject: [PATCH 4/5] Fix integration tests --- cmd/executor/cmd/root.go | 6 +++++- integration/images.go | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index 5bdeb0c87..dcbb48430 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -63,7 +63,7 @@ var RootCmd = &cobra.Command{ return errors.Wrap(err, "error resolving source context") } if err := removeIgnoredFiles(); err != nil { - return errors.Wrap(err, "error removing ignored files from build context") + return errors.Wrap(err, "error removing .dockerignore files from build context") } return resolveDockerfilePath() }, @@ -198,9 +198,11 @@ func removeIgnoredFiles() error { for r, i := range ignore { ignore[r] = filepath.Clean(filepath.Join(opts.SrcContext, i)) } + // first, remove all files in .dockerignore err = filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { if ignoreFile(path, ignore) { if err := os.RemoveAll(path); err != nil { + // don't return error, because this path could have been removed already logrus.Debugf("error removing %s from buildcontext", path) } } @@ -209,10 +211,12 @@ func removeIgnoredFiles() error { if err != nil { return err } + // then, remove .dockerignore path := filepath.Join(opts.SrcContext, ".dockerignore") return os.Remove(path) } +// ignoreFile returns true if the path matches any of the paths in ignore func ignoreFile(path string, ignore []string) bool { for _, i := range ignore { matched, err := filepath.Match(i, path) diff --git a/integration/images.go b/integration/images.go index 19d7a91d2..1f392be57 100644 --- a/integration/images.go +++ b/integration/images.go @@ -37,7 +37,7 @@ const ( buildContextPath = "/workspace" cacheDir = "/workspace/cache" baseImageToCache = "gcr.io/google-appengine/debian9@sha256:1d6a9a6d106bd795098f60f4abb7083626354fa6735e81743c7f8cfca11259f0" - testDirPath = "test/dir/path" + testDirPath = "context/test" ) // Arguments to build Dockerfiles with, used for both docker and kaniko builds @@ -55,7 +55,7 @@ var argsMap = map[string][]string{ "Dockerfile_test_multistage": {"file=/foo2"}, } -var filesToIgnore = []string{"test/*"} +var filesToIgnore = []string{"context/test/*"} // Arguments to build Dockerfiles with when building with docker var additionalDockerFlagsMap = map[string][]string{ @@ -271,7 +271,15 @@ func (d *DockerFileBuilder) buildCachedImages(imageRepo, cacheRepo, dockerfilesP } func setupTestDir() error { - return os.MkdirAll(testDirPath, 0644) + if err := os.MkdirAll(testDirPath, 0750); err != nil { + return err + } + p := filepath.Join(testDirPath, "foo") + f, err := os.Create(p) + if err != nil { + return err + } + return f.Close() } func generateDockerIgnore() error { From ff4e624c6b42152c451e795f0ac19c1361d01d10 Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Tue, 30 Oct 2018 16:06:46 -0700 Subject: [PATCH 5/5] don't delete .dockerignore --- cmd/executor/cmd/root.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index dcbb48430..fa244d332 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -198,8 +198,8 @@ func removeIgnoredFiles() error { for r, i := range ignore { ignore[r] = filepath.Clean(filepath.Join(opts.SrcContext, i)) } - // first, remove all files in .dockerignore - err = filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { + // remove all files in .dockerignore + return filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { if ignoreFile(path, ignore) { if err := os.RemoveAll(path); err != nil { // don't return error, because this path could have been removed already @@ -208,12 +208,6 @@ func removeIgnoredFiles() error { } return nil }) - if err != nil { - return err - } - // then, remove .dockerignore - path := filepath.Join(opts.SrcContext, ".dockerignore") - return os.Remove(path) } // ignoreFile returns true if the path matches any of the paths in ignore