Merge pull request #850 from tonistiigi/contenthash-wildcards

contenthash: add wildcard and nofollow support
docker-19.03
Akihiro Suda 2019-03-03 20:12:03 +09:00 committed by GitHub
commit e814100f45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 291 additions and 56 deletions

View File

@ -43,8 +43,8 @@ func getDefaultManager() *cacheManager {
// header, "/dir" is for contents. For the root node "" (empty string) is the // header, "/dir" is for contents. For the root node "" (empty string) is the
// key for root, "/" for the root header // key for root, "/" for the root header
func Checksum(ctx context.Context, ref cache.ImmutableRef, path string) (digest.Digest, error) { func Checksum(ctx context.Context, ref cache.ImmutableRef, path string, followLinks bool) (digest.Digest, error) {
return getDefaultManager().Checksum(ctx, ref, path) return getDefaultManager().Checksum(ctx, ref, path, followLinks)
} }
func GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) { func GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) {
@ -56,7 +56,8 @@ func SetCacheContext(ctx context.Context, md *metadata.StorageItem, cc CacheCont
} }
type CacheContext interface { type CacheContext interface {
Checksum(ctx context.Context, ref cache.Mountable, p string) (digest.Digest, error) Checksum(ctx context.Context, ref cache.Mountable, p string, followLinks bool) (digest.Digest, error)
ChecksumWildcard(ctx context.Context, ref cache.Mountable, p string, followLinks bool) (digest.Digest, error)
HandleChange(kind fsutil.ChangeKind, p string, fi os.FileInfo, err error) error HandleChange(kind fsutil.ChangeKind, p string, fi os.FileInfo, err error) error
} }
@ -64,18 +65,23 @@ type Hashed interface {
Digest() digest.Digest Digest() digest.Digest
} }
type Wildcard struct {
Path string
Record *CacheRecord
}
type cacheManager struct { type cacheManager struct {
locker *locker.Locker locker *locker.Locker
lru *simplelru.LRU lru *simplelru.LRU
lruMu sync.Mutex lruMu sync.Mutex
} }
func (cm *cacheManager) Checksum(ctx context.Context, ref cache.ImmutableRef, p string) (digest.Digest, error) { func (cm *cacheManager) Checksum(ctx context.Context, ref cache.ImmutableRef, p string, followLinks bool) (digest.Digest, error) {
cc, err := cm.GetCacheContext(ctx, ensureOriginMetadata(ref.Metadata())) cc, err := cm.GetCacheContext(ctx, ensureOriginMetadata(ref.Metadata()))
if err != nil { if err != nil {
return "", nil return "", nil
} }
return cc.Checksum(ctx, ref, p) return cc.Checksum(ctx, ref, p, followLinks)
} }
func (cm *cacheManager) GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) { func (cm *cacheManager) GetCacheContext(ctx context.Context, md *metadata.StorageItem) (CacheContext, error) {
@ -317,10 +323,49 @@ func (cc *cacheContext) HandleChange(kind fsutil.ChangeKind, p string, fi os.Fil
return nil return nil
} }
func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable, p string) (digest.Digest, error) { func (cc *cacheContext) ChecksumWildcard(ctx context.Context, mountable cache.Mountable, p string, followLinks bool) (digest.Digest, error) {
m := &mount{mountable: mountable} m := &mount{mountable: mountable}
defer m.clean() defer m.clean()
wildcards, err := cc.wildcards(ctx, m, p)
if err != nil {
return "", nil
}
if followLinks {
for i, w := range wildcards {
if w.Record.Type == CacheRecordTypeSymlink {
dgst, err := cc.checksumFollow(ctx, m, w.Path, followLinks)
if err != nil {
return "", err
}
wildcards[i].Record = &CacheRecord{Digest: dgst}
}
}
}
if len(wildcards) > 1 {
digester := digest.Canonical.Digester()
for i, w := range wildcards {
if i != 0 {
digester.Hash().Write([]byte{0})
}
digester.Hash().Write([]byte(w.Record.Digest))
}
return digester.Digest(), nil
} else {
return wildcards[0].Record.Digest, nil
}
}
func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable, p string, followLinks bool) (digest.Digest, error) {
m := &mount{mountable: mountable}
defer m.clean()
return cc.checksumFollow(ctx, m, p, followLinks)
}
func (cc *cacheContext) checksumFollow(ctx context.Context, m *mount, p string, follow bool) (digest.Digest, error) {
const maxSymlinkLimit = 255 const maxSymlinkLimit = 255
i := 0 i := 0
for { for {
@ -331,7 +376,7 @@ func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable,
if err != nil { if err != nil {
return "", err return "", err
} }
if cr.Type == CacheRecordTypeSymlink { if cr.Type == CacheRecordTypeSymlink && follow {
link := cr.Linkname link := cr.Linkname
if !path.IsAbs(cr.Linkname) { if !path.IsAbs(cr.Linkname) {
link = path.Join(path.Dir(p), link) link = path.Join(path.Dir(p), link)
@ -344,6 +389,82 @@ func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable,
} }
} }
func (cc *cacheContext) wildcards(ctx context.Context, m *mount, p string) ([]*Wildcard, error) {
cc.mu.Lock()
defer cc.mu.Unlock()
if cc.txn != nil {
cc.commitActiveTransaction()
}
root := cc.tree.Root()
scan, err := cc.needsScan(root, "")
if err != nil {
return nil, err
}
if scan {
if err := cc.scanPath(ctx, m, ""); err != nil {
return nil, err
}
}
defer func() {
if cc.dirty {
go cc.save()
cc.dirty = false
}
}()
p = path.Join("/", filepath.ToSlash(p))
if p == "/" {
p = ""
}
wildcards := make([]*Wildcard, 0, 2)
txn := cc.tree.Txn()
root = txn.Root()
var updated bool
iter := root.Seek([]byte{})
for {
k, _, ok := iter.Next()
if !ok {
break
}
if len(k) > 0 && k[len(k)-1] == byte(0) {
continue
}
fn := convertKeyToPath(k)
b, err := path.Match(p, string(fn))
if err != nil {
return nil, err
}
if !b {
continue
}
cr, upt, err := cc.checksum(ctx, root, txn, m, k, false)
if err != nil {
return nil, err
}
if upt {
updated = true
}
wildcards = append(wildcards, &Wildcard{Path: string(fn), Record: cr})
if cr.Type == CacheRecordTypeDir {
iter = root.Seek(append(k, 0, 0xff))
}
}
cc.tree = txn.Commit()
cc.dirty = updated
return wildcards, nil
}
func (cc *cacheContext) checksumNoFollow(ctx context.Context, m *mount, p string) (*CacheRecord, error) { func (cc *cacheContext) checksumNoFollow(ctx context.Context, m *mount, p string) (*CacheRecord, error) {
p = path.Join("/", filepath.ToSlash(p)) p = path.Join("/", filepath.ToSlash(p))
if p == "/" { if p == "/" {
@ -412,7 +533,7 @@ func (cc *cacheContext) lazyChecksum(ctx context.Context, m *mount, p string) (*
k := convertPathToKey([]byte(p)) k := convertPathToKey([]byte(p))
txn := cc.tree.Txn() txn := cc.tree.Txn()
root = txn.Root() root = txn.Root()
cr, updated, err := cc.checksum(ctx, root, txn, m, k) cr, updated, err := cc.checksum(ctx, root, txn, m, k, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -421,8 +542,8 @@ func (cc *cacheContext) lazyChecksum(ctx context.Context, m *mount, p string) (*
return cr, err return cr, err
} }
func (cc *cacheContext) checksum(ctx context.Context, root *iradix.Node, txn *iradix.Txn, m *mount, k []byte) (*CacheRecord, bool, error) { func (cc *cacheContext) checksum(ctx context.Context, root *iradix.Node, txn *iradix.Txn, m *mount, k []byte, follow bool) (*CacheRecord, bool, error) {
k, cr, err := getFollowLinks(root, k) k, cr, err := getFollowLinks(root, k, follow)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
@ -447,7 +568,7 @@ func (cc *cacheContext) checksum(ctx context.Context, root *iradix.Node, txn *ir
} }
h.Write(bytes.TrimPrefix(subk, k)) h.Write(bytes.TrimPrefix(subk, k))
subcr, _, err := cc.checksum(ctx, root, txn, m, subk) subcr, _, err := cc.checksum(ctx, root, txn, m, subk, true)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
@ -599,23 +720,23 @@ func (cc *cacheContext) scanPath(ctx context.Context, m *mount, p string) (retEr
return nil return nil
} }
func getFollowLinks(root *iradix.Node, k []byte) ([]byte, *CacheRecord, error) { func getFollowLinks(root *iradix.Node, k []byte, follow bool) ([]byte, *CacheRecord, error) {
var linksWalked int var linksWalked int
return getFollowLinksWalk(root, k, &linksWalked) return getFollowLinksWalk(root, k, follow, &linksWalked)
} }
func getFollowLinksWalk(root *iradix.Node, k []byte, linksWalked *int) ([]byte, *CacheRecord, error) { func getFollowLinksWalk(root *iradix.Node, k []byte, follow bool, linksWalked *int) ([]byte, *CacheRecord, error) {
v, ok := root.Get(k) v, ok := root.Get(k)
if ok { if ok {
return k, v.(*CacheRecord), nil return k, v.(*CacheRecord), nil
} }
if len(k) == 0 { if !follow || len(k) == 0 {
return nil, nil, nil return nil, nil, nil
} }
dir, file := splitKey(k) dir, file := splitKey(k)
_, parent, err := getFollowLinksWalk(root, dir, linksWalked) _, parent, err := getFollowLinksWalk(root, dir, follow, linksWalked)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -632,7 +753,7 @@ func getFollowLinksWalk(root *iradix.Node, k []byte, linksWalked *int) ([]byte,
if !path.IsAbs(link) { if !path.IsAbs(link) {
link = path.Join("/", path.Join(path.Dir(dirPath), link)) link = path.Join("/", path.Join(path.Dir(dirPath), link))
} }
return getFollowLinksWalk(root, append(convertPathToKey([]byte(link)), file...), linksWalked) return getFollowLinksWalk(root, append(convertPathToKey([]byte(link)), file...), follow, linksWalked)
} }
return nil, nil, nil return nil, nil, nil

View File

@ -29,6 +29,120 @@ const (
dgstDirD0Modified = digest.Digest("sha256:555ffa3028630d97ba37832b749eda85ab676fd64ffb629fbf0f4ec8c1e3bff1") dgstDirD0Modified = digest.Digest("sha256:555ffa3028630d97ba37832b749eda85ab676fd64ffb629fbf0f4ec8c1e3bff1")
) )
func TestChecksumWildcard(t *testing.T) {
t.Parallel()
tmpdir, err := ioutil.TempDir("", "buildkit-state")
require.NoError(t, err)
defer os.RemoveAll(tmpdir)
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
require.NoError(t, err)
cm := setupCacheManager(t, tmpdir, snapshotter)
defer cm.Close()
ch := []string{
"ADD bar file data1",
"ADD foo file data0",
"ADD fox file data2",
"ADD x dir",
"ADD x/d0 dir",
"ADD x/d0/abc file data0",
"ADD x/d0/def symlink abc",
"ADD x/d0/ghi symlink nosuchfile",
"ADD y1 symlink foo",
"ADD y2 symlink fox",
}
ref := createRef(t, cm, ch)
cc, err := newCacheContext(ref.Metadata())
require.NoError(t, err)
dgst, err := cc.ChecksumWildcard(context.TODO(), ref, "f*o", false)
require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst)
expFoos := digest.Digest("sha256:c9f914ad7ad8fe6092ce67484b43ca39c2087aabf9e4a1b223249b0f8b09b9f2")
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "f*", false)
require.NoError(t, err)
require.Equal(t, expFoos, dgst)
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "x/d?", false)
require.NoError(t, err)
require.Equal(t, dgstDirD0, dgst)
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "x/d?/def", true)
require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst)
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "y*", true)
require.NoError(t, err)
require.Equal(t, expFoos, dgst)
err = ref.Release(context.TODO())
require.NoError(t, err)
}
func TestSymlinksNoFollow(t *testing.T) {
t.Parallel()
tmpdir, err := ioutil.TempDir("", "buildkit-state")
require.NoError(t, err)
defer os.RemoveAll(tmpdir)
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
require.NoError(t, err)
cm := setupCacheManager(t, tmpdir, snapshotter)
defer cm.Close()
ch := []string{
"ADD target file data0",
"ADD sym symlink target",
"ADD sym2 symlink target2",
"ADD foo dir",
"ADD foo/ghi symlink target",
"ADD y1 symlink foo/ghi",
}
ref := createRef(t, cm, ch)
cc, err := newCacheContext(ref.Metadata())
require.NoError(t, err)
expectedSym := digest.Digest("sha256:a2ba571981f48ec34eb79c9a3ab091b6491e825c2f7e9914ea86e8e958be7fae")
dgst, err := cc.ChecksumWildcard(context.TODO(), ref, "sym", false)
require.NoError(t, err)
require.Equal(t, expectedSym, dgst)
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "sym2", false)
require.NoError(t, err)
require.NotEqual(t, expectedSym, dgst)
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "foo/ghi", false)
require.NoError(t, err)
require.Equal(t, expectedSym, dgst)
_, err = cc.ChecksumWildcard(context.TODO(), ref, "foo/ghi", true) // same because broken symlink
require.Error(t, err)
require.Equal(t, errNotFound, errors.Cause(err))
_, err = cc.ChecksumWildcard(context.TODO(), ref, "y1", true)
require.Error(t, err)
require.Equal(t, errNotFound, errors.Cause(err))
dgst, err = cc.Checksum(context.TODO(), ref, "sym", false)
require.NoError(t, err)
require.Equal(t, expectedSym, dgst)
dgst, err = cc.Checksum(context.TODO(), ref, "foo/ghi", false)
require.NoError(t, err)
require.Equal(t, expectedSym, dgst)
err = ref.Release(context.TODO())
require.NoError(t, err)
}
func TestChecksumBasicFile(t *testing.T) { func TestChecksumBasicFile(t *testing.T) {
t.Parallel() t.Parallel()
tmpdir, err := ioutil.TempDir("", "buildkit-state") tmpdir, err := ioutil.TempDir("", "buildkit-state")
@ -57,48 +171,48 @@ func TestChecksumBasicFile(t *testing.T) {
cc, err := newCacheContext(ref.Metadata()) cc, err := newCacheContext(ref.Metadata())
require.NoError(t, err) require.NoError(t, err)
_, err = cc.Checksum(context.TODO(), ref, "nosuch") _, err = cc.Checksum(context.TODO(), ref, "nosuch", true)
require.Error(t, err) require.Error(t, err)
dgst, err := cc.Checksum(context.TODO(), ref, "foo") dgst, err := cc.Checksum(context.TODO(), ref, "foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
// second file returns different hash // second file returns different hash
dgst, err = cc.Checksum(context.TODO(), ref, "bar") dgst, err = cc.Checksum(context.TODO(), ref, "bar", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, digest.Digest("sha256:c2b5e234f5f38fc5864da7def04782f82501a40d46192e4207d5b3f0c3c4732b"), dgst) require.Equal(t, digest.Digest("sha256:c2b5e234f5f38fc5864da7def04782f82501a40d46192e4207d5b3f0c3c4732b"), dgst)
// same file inside a directory // same file inside a directory
dgst, err = cc.Checksum(context.TODO(), ref, "d0/abc") dgst, err = cc.Checksum(context.TODO(), ref, "d0/abc", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
// repeat because codepath is different // repeat because codepath is different
dgst, err = cc.Checksum(context.TODO(), ref, "d0/abc") dgst, err = cc.Checksum(context.TODO(), ref, "d0/abc", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
// symlink to the same file is followed, returns same hash // symlink to the same file is followed, returns same hash
dgst, err = cc.Checksum(context.TODO(), ref, "d0/def") dgst, err = cc.Checksum(context.TODO(), ref, "d0/def", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
_, err = cc.Checksum(context.TODO(), ref, "d0/ghi") _, err = cc.Checksum(context.TODO(), ref, "d0/ghi", true)
require.Error(t, err) require.Error(t, err)
require.Equal(t, errNotFound, errors.Cause(err)) require.Equal(t, errNotFound, errors.Cause(err))
dgst, err = cc.Checksum(context.TODO(), ref, "/") dgst, err = cc.Checksum(context.TODO(), ref, "/", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, digest.Digest("sha256:427c9cf9ae98c0f81fb57a3076b965c7c149b6b0a85625ad4e884236649a42c6"), dgst) require.Equal(t, digest.Digest("sha256:427c9cf9ae98c0f81fb57a3076b965c7c149b6b0a85625ad4e884236649a42c6"), dgst)
dgst, err = cc.Checksum(context.TODO(), ref, "d0") dgst, err = cc.Checksum(context.TODO(), ref, "d0", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstDirD0, dgst) require.Equal(t, dgstDirD0, dgst)
@ -118,7 +232,7 @@ func TestChecksumBasicFile(t *testing.T) {
cc, err = newCacheContext(ref.Metadata()) cc, err = newCacheContext(ref.Metadata())
require.NoError(t, err) require.NoError(t, err)
dgst, err = cc.Checksum(context.TODO(), ref, "/") dgst, err = cc.Checksum(context.TODO(), ref, "/", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstDirD0, dgst) require.Equal(t, dgstDirD0, dgst)
@ -137,7 +251,7 @@ func TestChecksumBasicFile(t *testing.T) {
cc, err = newCacheContext(ref.Metadata()) cc, err = newCacheContext(ref.Metadata())
require.NoError(t, err) require.NoError(t, err)
dgst, err = cc.Checksum(context.TODO(), ref, "/") dgst, err = cc.Checksum(context.TODO(), ref, "/", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstDirD0Modified, dgst) require.Equal(t, dgstDirD0Modified, dgst)
@ -163,14 +277,14 @@ func TestChecksumBasicFile(t *testing.T) {
cc, err = newCacheContext(ref.Metadata()) cc, err = newCacheContext(ref.Metadata())
require.NoError(t, err) require.NoError(t, err)
dgst, err = cc.Checksum(context.TODO(), ref, "abc/aa/foo") dgst, err = cc.Checksum(context.TODO(), ref, "abc/aa/foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, digest.Digest("sha256:1c67653c3cf95b12a0014e2c4cd1d776b474b3218aee54155d6ae27b9b999c54"), dgst) require.Equal(t, digest.Digest("sha256:1c67653c3cf95b12a0014e2c4cd1d776b474b3218aee54155d6ae27b9b999c54"), dgst)
require.NotEqual(t, dgstDirD0, dgst) require.NotEqual(t, dgstDirD0, dgst)
// this will force rescan // this will force rescan
dgst, err = cc.Checksum(context.TODO(), ref, "d0") dgst, err = cc.Checksum(context.TODO(), ref, "d0", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstDirD0, dgst) require.Equal(t, dgstDirD0, dgst)
@ -210,19 +324,19 @@ func TestHandleChange(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
dgstFoo, err := cc.Checksum(context.TODO(), ref, "foo") dgstFoo, err := cc.Checksum(context.TODO(), ref, "foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgstFoo) require.Equal(t, dgstFileData0, dgstFoo)
// symlink to the same file is followed, returns same hash // symlink to the same file is followed, returns same hash
dgst, err := cc.Checksum(context.TODO(), ref, "d0/def") dgst, err := cc.Checksum(context.TODO(), ref, "d0/def", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFoo, dgst) require.Equal(t, dgstFoo, dgst)
// symlink to the same file is followed, returns same hash // symlink to the same file is followed, returns same hash
dgst, err = cc.Checksum(context.TODO(), ref, "d0") dgst, err = cc.Checksum(context.TODO(), ref, "d0", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstDirD0, dgst) require.Equal(t, dgstDirD0, dgst)
@ -234,7 +348,7 @@ func TestHandleChange(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
dgst, err = cc.Checksum(context.TODO(), ref, "d0") dgst, err = cc.Checksum(context.TODO(), ref, "d0", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstDirD0Modified, dgst) require.Equal(t, dgstDirD0Modified, dgst)
@ -245,11 +359,11 @@ func TestHandleChange(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
_, err = cc.Checksum(context.TODO(), ref, "d0") _, err = cc.Checksum(context.TODO(), ref, "d0", true)
require.Error(t, err) require.Error(t, err)
require.Equal(t, errNotFound, errors.Cause(err)) require.Equal(t, errNotFound, errors.Cause(err))
_, err = cc.Checksum(context.TODO(), ref, "d0/abc") _, err = cc.Checksum(context.TODO(), ref, "d0/abc", true)
require.Error(t, err) require.Error(t, err)
require.Equal(t, errNotFound, errors.Cause(err)) require.Equal(t, errNotFound, errors.Cause(err))
@ -286,7 +400,7 @@ func TestHandleRecursiveDir(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
dgst, err := cc.Checksum(context.TODO(), ref, "d0/foo/bar") dgst, err := cc.Checksum(context.TODO(), ref, "d0/foo/bar", true)
require.NoError(t, err) require.NoError(t, err)
ch = []string{ ch = []string{
@ -298,11 +412,11 @@ func TestHandleRecursiveDir(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
dgst2, err := cc.Checksum(context.TODO(), ref, "d1") dgst2, err := cc.Checksum(context.TODO(), ref, "d1", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgst2, dgst) require.Equal(t, dgst2, dgst)
_, err = cc.Checksum(context.TODO(), ref, "") _, err = cc.Checksum(context.TODO(), ref, "", true)
require.NoError(t, err) require.NoError(t, err)
} }
@ -333,7 +447,7 @@ func TestChecksumUnorderedFiles(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
dgst, err := cc.Checksum(context.TODO(), ref, "d0") dgst, err := cc.Checksum(context.TODO(), ref, "d0", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgst, digest.Digest("sha256:14276c302c940a80f82ca5477bf766c98a24702d6a9948ee71bb277cdad3ae05")) require.Equal(t, dgst, digest.Digest("sha256:14276c302c940a80f82ca5477bf766c98a24702d6a9948ee71bb277cdad3ae05"))
@ -353,7 +467,7 @@ func TestChecksumUnorderedFiles(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
dgst2, err := cc.Checksum(context.TODO(), ref, "d0") dgst2, err := cc.Checksum(context.TODO(), ref, "d0", true)
require.NoError(t, err) require.NoError(t, err)
require.NotEqual(t, dgst, dgst2) require.NotEqual(t, dgst, dgst2)
@ -378,11 +492,11 @@ func TestSymlinkInPathScan(t *testing.T) {
} }
ref := createRef(t, cm, ch) ref := createRef(t, cm, ch)
dgst, err := Checksum(context.TODO(), ref, "d0/def/foo") dgst, err := Checksum(context.TODO(), ref, "d0/def/foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
dgst, err = Checksum(context.TODO(), ref, "d0/def/foo") dgst, err = Checksum(context.TODO(), ref, "d0/def/foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
@ -412,10 +526,10 @@ func TestSymlinkNeedsScan(t *testing.T) {
ref := createRef(t, cm, ch) ref := createRef(t, cm, ch)
// scan the d0 path containing the symlink that doesn't get followed // scan the d0 path containing the symlink that doesn't get followed
_, err = Checksum(context.TODO(), ref, "d0/d1") _, err = Checksum(context.TODO(), ref, "d0/d1", true)
require.NoError(t, err) require.NoError(t, err)
dgst, err := Checksum(context.TODO(), ref, "d0/d1/def/foo") dgst, err := Checksum(context.TODO(), ref, "d0/d1/def/foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
@ -442,7 +556,7 @@ func TestSymlinkAbsDirSuffix(t *testing.T) {
} }
ref := createRef(t, cm, ch) ref := createRef(t, cm, ch)
dgst, err := Checksum(context.TODO(), ref, "link/foo") dgst, err := Checksum(context.TODO(), ref, "link/foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
@ -485,27 +599,27 @@ func TestSymlinkInPathHandleChange(t *testing.T) {
err = emit(cc.HandleChange, changeStream(ch)) err = emit(cc.HandleChange, changeStream(ch))
require.NoError(t, err) require.NoError(t, err)
dgst, err := cc.Checksum(context.TODO(), ref, "d1/def/foo") dgst, err := cc.Checksum(context.TODO(), ref, "d1/def/foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
dgst, err = cc.Checksum(context.TODO(), ref, "d1/def/bar/abc") dgst, err = cc.Checksum(context.TODO(), ref, "d1/def/bar/abc", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
dgstFileData0, err := cc.Checksum(context.TODO(), ref, "sub/d0") dgstFileData0, err := cc.Checksum(context.TODO(), ref, "sub/d0", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgstDirD0) require.Equal(t, dgstFileData0, dgstDirD0)
dgstFileData0, err = cc.Checksum(context.TODO(), ref, "d1/def/baz") dgstFileData0, err = cc.Checksum(context.TODO(), ref, "d1/def/baz", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgstDirD0) require.Equal(t, dgstFileData0, dgstDirD0)
dgstFileData0, err = cc.Checksum(context.TODO(), ref, "d1/def/bay") dgstFileData0, err = cc.Checksum(context.TODO(), ref, "d1/def/bay", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgstDirD0) require.Equal(t, dgstFileData0, dgstDirD0)
dgstFileData0, err = cc.Checksum(context.TODO(), ref, "link") dgstFileData0, err = cc.Checksum(context.TODO(), ref, "link", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgstDirD0) require.Equal(t, dgstFileData0, dgstDirD0)
@ -536,7 +650,7 @@ func TestPersistence(t *testing.T) {
ref := createRef(t, cm, ch) ref := createRef(t, cm, ch)
id := ref.ID() id := ref.ID()
dgst, err := Checksum(context.TODO(), ref, "foo") dgst, err := Checksum(context.TODO(), ref, "foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
@ -546,7 +660,7 @@ func TestPersistence(t *testing.T) {
ref, err = cm.Get(context.TODO(), id) ref, err = cm.Get(context.TODO(), id)
require.NoError(t, err) require.NoError(t, err)
dgst, err = Checksum(context.TODO(), ref, "foo") dgst, err = Checksum(context.TODO(), ref, "foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
@ -564,7 +678,7 @@ func TestPersistence(t *testing.T) {
ref, err = cm.Get(context.TODO(), id) ref, err = cm.Get(context.TODO(), id)
require.NoError(t, err) require.NoError(t, err)
dgst, err = Checksum(context.TODO(), ref, "foo") dgst, err = Checksum(context.TODO(), ref, "foo", true)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dgstFileData0, dgst) require.Equal(t, dgstFileData0, dgst)
} }

View File

@ -32,7 +32,7 @@ func NewContentHashFunc(selectors []string) solver.ResultBasedCacheFunc {
// FIXME(tonistiigi): enabling this parallelization seems to create wrong results for some big inputs(like gobuild) // FIXME(tonistiigi): enabling this parallelization seems to create wrong results for some big inputs(like gobuild)
// func(i int) { // func(i int) {
// eg.Go(func() error { // eg.Go(func() error {
dgst, err := contenthash.Checksum(ctx, ref.ImmutableRef, path.Join("/", sel)) dgst, err := contenthash.Checksum(ctx, ref.ImmutableRef, path.Join("/", sel), true)
if err != nil { if err != nil {
return "", err return "", err
} }