add differ support for local source

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
v0.9
Tonis Tiigi 2021-04-20 21:46:07 -07:00
parent 59d2f76e5e
commit baa4fcdb0f
8 changed files with 141 additions and 3 deletions

View File

@ -19,6 +19,7 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
"syscall"
"testing" "testing"
"time" "time"
@ -126,6 +127,7 @@ func TestIntegration(t *testing.T) {
testStargzLazyPull, testStargzLazyPull,
testFileOpInputSwap, testFileOpInputSwap,
testRelativeMountpoint, testRelativeMountpoint,
testLocalSourceDiffer,
}, mirrors) }, mirrors)
integration.Run(t, []integration.Test{ integration.Run(t, []integration.Test{
@ -1269,6 +1271,86 @@ func testFileOpInputSwap(t *testing.T, sb integration.Sandbox) {
require.Contains(t, err.Error(), "bar: no such file") require.Contains(t, err.Error(), "bar: no such file")
} }
func testLocalSourceDiffer(t *testing.T, sb integration.Sandbox) {
for _, d := range []llb.DiffType{llb.DiffNone, llb.DiffMetadata} {
t.Run(fmt.Sprintf("differ=%s", d), func(t *testing.T) {
testLocalSourceWithDiffer(t, sb, d)
})
}
}
func testLocalSourceWithDiffer(t *testing.T, sb integration.Sandbox, d llb.DiffType) {
requiresLinux(t)
c, err := New(context.TODO(), sb.Address())
require.NoError(t, err)
defer c.Close()
dir, err := tmpdir(
fstest.CreateFile("foo", []byte("foo"), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
tv := syscall.NsecToTimespec(time.Now().UnixNano())
err = syscall.UtimesNano(filepath.Join(dir, "foo"), []syscall.Timespec{tv, tv})
require.NoError(t, err)
st := llb.Local("mylocal"+string(d), llb.Differ(d, false))
def, err := st.Marshal(context.TODO())
require.NoError(t, err)
destDir, err := ioutil.TempDir("", "buildkit")
require.NoError(t, err)
defer os.RemoveAll(destDir)
_, err = c.Solve(context.TODO(), def, SolveOpt{
Exports: []ExportEntry{
{
Type: ExporterLocal,
OutputDir: destDir,
},
},
LocalDirs: map[string]string{
"mylocal" + string(d): dir,
},
}, nil)
require.NoError(t, err)
dt, err := ioutil.ReadFile(filepath.Join(destDir, "foo"))
require.NoError(t, err)
require.Equal(t, []byte("foo"), dt)
err = ioutil.WriteFile(filepath.Join(dir, "foo"), []byte("bar"), 0600)
require.NoError(t, err)
err = syscall.UtimesNano(filepath.Join(dir, "foo"), []syscall.Timespec{tv, tv})
require.NoError(t, err)
_, err = c.Solve(context.TODO(), def, SolveOpt{
Exports: []ExportEntry{
{
Type: ExporterLocal,
OutputDir: destDir,
},
},
LocalDirs: map[string]string{
"mylocal" + string(d): dir,
},
}, nil)
require.NoError(t, err)
dt, err = ioutil.ReadFile(filepath.Join(destDir, "foo"))
require.NoError(t, err)
if d == llb.DiffMetadata {
require.Equal(t, []byte("foo"), dt)
}
if d == llb.DiffNone {
require.Equal(t, []byte("bar"), dt)
}
}
func testFileOpRmWildcard(t *testing.T, sb integration.Sandbox) { func testFileOpRmWildcard(t *testing.T, sb integration.Sandbox) {
requiresLinux(t) requiresLinux(t)
c, err := New(context.TODO(), sb.Address()) c, err := New(context.TODO(), sb.Address())

View File

@ -361,6 +361,12 @@ func Local(name string, opts ...LocalOption) State {
attrs[pb.AttrSharedKeyHint] = gi.SharedKeyHint attrs[pb.AttrSharedKeyHint] = gi.SharedKeyHint
addCap(&gi.Constraints, pb.CapSourceLocalSharedKeyHint) addCap(&gi.Constraints, pb.CapSourceLocalSharedKeyHint)
} }
if gi.Differ.Type != "" {
attrs[pb.AttrLocalDiffer] = string(gi.Differ.Type)
if gi.Differ.Required {
addCap(&gi.Constraints, pb.CapSourceLocalDiffer)
}
}
addCap(&gi.Constraints, pb.CapSourceLocal) addCap(&gi.Constraints, pb.CapSourceLocal)
@ -423,6 +429,26 @@ func SharedKeyHint(h string) LocalOption {
}) })
} }
func Differ(t DiffType, required bool) LocalOption {
return localOptionFunc(func(li *LocalInfo) {
li.Differ = DifferInfo{
Type: t,
Required: required,
}
})
}
type DiffType string
const DiffNone DiffType = pb.AttrLocalDifferNone
const DiffMetadata DiffType = pb.AttrLocalDifferMetadata
const DiffContent DiffType = pb.AttrLocalDifferContent
type DifferInfo struct {
Type DiffType
Required bool
}
type LocalInfo struct { type LocalInfo struct {
constraintsWrapper constraintsWrapper
SessionID string SessionID string
@ -430,6 +456,7 @@ type LocalInfo struct {
ExcludePatterns string ExcludePatterns string
FollowPaths string FollowPaths string
SharedKeyHint string SharedKeyHint string
Differ DifferInfo
} }
func HTTP(url string, opts ...HTTPOption) State { func HTTP(url string, opts ...HTTPOption) State {

View File

@ -70,7 +70,7 @@ func (wc *streamWriterCloser) Close() error {
return nil return nil
} }
func recvDiffCopy(ds grpc.ClientStream, dest string, cu CacheUpdater, progress progressCb, filter func(string, *fstypes.Stat) bool) (err error) { func recvDiffCopy(ds grpc.ClientStream, dest string, cu CacheUpdater, progress progressCb, differ fsutil.DiffType, filter func(string, *fstypes.Stat) bool) (err error) {
st := time.Now() st := time.Now()
defer func() { defer func() {
logrus.Debugf("diffcopy took: %v", time.Since(st)) logrus.Debugf("diffcopy took: %v", time.Since(st))
@ -93,6 +93,7 @@ func recvDiffCopy(ds grpc.ClientStream, dest string, cu CacheUpdater, progress p
ContentHasher: ch, ContentHasher: ch,
ProgressCb: progress, ProgressCb: progress,
Filter: fsutil.FilterFunc(filter), Filter: fsutil.FilterFunc(filter),
Differ: differ,
})) }))
} }

View File

@ -24,6 +24,7 @@ const (
keyFollowPaths = "followpaths" keyFollowPaths = "followpaths"
keyDirName = "dir-name" keyDirName = "dir-name"
keyExporterMetaPrefix = "exporter-md-" keyExporterMetaPrefix = "exporter-md-"
keyDiffer = "differ"
) )
type fsSyncProvider struct { type fsSyncProvider struct {
@ -130,7 +131,7 @@ type progressCb func(int, bool)
type protocol struct { type protocol struct {
name string name string
sendFn func(stream Stream, fs fsutil.FS, progress progressCb) error sendFn func(stream Stream, fs fsutil.FS, progress progressCb) error
recvFn func(stream grpc.ClientStream, destDir string, cu CacheUpdater, progress progressCb, mapFunc func(string, *fstypes.Stat) bool) error recvFn func(stream grpc.ClientStream, destDir string, cu CacheUpdater, progress progressCb, differ fsutil.DiffType, mapFunc func(string, *fstypes.Stat) bool) error
} }
func isProtoSupported(p string) bool { func isProtoSupported(p string) bool {
@ -160,6 +161,7 @@ type FSSendRequestOpt struct {
CacheUpdater CacheUpdater CacheUpdater CacheUpdater
ProgressCb func(int, bool) ProgressCb func(int, bool)
Filter func(string, *fstypes.Stat) bool Filter func(string, *fstypes.Stat) bool
Differ fsutil.DiffType
} }
// CacheUpdater is an object capable of sending notifications for the cache hash changes // CacheUpdater is an object capable of sending notifications for the cache hash changes
@ -227,7 +229,7 @@ func FSSync(ctx context.Context, c session.Caller, opt FSSendRequestOpt) error {
panic(fmt.Sprintf("invalid protocol: %q", pr.name)) panic(fmt.Sprintf("invalid protocol: %q", pr.name))
} }
return pr.recvFn(stream, opt.DestDir, opt.CacheUpdater, opt.ProgressCb, opt.Filter) return pr.recvFn(stream, opt.DestDir, opt.CacheUpdater, opt.ProgressCb, opt.Differ, opt.Filter)
} }
// NewFSSyncTargetDir allows writing into a directory // NewFSSyncTargetDir allows writing into a directory

View File

@ -12,6 +12,7 @@ const AttrIncludePatterns = "local.includepattern"
const AttrFollowPaths = "local.followpaths" const AttrFollowPaths = "local.followpaths"
const AttrExcludePatterns = "local.excludepatterns" const AttrExcludePatterns = "local.excludepatterns"
const AttrSharedKeyHint = "local.sharedkeyhint" const AttrSharedKeyHint = "local.sharedkeyhint"
const AttrLLBDefinitionFilename = "llbbuild.filename" const AttrLLBDefinitionFilename = "llbbuild.filename"
const AttrHTTPChecksum = "http.checksum" const AttrHTTPChecksum = "http.checksum"
@ -26,4 +27,9 @@ const AttrImageResolveModeForcePull = "pull"
const AttrImageResolveModePreferLocal = "local" const AttrImageResolveModePreferLocal = "local"
const AttrImageRecordType = "image.recordtype" const AttrImageRecordType = "image.recordtype"
const AttrLocalDiffer = "local.differ"
const AttrLocalDifferNone = "none"
const AttrLocalDifferMetadata = "metadata"
const AttrLocalDifferContent = "content"
type IsFileAction = isFileAction_Action type IsFileAction = isFileAction_Action

View File

@ -18,6 +18,7 @@ const (
CapSourceLocalFollowPaths apicaps.CapID = "source.local.followpaths" CapSourceLocalFollowPaths apicaps.CapID = "source.local.followpaths"
CapSourceLocalExcludePatterns apicaps.CapID = "source.local.excludepatterns" CapSourceLocalExcludePatterns apicaps.CapID = "source.local.excludepatterns"
CapSourceLocalSharedKeyHint apicaps.CapID = "source.local.sharedkeyhint" CapSourceLocalSharedKeyHint apicaps.CapID = "source.local.sharedkeyhint"
CapSourceLocalDiffer apicaps.CapID = "source.local.differ"
CapSourceGit apicaps.CapID = "source.git" CapSourceGit apicaps.CapID = "source.git"
CapSourceGitKeepDir apicaps.CapID = "source.git.keepgitdir" CapSourceGitKeepDir apicaps.CapID = "source.git.keepgitdir"
@ -118,6 +119,13 @@ func init() {
Enabled: true, Enabled: true,
Status: apicaps.CapStatusExperimental, Status: apicaps.CapStatusExperimental,
}) })
Caps.Init(apicaps.Cap{
ID: CapSourceLocalDiffer,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{ Caps.Init(apicaps.Cap{
ID: CapSourceGit, ID: CapSourceGit,
Enabled: true, Enabled: true,

View File

@ -11,6 +11,7 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/tonistiigi/fsutil"
) )
var ( var (
@ -146,6 +147,15 @@ func FromLLB(op *pb.Op_Source, platform *pb.Platform) (Identifier, error) {
id.FollowPaths = paths id.FollowPaths = paths
case pb.AttrSharedKeyHint: case pb.AttrSharedKeyHint:
id.SharedKeyHint = v id.SharedKeyHint = v
case pb.AttrLocalDiffer:
switch v {
case pb.AttrLocalDifferMetadata, "":
id.Differ = fsutil.DiffMetadata
case pb.AttrLocalDifferNone:
id.Differ = fsutil.DiffNone
case pb.AttrLocalDifferContent:
id.Differ = fsutil.DiffContent
}
} }
} }
} }
@ -214,6 +224,7 @@ type LocalIdentifier struct {
ExcludePatterns []string ExcludePatterns []string
FollowPaths []string FollowPaths []string
SharedKeyHint string SharedKeyHint string
Differ fsutil.DiffType
} }
func NewLocalIdentifier(str string) (*LocalIdentifier, error) { func NewLocalIdentifier(str string) (*LocalIdentifier, error) {

View File

@ -178,6 +178,7 @@ func (ls *localSourceHandler) snapshot(ctx context.Context, s session.Group, cal
DestDir: dest, DestDir: dest,
CacheUpdater: &cacheUpdater{cc, mount.IdentityMapping()}, CacheUpdater: &cacheUpdater{cc, mount.IdentityMapping()},
ProgressCb: newProgressHandler(ctx, "transferring "+ls.src.Name+":"), ProgressCb: newProgressHandler(ctx, "transferring "+ls.src.Name+":"),
Differ: ls.src.Differ,
} }
if idmap := mount.IdentityMapping(); idmap != nil { if idmap := mount.IdentityMapping(); idmap != nil {