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 39c24e310b..de81161410 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 55d256f289..089378442e 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 0000000000..04fdc27014 --- /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 464db8cc88..daeeca24b1 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 fc15c1f213..2c91955981 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 daeeca24b1..b190e61f6d 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 de81161410..39c24e310b 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 089378442e..5bdeb0c872 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 + } + ignore, err := dockerfile.ParseDockerignore(opts) + if err != nil { + return err } - err := filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { - if ignoreFile(path) { + 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 b190e61f6d..19d7a91d2a 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 2c91955981..fc15c1f213 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 8b06985b60..c2eb9bff7e 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 5bdeb0c872..dcbb48430f 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 19d7a91d2a..1f392be571 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 dcbb48430f..fa244d3323 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