|
@@ -30,11 +30,11 @@ type (
|
|
ArchiveReader io.Reader
|
|
ArchiveReader io.Reader
|
|
Compression int
|
|
Compression int
|
|
TarOptions struct {
|
|
TarOptions struct {
|
|
- Includes []string
|
|
|
|
- Excludes []string
|
|
|
|
- Compression Compression
|
|
|
|
- NoLchown bool
|
|
|
|
- Name string
|
|
|
|
|
|
+ IncludeFiles []string
|
|
|
|
+ ExcludePatterns []string
|
|
|
|
+ Compression Compression
|
|
|
|
+ NoLchown bool
|
|
|
|
+ Name string
|
|
}
|
|
}
|
|
|
|
|
|
// Archiver allows the reuse of most utility functions of this package
|
|
// Archiver allows the reuse of most utility functions of this package
|
|
@@ -378,7 +378,7 @@ func escapeName(name string) string {
|
|
}
|
|
}
|
|
|
|
|
|
// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
|
|
// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
|
|
-// paths are included in `options.Includes` (if non-nil) or not in `options.Excludes`.
|
|
|
|
|
|
+// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
|
|
func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
|
func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
|
pipeReader, pipeWriter := io.Pipe()
|
|
pipeReader, pipeWriter := io.Pipe()
|
|
|
|
|
|
@@ -401,12 +401,14 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|
// mutating the filesystem and we can see transient errors
|
|
// mutating the filesystem and we can see transient errors
|
|
// from this
|
|
// from this
|
|
|
|
|
|
- if options.Includes == nil {
|
|
|
|
- options.Includes = []string{"."}
|
|
|
|
|
|
+ if options.IncludeFiles == nil {
|
|
|
|
+ options.IncludeFiles = []string{"."}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ seen := make(map[string]bool)
|
|
|
|
+
|
|
var renamedRelFilePath string // For when tar.Options.Name is set
|
|
var renamedRelFilePath string // For when tar.Options.Name is set
|
|
- for _, include := range options.Includes {
|
|
|
|
|
|
+ for _, include := range options.IncludeFiles {
|
|
filepath.Walk(filepath.Join(srcPath, include), func(filePath string, f os.FileInfo, err error) error {
|
|
filepath.Walk(filepath.Join(srcPath, include), func(filePath string, f os.FileInfo, err error) error {
|
|
if err != nil {
|
|
if err != nil {
|
|
log.Debugf("Tar: Can't stat file %s to tar: %s", srcPath, err)
|
|
log.Debugf("Tar: Can't stat file %s to tar: %s", srcPath, err)
|
|
@@ -420,10 +422,19 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
- skip, err := fileutils.Matches(relFilePath, options.Excludes)
|
|
|
|
- if err != nil {
|
|
|
|
- log.Debugf("Error matching %s", relFilePath, err)
|
|
|
|
- return err
|
|
|
|
|
|
+ skip := false
|
|
|
|
+
|
|
|
|
+ // If "include" is an exact match for the current file
|
|
|
|
+ // then even if there's an "excludePatterns" pattern that
|
|
|
|
+ // matches it, don't skip it. IOW, assume an explicit 'include'
|
|
|
|
+ // is asking for that file no matter what - which is true
|
|
|
|
+ // for some files, like .dockerignore and Dockerfile (sometimes)
|
|
|
|
+ if include != relFilePath {
|
|
|
|
+ skip, err = fileutils.Matches(relFilePath, options.ExcludePatterns)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Debugf("Error matching %s", relFilePath, err)
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if skip {
|
|
if skip {
|
|
@@ -433,6 +444,11 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if seen[relFilePath] {
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+ seen[relFilePath] = true
|
|
|
|
+
|
|
// Rename the base resource
|
|
// Rename the base resource
|
|
if options.Name != "" && filePath == srcPath+"/"+filepath.Base(relFilePath) {
|
|
if options.Name != "" && filePath == srcPath+"/"+filepath.Base(relFilePath) {
|
|
renamedRelFilePath = relFilePath
|
|
renamedRelFilePath = relFilePath
|
|
@@ -487,7 +503,7 @@ loop:
|
|
// This keeps "../" as-is, but normalizes "/../" to "/"
|
|
// This keeps "../" as-is, but normalizes "/../" to "/"
|
|
hdr.Name = filepath.Clean(hdr.Name)
|
|
hdr.Name = filepath.Clean(hdr.Name)
|
|
|
|
|
|
- for _, exclude := range options.Excludes {
|
|
|
|
|
|
+ for _, exclude := range options.ExcludePatterns {
|
|
if strings.HasPrefix(hdr.Name, exclude) {
|
|
if strings.HasPrefix(hdr.Name, exclude) {
|
|
continue loop
|
|
continue loop
|
|
}
|
|
}
|
|
@@ -563,8 +579,8 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
|
if options == nil {
|
|
if options == nil {
|
|
options = &TarOptions{}
|
|
options = &TarOptions{}
|
|
}
|
|
}
|
|
- if options.Excludes == nil {
|
|
|
|
- options.Excludes = []string{}
|
|
|
|
|
|
+ if options.ExcludePatterns == nil {
|
|
|
|
+ options.ExcludePatterns = []string{}
|
|
}
|
|
}
|
|
decompressedArchive, err := DecompressStream(archive)
|
|
decompressedArchive, err := DecompressStream(archive)
|
|
if err != nil {
|
|
if err != nil {
|