From 3fc43f4c736ad47488d594e9effdde4a7e3b391c Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Fri, 19 Oct 2018 09:54:49 -0700 Subject: [PATCH] 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 == ' ' +}