mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Implement TarFilter in go, rather than calling out to tar
This uses a plain filepath.Walk + addTarFile to create a tar file, optionially compressing it with gzip. Unfortunately go only has gzip compression support, not bzip2 or xz. However, this is not a regression, as docker currently uses *no* compression for TarFilter(). The only compression of tarfiles currently happens in utils/tarsum.go, and that manually does gzip compression. Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
This commit is contained in:
parent
bab8efbf05
commit
5ea48aa7f8
2 changed files with 69 additions and 21 deletions
|
@ -97,16 +97,20 @@ func DecompressStream(archive io.Reader) (io.Reader, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (compression *Compression) Flag() string {
|
||||
switch *compression {
|
||||
case Bzip2:
|
||||
return "j"
|
||||
func CompressStream(dest io.WriteCloser, compression Compression) (io.WriteCloser, error) {
|
||||
|
||||
switch compression {
|
||||
case Uncompressed:
|
||||
return dest, nil
|
||||
case Gzip:
|
||||
return "z"
|
||||
case Xz:
|
||||
return "J"
|
||||
return gzip.NewWriter(dest), nil
|
||||
case Bzip2, Xz:
|
||||
// archive/bzip2 does not support writing, and there is no xz support at all
|
||||
// However, this is not a problem as docker only currently generates gzipped tars
|
||||
return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension())
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (compression *Compression) Extension() string {
|
||||
|
@ -130,7 +134,7 @@ func addTarFile(path, name string, tw *tar.Writer) error {
|
|||
}
|
||||
|
||||
link := ""
|
||||
if fi.Mode() & os.ModeSymlink != 0 {
|
||||
if fi.Mode()&os.ModeSymlink != 0 {
|
||||
if link, err = os.Readlink(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -274,19 +278,55 @@ 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, options *TarOptions) (io.Reader, error) {
|
||||
args := []string{"tar", "--numeric-owner", "-f", "-", "-C", path, "-T", "-"}
|
||||
if options.Includes == nil {
|
||||
options.Includes = []string{"."}
|
||||
}
|
||||
args = append(args, "-c"+options.Compression.Flag())
|
||||
func TarFilter(srcPath string, options *TarOptions) (io.Reader, error) {
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
|
||||
files := ""
|
||||
for _, f := range options.Includes {
|
||||
files = files + escapeName(f) + "\n"
|
||||
compressWriter, err := CompressStream(pipeWriter, options.Compression)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return CmdStream(exec.Command(args[0], args[1:]...), bytes.NewBufferString(files))
|
||||
tw := tar.NewWriter(compressWriter)
|
||||
|
||||
go func() {
|
||||
// In general we log errors here but ignore them because
|
||||
// during e.g. a diff operation the container can continue
|
||||
// mutating the filesystem and we can see transient errors
|
||||
// from this
|
||||
|
||||
if options.Includes == nil {
|
||||
options.Includes = []string{"."}
|
||||
}
|
||||
|
||||
for _, include := range options.Includes {
|
||||
filepath.Walk(filepath.Join(srcPath, include), func(filePath string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
utils.Debugf("Tar: Can't stat file %s to tar: %s\n", srcPath, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
relFilePath, err := filepath.Rel(srcPath, filePath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := addTarFile(filePath, relFilePath, tw); err != nil {
|
||||
utils.Debugf("Can't add file %s to tar: %s\n", srcPath, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Make sure to check the error on Close.
|
||||
if err := tw.Close(); err != nil {
|
||||
utils.Debugf("Can't close tar writer: %s\n", err)
|
||||
}
|
||||
if err := compressWriter.Close(); err != nil {
|
||||
utils.Debugf("Can't close compress writer: %s\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return pipeReader, nil
|
||||
}
|
||||
|
||||
// Untar reads a stream of bytes from `archive`, parses it as a tar archive,
|
||||
|
|
|
@ -89,6 +89,16 @@ func tarUntar(t *testing.T, origin string, compression Compression) error {
|
|||
if _, err := os.Stat(tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
changes, err := ChangesDirs(origin, tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(changes) != 0 {
|
||||
t.Fatalf("Unexpected differences after tarUntar: %v", changes)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -108,8 +118,6 @@ func TestTarUntar(t *testing.T) {
|
|||
for _, c := range []Compression{
|
||||
Uncompressed,
|
||||
Gzip,
|
||||
Bzip2,
|
||||
Xz,
|
||||
} {
|
||||
if err := tarUntar(t, origin, c); err != nil {
|
||||
t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue