From 2c7f50a77dc281289387008b4a08656e7e5328be Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 11 Nov 2013 14:30:38 -0800 Subject: [PATCH] Add ability to exclude files from tar --- archive/archive.go | 34 +++++++++++++++++++++++----------- archive/changes.go | 36 +++++++++++++++++------------------- aufs/aufs.go | 16 +++++++++------- container.go | 6 +++++- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/archive/archive.go b/archive/archive.go index dd96abf626..4d28587e5d 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -15,7 +15,15 @@ import ( type Archive io.Reader -type Compression uint32 +type Compression int + +type TarOptions struct { + Includes []string + Excludes []string + Recursive bool + Compression Compression + CreateFiles []string +} const ( Uncompressed Compression = iota @@ -80,7 +88,7 @@ func (compression *Compression) Extension() string { // Tar creates an archive from the directory at `path`, and returns it as a // stream of bytes. func Tar(path string, compression Compression) (io.Reader, error) { - return TarFilter(path, compression, nil, true, nil) + return TarFilter(path, &TarOptions{Recursive: true, Compression: compression}) } func escapeName(name string) string { @@ -101,25 +109,29 @@ func escapeName(name string) string { // Tar creates an archive from the directory at `path`, only including files whose relative // paths are included in `filter`. If `filter` is nil, then all files are included. -func TarFilter(path string, compression Compression, filter []string, recursive bool, createFiles []string) (io.Reader, error) { +func TarFilter(path string, options *TarOptions) (io.Reader, error) { args := []string{"tar", "--numeric-owner", "-f", "-", "-C", path, "-T", "-"} - if filter == nil { - filter = []string{"."} + if options.Includes == nil { + options.Includes = []string{"."} } - args = append(args, "-c"+compression.Flag()) + args = append(args, "-c"+options.Compression.Flag()) - if !recursive { + for _, exclude := range options.Excludes { + args = append(args, fmt.Sprintf("--exclude=%s", exclude)) + } + + if !options.Recursive { args = append(args, "--no-recursion") } files := "" - for _, f := range filter { + for _, f := range options.Includes { files = files + escapeName(f) + "\n" } tmpDir := "" - if createFiles != nil { + if options.CreateFiles != nil { var err error // Can't use := here or we override the outer tmpDir tmpDir, err = ioutil.TempDir("", "docker-tar") if err != nil { @@ -127,7 +139,7 @@ func TarFilter(path string, compression Compression, filter []string, recursive } files = files + "-C" + tmpDir + "\n" - for _, f := range createFiles { + for _, f := range options.CreateFiles { path := filepath.Join(tmpDir, f) err := os.MkdirAll(filepath.Dir(path), 0600) if err != nil { @@ -194,7 +206,7 @@ func Untar(archive io.Reader, path string) error { // TarUntar aborts and returns the error. func TarUntar(src string, filter []string, dst string) error { utils.Debugf("TarUntar(%s %s %s)", src, filter, dst) - archive, err := TarFilter(src, Uncompressed, filter, true, nil) + archive, err := TarFilter(src, &TarOptions{Compression: Uncompressed, Includes: filter, Recursive: true}) if err != nil { return err } diff --git a/archive/changes.go b/archive/changes.go index a03172115f..94c30e325a 100644 --- a/archive/changes.go +++ b/archive/changes.go @@ -207,24 +207,22 @@ func ChangesDirs(newDir, oldDir string) ([]Change, error) { return changes, nil } - func ExportChanges(root, rw string) (Archive, error) { - changes, err := ChangesDirs(root, rw) - if err != nil { - return nil, err - } - files := make([]string, 0) - deletions := make([]string, 0) - for _, change := range changes { - if change.Kind == ChangeModify || change.Kind == ChangeAdd { - files = append(files, change.Path) - } - if change.Kind == ChangeDelete { - base := filepath.Base(change.Path) - dir := filepath.Dir(change.Path) - deletions = append(deletions, filepath.Join(dir, ".wh."+base)) - } - } - return TarFilter(root, Uncompressed, files, false, deletions) + changes, err := ChangesDirs(root, rw) + if err != nil { + return nil, err + } + files := make([]string, 0) + deletions := make([]string, 0) + for _, change := range changes { + if change.Kind == ChangeModify || change.Kind == ChangeAdd { + files = append(files, change.Path) + } + if change.Kind == ChangeDelete { + base := filepath.Base(change.Path) + dir := filepath.Dir(change.Path) + deletions = append(deletions, filepath.Join(dir, ".wh."+base)) + } + } + return TarFilter(root, &TarOptions{Compression: Uncompressed, Recursive: false, Includes: files, CreateFiles: deletions}) } - diff --git a/aufs/aufs.go b/aufs/aufs.go index 6865020a94..a1ec39d3d2 100644 --- a/aufs/aufs.go +++ b/aufs/aufs.go @@ -137,8 +137,7 @@ func (a *AufsDriver) createDirsFor(id string) error { } for _, p := range paths { - dir := path.Join(a.rootPath(), p, id) - if err := os.MkdirAll(dir, 0755); err != nil { + if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil { return err } } @@ -201,11 +200,14 @@ func (a *AufsDriver) Get(id string) (string, error) { // Returns an archive of the contents for the id func (a *AufsDriver) Diff(id string) (archive.Archive, error) { - p, err := a.Get(id) - if err != nil { - return nil, err - } - return archive.Tar(p, archive.Uncompressed) + // Exclude top level aufs metadata from the diff + return archive.TarFilter( + path.Join(a.rootPath(), "diff", id), + &archive.TarOptions{ + Excludes: []string{".wh*"}, + Recursive: true, + Compression: archive.Uncompressed, + }) } // Returns the size of the contents for the id diff --git a/container.go b/container.go index 3f471f4d09..c39bc335a1 100644 --- a/container.go +++ b/container.go @@ -1527,7 +1527,11 @@ func (container *Container) Copy(resource string) (archive.Archive, error) { filter = []string{path.Base(basePath)} basePath = path.Dir(basePath) } - return archive.TarFilter(basePath, archive.Uncompressed, filter, true, nil) + return archive.TarFilter(basePath, &archive.TarOptions{ + Compression: archive.Uncompressed, + Includes: filter, + Recursive: true, + }) } // Returns true if the container exposes a certain port