Merge pull request #850 from tonistiigi/contenthash-wildcards
contenthash: add wildcard and nofollow supportdocker-19.03
commit
e814100f45
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue