diff --git a/buildfile.go b/buildfile.go index dc86026226..de03e5879f 100644 --- a/buildfile.go +++ b/buildfile.go @@ -353,8 +353,9 @@ func (b *buildFile) CmdAdd(args string) error { // FIXME: do we really need this? var ( - origPath = orig - destPath = dest + origPath = orig + destPath = dest + remoteHash string ) if utils.IsURL(orig) { @@ -373,11 +374,20 @@ func (b *buildFile) CmdAdd(args string) error { } defer os.RemoveAll(tmpDirName) if _, err = io.Copy(tmpFile, resp.Body); err != nil { + tmpFile.Close() return err } origPath = path.Join(filepath.Base(tmpDirName), filepath.Base(tmpFileName)) tmpFile.Close() + // Process the checksum + r, err := archive.Tar(tmpFileName, archive.Uncompressed) + if err != nil { + return err + } + tarSum := utils.TarSum{Reader: r, DisableCompression: true} + remoteHash = tarSum.Sum(nil) + // If the destination is a directory, figure out the filename. if strings.HasSuffix(dest, "/") { u, err := url.Parse(orig) @@ -408,20 +418,16 @@ func (b *buildFile) CmdAdd(args string) error { sums = b.context.GetSums() ) - // Has tarsum strips the '.' and './', we put it back for comparaison. - for file, sum := range sums { - if len(file) == 0 || file[0] != '.' && file[0] != '/' { - delete(sums, file) - sums["./"+file] = sum - } - } - - if fi, err := os.Stat(path.Join(b.contextPath, origPath)); err != nil { + if remoteHash != "" { + hash = remoteHash + } else if fi, err := os.Stat(path.Join(b.contextPath, origPath)); err != nil { return err } else if fi.IsDir() { var subfiles []string for file, sum := range sums { - if strings.HasPrefix(file, origPath) { + absFile := path.Join(b.contextPath, file) + absOrigPath := path.Join(b.contextPath, origPath) + if strings.HasPrefix(absFile, absOrigPath) { subfiles = append(subfiles, sum) } } @@ -430,7 +436,13 @@ func (b *buildFile) CmdAdd(args string) error { hasher.Write([]byte(strings.Join(subfiles, ","))) hash = "dir:" + hex.EncodeToString(hasher.Sum(nil)) } else { - hash = "file:" + sums[origPath] + if origPath[0] == '/' && len(origPath) > 1 { + origPath = origPath[1:] + } + origPath = strings.TrimPrefix(origPath, "./") + if h, ok := sums[origPath]; ok { + hash = "file:" + h + } } b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", hash, dest)} hit, err := b.probeCache() diff --git a/integration/buildfile_test.go b/integration/buildfile_test.go index ef51777390..5dd403274e 100644 --- a/integration/buildfile_test.go +++ b/integration/buildfile_test.go @@ -592,6 +592,26 @@ func TestBuildADDLocalFileWithoutCache(t *testing.T) { checkCacheBehavior(t, template, false) } +func TestBuildADDCurrentDirectoryWithCache(t *testing.T) { + template := testContextTemplate{` + from {IMAGE} + maintainer dockerio + add . /usr/lib/bla + `, + nil, nil} + checkCacheBehavior(t, template, true) +} + +func TestBuildADDCurrentDirectoryWithoutCache(t *testing.T) { + template := testContextTemplate{` + from {IMAGE} + maintainer dockerio + add . /usr/lib/bla + `, + nil, nil} + checkCacheBehavior(t, template, false) +} + func TestBuildADDRemoteFileWithCache(t *testing.T) { template := testContextTemplate{` from {IMAGE} diff --git a/utils/utils.go b/utils/utils.go index d5dbf35f0a..4dfadb793f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -6,7 +6,6 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "errors" "fmt" "index/suffixarray" "io" @@ -46,14 +45,12 @@ func Go(f func() error) chan error { } // Request a given URL and return an io.Reader -func Download(url string) (*http.Response, error) { - var resp *http.Response - var err error +func Download(url string) (resp *http.Response, err error) { if resp, err = http.Get(url); err != nil { return nil, err } if resp.StatusCode >= 400 { - return nil, errors.New("Got HTTP status code >= 400: " + resp.Status) + return nil, fmt.Errorf("Got HTTP status code >= 400: %s", resp.Status) } return resp, nil }