From e004ebd86d88c184e770f644f519cf23b52a8062 Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Mon, 17 Dec 2018 17:30:53 +0100 Subject: [PATCH] a --- internal/packager/packing_test.go | 56 ++++++++++--- internal/tar/untar.go | 126 ------------------------------ 2 files changed, 45 insertions(+), 137 deletions(-) delete mode 100644 internal/tar/untar.go diff --git a/internal/packager/packing_test.go b/internal/packager/packing_test.go index 3fc15feb1..cc7a39d70 100644 --- a/internal/packager/packing_test.go +++ b/internal/packager/packing_test.go @@ -1,13 +1,15 @@ package packager import ( + "archive/tar" "bytes" + "fmt" + "io" + "strings" "testing" - "github.com/docker/app/internal/tar" "github.com/docker/app/types" "gotest.tools/assert" - "gotest.tools/fs" ) func TestPackInvocationImageContext(t *testing.T) { @@ -15,13 +17,45 @@ func TestPackInvocationImageContext(t *testing.T) { assert.NilError(t, err) buf := bytes.NewBuffer(nil) assert.NilError(t, PackInvocationImageContext(app, buf)) - dir := fs.NewDir(t, t.Name()) - defer dir.Remove() - assert.NilError(t, untar.Untar(buf, dir.Path(), false)) - expectedDir := fs.NewDir(t, t.Name(), - fs.FromDir("testdata/packages"), - fs.WithFile("Dockerfile", dockerFile), - fs.WithFile(".dockerignore", dockerIgnore)) - defer expectedDir.Remove() - assert.Assert(t, fs.Equal(dir.Path(), fs.ManifestFromDir(t, expectedDir.Path()))) + assert.NilError(t, hasExpectedFiles(buf, map[string]bool{ + "Dockerfile": true, + ".dockerignore": true, + "packing.dockerapp/metadata.yml": true, + "packing.dockerapp/docker-compose.yml": true, + "packing.dockerapp/parameters.yml": true, + "packing.dockerapp/config.cfg": true, + "packing.dockerapp/nesteddir/config2.cfg": true, + "packing.dockerapp/nesteddir/nested2/nested3/config3.cfg": true, + })) +} + +func hasExpectedFiles(r io.Reader, expectedFiles map[string]bool) error { + tr := tar.NewReader(r) + var errors []string + var count int + for { + hdr, err := tr.Next() + if err == io.EOF { + break // End of archive + } + if err != nil { + return err + } + if hdr.Size == 0 { + errors = append(errors, fmt.Sprintf("content of '%s' is empty", hdr.Name)) + } + count++ + if !expectedFiles[hdr.Name] { + errors = append(errors, fmt.Sprintf("couldn't find file '%s' in the tar archive", hdr.Name)) + break + } + } + if count != len(expectedFiles) { + errors = append(errors, fmt.Sprintf("number of expected files is in archive is '%d', but '%d' were found", + len(expectedFiles), count)) + } + if len(errors) != 0 { + return fmt.Errorf("%s", strings.Join(errors, "\n")) + } + return nil } diff --git a/internal/tar/untar.go b/internal/tar/untar.go deleted file mode 100644 index b44b20477..000000000 --- a/internal/tar/untar.go +++ /dev/null @@ -1,126 +0,0 @@ -package untar - -import ( - "archive/tar" - "compress/gzip" - "fmt" - "io" - "log" - "os" - "path/filepath" - "strings" - "time" -) - -// Untar takes a io.Reader, the destination directory and a boolean set to true when it's gzipped -// Adapted from https://github.com/golang/build/blob/master/internal/untar/untar.go -// As it's an internal function, it could not be imported -func Untar(r io.Reader, dir string, isGzipped bool) error { - return untar(r, dir, isGzipped) -} - -func untar(r io.Reader, dir string, isGzipped bool) (err error) { - t0 := time.Now() - nFiles := 0 - madeDir := map[string]bool{} - defer func() { - td := time.Since(t0) - if err == nil { - log.Printf("extracted tarball into %s: %d files, %d dirs (%v)", dir, nFiles, len(madeDir), td) - } else { - log.Printf("error extracting tarball into %s after %d files, %d dirs, %v: %v", dir, nFiles, len(madeDir), td, err) - } - }() - - var tr *tar.Reader - if isGzipped { - zr, err := gzip.NewReader(r) - if err != nil { - return fmt.Errorf("requires gzip-compressed body: %v", err) - } - tr = tar.NewReader(zr) - } - if tr == nil { - tr = tar.NewReader(r) - } - - loggedChtimesError := false - for { - f, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - log.Printf("tar reading error: %v", err) - return fmt.Errorf("tar error: %v", err) - } - if !validRelPath(f.Name) { - return fmt.Errorf("tar contained invalid name error %q", f.Name) - } - rel := filepath.FromSlash(f.Name) - abs := filepath.Join(dir, rel) - - fi := f.FileInfo() - mode := fi.Mode() - switch { - case mode.IsRegular(): - var ioReader io.Reader = tr - err := processRegular(madeDir, abs, mode, f, t0, &ioReader, &loggedChtimesError) - if err != nil { - return err - } - nFiles++ - case mode.IsDir(): - if err := os.MkdirAll(abs, 0755); err != nil { - return err - } - madeDir[abs] = true - default: - return fmt.Errorf("tar file entry %s contained unsupported file type %v", f.Name, mode) - } - } - return nil -} - -func validRelPath(p string) bool { - if p == "" || strings.Contains(p, `\`) || strings.HasPrefix(p, "/") || strings.Contains(p, "../") { - return false - } - return true -} - -func processRegular(madeDir map[string]bool, abs string, mode os.FileMode, f *tar.Header, t0 time.Time, tr *io.Reader, loggedChtimesError *bool) error { - dir := filepath.Dir(abs) - if !madeDir[dir] { - if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil { - return err - } - madeDir[dir] = true - } - wf, err := os.OpenFile(abs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm()) - if err != nil { - return err - } - n, err := io.Copy(wf, *tr) - if closeErr := wf.Close(); closeErr != nil && err == nil { - err = closeErr - } - if err != nil { - return fmt.Errorf("error writing to %s: %v", abs, err) - } - if n != f.Size { - return fmt.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size) - } - modTime := f.ModTime - if modTime.After(t0) { - modTime = t0 - } - if !modTime.IsZero() { - if err := os.Chtimes(abs, modTime, modTime); err != nil && !*loggedChtimesError { - log.Printf("error changing modtime: %v (further Chtimes errors suppressed)", err) - *loggedChtimesError = true // once is enough - } - } - - return nil -}