contenthash: include basename in content checksum for wildcards
While we generally ignore the basename in this layer, for wildcards there in no other place to add the basename to the checksum as they can not be resolved earlier. Before the basename that was in the checksum was the wildcard itself, so if the wildcard remained same, content remained same but the file where wildcard pointed to was renamed, the cache was not invalidated. Unfortunately, this change breaks cache for all copy commands that use a wildcard. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>v0.9
parent
8effd45b99
commit
1982e1e285
|
@ -406,17 +406,19 @@ func (cc *cacheContext) ChecksumWildcard(ctx context.Context, mountable cache.Mo
|
|||
return digest.FromBytes([]byte{}), nil
|
||||
}
|
||||
|
||||
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
|
||||
if len(wildcards) == 1 && path.Base(p) == path.Base(wildcards[0].Path) {
|
||||
return wildcards[0].Record.Digest, nil
|
||||
}
|
||||
return wildcards[0].Record.Digest, nil
|
||||
|
||||
digester := digest.Canonical.Digester()
|
||||
for i, w := range wildcards {
|
||||
if i != 0 {
|
||||
digester.Hash().Write([]byte{0})
|
||||
}
|
||||
digester.Hash().Write([]byte(path.Base(w.Path)))
|
||||
digester.Hash().Write([]byte(w.Record.Digest))
|
||||
}
|
||||
return digester.Digest(), nil
|
||||
}
|
||||
|
||||
func (cc *cacheContext) Checksum(ctx context.Context, mountable cache.Mountable, p string, followLinks bool, s session.Group) (digest.Digest, error) {
|
||||
|
|
|
@ -179,9 +179,9 @@ func TestChecksumWildcard(t *testing.T) {
|
|||
|
||||
dgst, err := cc.ChecksumWildcard(context.TODO(), ref, "f*o", false, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, dgstFileData0, dgst)
|
||||
require.Equal(t, digest.FromBytes(append([]byte("foo"), []byte(dgstFileData0)...)), dgst)
|
||||
|
||||
expFoos := digest.Digest("sha256:c9f914ad7ad8fe6092ce67484b43ca39c2087aabf9e4a1b223249b0f8b09b9f2")
|
||||
expFoos := digest.Digest("sha256:7f51c821895cfc116d3f64231dfb438e87a237ecbbe027cd96b7ee5e763cc569")
|
||||
|
||||
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "f*", false, nil)
|
||||
require.NoError(t, err)
|
||||
|
@ -189,15 +189,17 @@ func TestChecksumWildcard(t *testing.T) {
|
|||
|
||||
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "x/d?", false, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, dgstDirD0, dgst)
|
||||
require.Equal(t, digest.FromBytes(append([]byte("d0"), []byte(dgstDirD0)...)), dgst)
|
||||
|
||||
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "x/d?/def", true, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, dgstFileData0, dgst)
|
||||
|
||||
expFoos2 := digest.Digest("sha256:8afc09c7018d65d5eb318a9ef55cb704dec1f06d288181d913fc27a571aa042d")
|
||||
|
||||
dgst, err = cc.ChecksumWildcard(context.TODO(), ref, "y*", true, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expFoos, dgst)
|
||||
require.Equal(t, expFoos2, dgst)
|
||||
|
||||
err = ref.Release(context.TODO())
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -109,6 +109,7 @@ var allTests = []integration.Test{
|
|||
testDefaultShellAndPath,
|
||||
testDockerfileLowercase,
|
||||
testExportCacheLoop,
|
||||
testWildcardRenameCache,
|
||||
}
|
||||
|
||||
var fileOpTests = []integration.Test{
|
||||
|
@ -3832,6 +3833,52 @@ LABEL foo=bar
|
|||
require.Equal(t, "baz", v)
|
||||
}
|
||||
|
||||
// #2008
|
||||
func testWildcardRenameCache(t *testing.T, sb integration.Sandbox) {
|
||||
skipDockerd(t, sb)
|
||||
f := getFrontend(t, sb)
|
||||
|
||||
dockerfile := []byte(`
|
||||
FROM alpine
|
||||
COPY file* /files/
|
||||
RUN ls /files/file1
|
||||
`)
|
||||
dir, err := tmpdir(
|
||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
||||
fstest.CreateFile("file1", []byte("foo"), 0600),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
c, err := client.New(context.TODO(), sb.Address())
|
||||
require.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
destDir, err := ioutil.TempDir("", "buildkit")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(destDir)
|
||||
|
||||
_, err = f.Solve(context.TODO(), c, client.SolveOpt{
|
||||
LocalDirs: map[string]string{
|
||||
builder.DefaultLocalNameDockerfile: dir,
|
||||
builder.DefaultLocalNameContext: dir,
|
||||
},
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = os.Rename(filepath.Join(dir, "file1"), filepath.Join(dir, "file2"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// cache should be invalidated and build should fail
|
||||
_, err = f.Solve(context.TODO(), c, client.SolveOpt{
|
||||
LocalDirs: map[string]string{
|
||||
builder.DefaultLocalNameDockerfile: dir,
|
||||
builder.DefaultLocalNameContext: dir,
|
||||
},
|
||||
}, nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func testOnBuildCleared(t *testing.T, sb integration.Sandbox) {
|
||||
f := getFrontend(t, sb)
|
||||
|
||||
|
|
Loading…
Reference in New Issue