mirror of
https://github.com/GoogleContainerTools/kaniko
synced 2026-10-21 08:06:50 +02:00
Fix .dockerignore for build context copies in later stages (#1447)
* Extend .dockerignore integration test with copies in later stages .dockerignore should continue to apply when copying from the build context in later stages, but it currently doesn't * Replace excluded global with passed along FileContext struct This new FileContext struct allows much cleaner handling of context specific file exclusions. The global excluded file state is no longer needed. Additionally this also fixes the issue where excluded files aren't being applied for build context copies in later build stages.
This commit is contained in:
@@ -85,7 +85,7 @@ func ResolveEnvironmentReplacement(value string, envs []string, isFilepath bool)
|
||||
return fp, nil
|
||||
}
|
||||
|
||||
func ResolveEnvAndWildcards(sd instructions.SourcesAndDest, buildcontext string, envs []string) ([]string, string, error) {
|
||||
func ResolveEnvAndWildcards(sd instructions.SourcesAndDest, fileContext FileContext, envs []string) ([]string, string, error) {
|
||||
// First, resolve any environment replacement
|
||||
resolvedEnvs, err := ResolveEnvironmentReplacementList(sd, envs, true)
|
||||
if err != nil {
|
||||
@@ -96,11 +96,11 @@ func ResolveEnvAndWildcards(sd instructions.SourcesAndDest, buildcontext string,
|
||||
}
|
||||
dest := resolvedEnvs[len(resolvedEnvs)-1]
|
||||
// Resolve wildcards and get a list of resolved sources
|
||||
srcs, err := ResolveSources(resolvedEnvs[0:len(resolvedEnvs)-1], buildcontext)
|
||||
srcs, err := ResolveSources(resolvedEnvs[0:len(resolvedEnvs)-1], fileContext.Root)
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "failed to resolve sources")
|
||||
}
|
||||
err = IsSrcsValid(sd, srcs, buildcontext)
|
||||
err = IsSrcsValid(sd, srcs, fileContext)
|
||||
return srcs, dest, err
|
||||
}
|
||||
|
||||
@@ -220,14 +220,14 @@ func URLDestinationFilepath(rawurl, dest, cwd string, envs []string) (string, er
|
||||
return destPath, nil
|
||||
}
|
||||
|
||||
func IsSrcsValid(srcsAndDest instructions.SourcesAndDest, resolvedSources []string, root string) error {
|
||||
func IsSrcsValid(srcsAndDest instructions.SourcesAndDest, resolvedSources []string, fileContext FileContext) error {
|
||||
srcs := srcsAndDest[:len(srcsAndDest)-1]
|
||||
dest := srcsAndDest[len(srcsAndDest)-1]
|
||||
|
||||
if !ContainsWildcards(srcs) {
|
||||
totalSrcs := 0
|
||||
for _, src := range srcs {
|
||||
if ExcludeFile(src, root) {
|
||||
if fileContext.ExcludesFile(src) {
|
||||
continue
|
||||
}
|
||||
totalSrcs++
|
||||
@@ -242,7 +242,7 @@ func IsSrcsValid(srcsAndDest instructions.SourcesAndDest, resolvedSources []stri
|
||||
if IsSrcRemoteFileURL(resolvedSources[0]) {
|
||||
return nil
|
||||
}
|
||||
path := filepath.Join(root, resolvedSources[0])
|
||||
path := filepath.Join(fileContext.Root, resolvedSources[0])
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("failed to get fileinfo for %v", path))
|
||||
@@ -259,12 +259,12 @@ func IsSrcsValid(srcsAndDest instructions.SourcesAndDest, resolvedSources []stri
|
||||
continue
|
||||
}
|
||||
src = filepath.Clean(src)
|
||||
files, err := RelativeFiles(src, root)
|
||||
files, err := RelativeFiles(src, fileContext.Root)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get relative files")
|
||||
}
|
||||
for _, file := range files {
|
||||
if ExcludeFile(file, root) {
|
||||
if fileContext.ExcludesFile(file) {
|
||||
continue
|
||||
}
|
||||
totalFiles++
|
||||
|
||||
@@ -478,10 +478,11 @@ var isSrcValidTests = []struct {
|
||||
func Test_IsSrcsValid(t *testing.T) {
|
||||
for _, test := range isSrcValidTests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if err := GetExcludedFiles("", buildContextPath); err != nil {
|
||||
t.Fatalf("error getting excluded files: %v", err)
|
||||
fileContext, err := NewFileContextFromDockerfile("", buildContextPath)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating file context: %v", err)
|
||||
}
|
||||
err := IsSrcsValid(test.srcsAndDest, test.resolvedSources, buildContextPath)
|
||||
err = IsSrcsValid(test.srcsAndDest, test.resolvedSources, fileContext)
|
||||
testutil.CheckError(t, test.shouldErr, err)
|
||||
})
|
||||
}
|
||||
|
||||
+34
-26
@@ -74,8 +74,10 @@ var ignorelist = initialIgnoreList
|
||||
|
||||
var volumes = []string{}
|
||||
|
||||
var excluded []string
|
||||
var IsFirstStage = true
|
||||
type FileContext struct {
|
||||
Root string
|
||||
ExcludedFiles []string
|
||||
}
|
||||
|
||||
type ExtractFunction func(string, *tar.Header, io.Reader) error
|
||||
|
||||
@@ -581,7 +583,7 @@ func DetermineTargetFileOwnership(fi os.FileInfo, uid, gid int64) (int64, int64)
|
||||
|
||||
// CopyDir copies the file or directory at src to dest
|
||||
// It returns a list of files it copied over
|
||||
func CopyDir(src, dest, buildcontext string, uid, gid int64) ([]string, error) {
|
||||
func CopyDir(src, dest string, context FileContext, uid, gid int64) ([]string, error) {
|
||||
files, err := RelativeFiles("", src)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "copying dir")
|
||||
@@ -593,7 +595,7 @@ func CopyDir(src, dest, buildcontext string, uid, gid int64) ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "copying dir")
|
||||
}
|
||||
if ExcludeFile(fullPath, buildcontext) {
|
||||
if context.ExcludesFile(fullPath) {
|
||||
logrus.Debugf("%s found in .dockerignore, ignoring", src)
|
||||
continue
|
||||
}
|
||||
@@ -608,12 +610,12 @@ func CopyDir(src, dest, buildcontext string, uid, gid int64) ([]string, error) {
|
||||
}
|
||||
} else if IsSymlink(fi) {
|
||||
// If file is a symlink, we want to create the same relative symlink
|
||||
if _, err := CopySymlink(fullPath, destPath, buildcontext); err != nil {
|
||||
if _, err := CopySymlink(fullPath, destPath, context); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// ... Else, we want to copy over a file
|
||||
if _, err := CopyFile(fullPath, destPath, buildcontext, uid, gid); err != nil {
|
||||
if _, err := CopyFile(fullPath, destPath, context, uid, gid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -623,8 +625,8 @@ func CopyDir(src, dest, buildcontext string, uid, gid int64) ([]string, error) {
|
||||
}
|
||||
|
||||
// CopySymlink copies the symlink at src to dest.
|
||||
func CopySymlink(src, dest, buildcontext string) (bool, error) {
|
||||
if ExcludeFile(src, buildcontext) {
|
||||
func CopySymlink(src, dest string, context FileContext) (bool, error) {
|
||||
if context.ExcludesFile(src) {
|
||||
logrus.Debugf("%s found in .dockerignore, ignoring", src)
|
||||
return true, nil
|
||||
}
|
||||
@@ -644,8 +646,8 @@ func CopySymlink(src, dest, buildcontext string) (bool, error) {
|
||||
}
|
||||
|
||||
// CopyFile copies the file at src to dest
|
||||
func CopyFile(src, dest, buildcontext string, uid, gid int64) (bool, error) {
|
||||
if ExcludeFile(src, buildcontext) {
|
||||
func CopyFile(src, dest string, context FileContext, uid, gid int64) (bool, error) {
|
||||
if context.ExcludesFile(src) {
|
||||
logrus.Debugf("%s found in .dockerignore, ignoring", src)
|
||||
return true, nil
|
||||
}
|
||||
@@ -669,40 +671,46 @@ func CopyFile(src, dest, buildcontext string, uid, gid int64) (bool, error) {
|
||||
return false, CreateFile(dest, srcFile, fi.Mode(), uint32(uid), uint32(gid))
|
||||
}
|
||||
|
||||
// GetExcludedFiles gets a list of files to exclude from the .dockerignore
|
||||
func GetExcludedFiles(dockerfilepath string, buildcontext string) error {
|
||||
path := dockerfilepath + ".dockerignore"
|
||||
func NewFileContextFromDockerfile(dockerfilePath, buildcontext string) (FileContext, error) {
|
||||
fileContext := FileContext{Root: buildcontext}
|
||||
excludedFiles, err := getExcludedFiles(dockerfilePath, buildcontext)
|
||||
if err != nil {
|
||||
return fileContext, err
|
||||
}
|
||||
fileContext.ExcludedFiles = excludedFiles
|
||||
return fileContext, nil
|
||||
}
|
||||
|
||||
// getExcludedFiles returns a list of files to exclude from the .dockerignore
|
||||
func getExcludedFiles(dockerfilePath, buildcontext string) ([]string, error) {
|
||||
path := dockerfilePath + ".dockerignore"
|
||||
if !FilepathExists(path) {
|
||||
path = filepath.Join(buildcontext, ".dockerignore")
|
||||
}
|
||||
if !FilepathExists(path) {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
logrus.Infof("Using dockerignore file: %v", path)
|
||||
contents, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parsing .dockerignore")
|
||||
return nil, errors.Wrap(err, "parsing .dockerignore")
|
||||
}
|
||||
reader := bytes.NewBuffer(contents)
|
||||
excluded, err = dockerignore.ReadAll(reader)
|
||||
return err
|
||||
return dockerignore.ReadAll(reader)
|
||||
}
|
||||
|
||||
// ExcludeFile returns true if the .dockerignore specified this file should be ignored
|
||||
func ExcludeFile(path, buildcontext string) bool {
|
||||
// Apply dockerfile excludes for first stage only
|
||||
if !IsFirstStage {
|
||||
return false
|
||||
}
|
||||
if HasFilepathPrefix(path, buildcontext, false) {
|
||||
// ExcludesFile returns true if the file context specified this file should be ignored.
|
||||
// Usually this is specified via .dockerignore
|
||||
func (c FileContext) ExcludesFile(path string) bool {
|
||||
if HasFilepathPrefix(path, c.Root, false) {
|
||||
var err error
|
||||
path, err = filepath.Rel(buildcontext, path)
|
||||
path, err = filepath.Rel(c.Root, path)
|
||||
if err != nil {
|
||||
logrus.Errorf("unable to get relative path, including %s in build: %v", path, err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
match, err := fileutils.Matches(path, excluded)
|
||||
match, err := fileutils.Matches(path, c.ExcludedFiles)
|
||||
if err != nil {
|
||||
logrus.Errorf("error matching, including %s in build: %v", path, err)
|
||||
return false
|
||||
|
||||
@@ -880,7 +880,7 @@ func TestCopySymlink(t *testing.T) {
|
||||
if err := os.Symlink(tc.linkTarget, link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := CopySymlink(link, dest, ""); err != nil {
|
||||
if _, err := CopySymlink(link, dest, FileContext{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := os.Lstat(dest); err != nil {
|
||||
@@ -966,19 +966,20 @@ func Test_correctDockerignoreFileIsUsed(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if err := GetExcludedFiles(tt.args.dockerfilepath, tt.args.buildcontext); err != nil {
|
||||
fileContext, err := NewFileContextFromDockerfile(tt.args.dockerfilepath, tt.args.buildcontext)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, excl := range tt.args.excluded {
|
||||
t.Run(tt.name+" to exclude "+excl, func(t *testing.T) {
|
||||
if !ExcludeFile(excl, tt.args.buildcontext) {
|
||||
if !fileContext.ExcludesFile(excl) {
|
||||
t.Errorf("'%v' not excluded", excl)
|
||||
}
|
||||
})
|
||||
}
|
||||
for _, incl := range tt.args.included {
|
||||
t.Run(tt.name+" to include "+incl, func(t *testing.T) {
|
||||
if ExcludeFile(incl, tt.args.buildcontext) {
|
||||
if fileContext.ExcludesFile(incl) {
|
||||
t.Errorf("'%v' not included", incl)
|
||||
}
|
||||
})
|
||||
@@ -1004,7 +1005,7 @@ func Test_CopyFile_skips_self(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ignored, err := CopyFile(tempFile, tempFile, "", DoNotChangeUID, DoNotChangeGID)
|
||||
ignored, err := CopyFile(tempFile, tempFile, FileContext{}, DoNotChangeUID, DoNotChangeGID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user