local: allow followpaths for local source
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>docker-18.09
parent
103cd072d6
commit
055dcb6c09
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
"github.com/containerd/continuity/fs/fstest"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/moby/buildkit/client/llb"
|
||||
"github.com/moby/buildkit/identity"
|
||||
|
@ -50,9 +51,64 @@ func TestClientIntegration(t *testing.T) {
|
|||
testBasicCacheImportExport,
|
||||
testCachedMounts,
|
||||
testProxyEnv,
|
||||
testLocalSymlinkEscape,
|
||||
})
|
||||
}
|
||||
|
||||
func testLocalSymlinkEscape(t *testing.T, sb integration.Sandbox) {
|
||||
t.Parallel()
|
||||
requiresLinux(t)
|
||||
c, err := New(sb.Address())
|
||||
require.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
test := []byte(`set -x
|
||||
[[ -L /mount/foo ]]
|
||||
[[ -L /mount/sub/bar ]]
|
||||
[[ -L /mount/bax ]]
|
||||
[[ -f /mount/bay ]]
|
||||
[[ ! -f /mount/baz ]]
|
||||
[[ ! -f /mount/etc/passwd ]]
|
||||
[[ ! -f /mount/etc/group ]]
|
||||
[[ $(readlink /mount/foo) == "/etc/passwd" ]]
|
||||
[[ $(readlink /mount/sub/bar) == "../../../etc/group" ]]
|
||||
`)
|
||||
|
||||
dir, err := tmpdir(
|
||||
// point to absolute path that is not part of dir
|
||||
fstest.Symlink("/etc/passwd", "foo"),
|
||||
fstest.CreateDir("sub", 0700),
|
||||
// point outside of the dir
|
||||
fstest.Symlink("../../../etc/group", "sub/bar"),
|
||||
// regular valid symlink
|
||||
fstest.Symlink("bay", "bax"),
|
||||
// target for symlink (not requested)
|
||||
fstest.CreateFile("bay", []byte{}, 0600),
|
||||
// unused file that shouldn't be included
|
||||
fstest.CreateFile("baz", []byte{}, 0600),
|
||||
fstest.CreateFile("test.sh", test, 0700),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
local := llb.Local("mylocal", llb.FollowPaths([]string{
|
||||
"test.sh", "foo", "sub/bar", "bax",
|
||||
}))
|
||||
|
||||
st := llb.Image("busybox:latest").
|
||||
Run(llb.Shlex(`sh /mount/test.sh`), llb.AddMount("/mount", local, llb.Readonly))
|
||||
|
||||
def, err := st.Marshal()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = c.Solve(context.TODO(), def, SolveOpt{
|
||||
LocalDirs: map[string]string{
|
||||
"mylocal": dir,
|
||||
},
|
||||
}, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func testRelativeWorkDir(t *testing.T, sb integration.Sandbox) {
|
||||
t.Parallel()
|
||||
requiresLinux(t)
|
||||
|
@ -1182,3 +1238,14 @@ func testInvalidExporter(t *testing.T, sb integration.Sandbox) {
|
|||
|
||||
checkAllReleasable(t, c, sb, true)
|
||||
}
|
||||
|
||||
func tmpdir(appliers ...fstest.Applier) (string, error) {
|
||||
tmpdir, err := ioutil.TempDir("", "buildkit-client")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := fstest.Apply(appliers...).Apply(tmpdir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tmpdir, nil
|
||||
}
|
||||
|
|
|
@ -210,6 +210,9 @@ func Local(name string, opts ...LocalOption) State {
|
|||
if gi.IncludePatterns != "" {
|
||||
attrs[pb.AttrIncludePatterns] = gi.IncludePatterns
|
||||
}
|
||||
if gi.FollowPaths != "" {
|
||||
attrs[pb.AttrFollowPaths] = gi.FollowPaths
|
||||
}
|
||||
if gi.ExcludePatterns != "" {
|
||||
attrs[pb.AttrExcludePatterns] = gi.ExcludePatterns
|
||||
}
|
||||
|
@ -248,6 +251,17 @@ func IncludePatterns(p []string) LocalOption {
|
|||
})
|
||||
}
|
||||
|
||||
func FollowPaths(p []string) LocalOption {
|
||||
return localOptionFunc(func(li *LocalInfo) {
|
||||
if len(p) == 0 {
|
||||
li.FollowPaths = ""
|
||||
return
|
||||
}
|
||||
dt, _ := json.Marshal(p) // empty on error
|
||||
li.FollowPaths = string(dt)
|
||||
})
|
||||
}
|
||||
|
||||
func ExcludePatterns(p []string) LocalOption {
|
||||
return localOptionFunc(func(li *LocalInfo) {
|
||||
if len(p) == 0 {
|
||||
|
@ -270,6 +284,7 @@ type LocalInfo struct {
|
|||
SessionID string
|
||||
IncludePatterns string
|
||||
ExcludePatterns string
|
||||
FollowPaths string
|
||||
SharedKeyHint string
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,11 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func sendDiffCopy(stream grpc.Stream, dir string, includes, excludes []string, progress progressCb, _map func(*fsutil.Stat) bool) error {
|
||||
func sendDiffCopy(stream grpc.Stream, dir string, includes, excludes, followPaths []string, progress progressCb, _map func(*fsutil.Stat) bool) error {
|
||||
return fsutil.Send(stream.Context(), stream, dir, &fsutil.WalkOpt{
|
||||
ExcludePatterns: excludes,
|
||||
IncludePatterns: includes,
|
||||
FollowPaths: followPaths,
|
||||
Map: _map,
|
||||
}, progress)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ const (
|
|||
keyOverrideExcludes = "override-excludes"
|
||||
keyIncludePatterns = "include-patterns"
|
||||
keyExcludePatterns = "exclude-patterns"
|
||||
keyFollowPaths = "followpaths"
|
||||
keyDirName = "dir-name"
|
||||
)
|
||||
|
||||
|
@ -87,6 +88,8 @@ func (sp *fsSyncProvider) handle(method string, stream grpc.ServerStream) (retEr
|
|||
}
|
||||
includes := opts[keyIncludePatterns]
|
||||
|
||||
followPaths := opts[keyFollowPaths]
|
||||
|
||||
var progress progressCb
|
||||
if sp.p != nil {
|
||||
progress = sp.p
|
||||
|
@ -98,7 +101,7 @@ func (sp *fsSyncProvider) handle(method string, stream grpc.ServerStream) (retEr
|
|||
doneCh = sp.doneCh
|
||||
sp.doneCh = nil
|
||||
}
|
||||
err := pr.sendFn(stream, dir.Dir, includes, excludes, progress, dir.Map)
|
||||
err := pr.sendFn(stream, dir.Dir, includes, excludes, followPaths, progress, dir.Map)
|
||||
if doneCh != nil {
|
||||
if err != nil {
|
||||
doneCh <- err
|
||||
|
@ -117,7 +120,7 @@ type progressCb func(int, bool)
|
|||
|
||||
type protocol struct {
|
||||
name string
|
||||
sendFn func(stream grpc.Stream, srcDir string, includes, excludes []string, progress progressCb, _map func(*fsutil.Stat) bool) error
|
||||
sendFn func(stream grpc.Stream, srcDir string, includes, excludes, followPaths []string, progress progressCb, _map func(*fsutil.Stat) bool) error
|
||||
recvFn func(stream grpc.Stream, destDir string, cu CacheUpdater, progress progressCb) error
|
||||
}
|
||||
|
||||
|
@ -142,6 +145,7 @@ type FSSendRequestOpt struct {
|
|||
Name string
|
||||
IncludePatterns []string
|
||||
ExcludePatterns []string
|
||||
FollowPaths []string
|
||||
OverrideExcludes bool // deprecated: this is used by docker/cli for automatically loading .dockerignore from the directory
|
||||
DestDir string
|
||||
CacheUpdater CacheUpdater
|
||||
|
@ -181,6 +185,10 @@ func FSSync(ctx context.Context, c session.Caller, opt FSSendRequestOpt) error {
|
|||
opts[keyExcludePatterns] = opt.ExcludePatterns
|
||||
}
|
||||
|
||||
if opt.FollowPaths != nil {
|
||||
opts[keyFollowPaths] = opt.FollowPaths
|
||||
}
|
||||
|
||||
opts[keyDirName] = []string{opt.Name}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
@ -261,7 +269,7 @@ func CopyToCaller(ctx context.Context, srcPath string, c session.Caller, progres
|
|||
return err
|
||||
}
|
||||
|
||||
return sendDiffCopy(cc, srcPath, nil, nil, progress, nil)
|
||||
return sendDiffCopy(cc, srcPath, nil, nil, nil, progress, nil)
|
||||
}
|
||||
|
||||
func CopyFileWriter(ctx context.Context, c session.Caller) (io.WriteCloser, error) {
|
||||
|
|
|
@ -4,6 +4,7 @@ const AttrKeepGitDir = "git.keepgitdir"
|
|||
const AttrFullRemoteURL = "git.fullurl"
|
||||
const AttrLocalSessionID = "local.session"
|
||||
const AttrIncludePatterns = "local.includepattern"
|
||||
const AttrFollowPaths = "local.followpaths"
|
||||
const AttrExcludePatterns = "local.excludepatterns"
|
||||
const AttrSharedKeyHint = "local.sharedkeyhint"
|
||||
const AttrLLBDefinitionFilename = "llbbuild.filename"
|
||||
|
|
|
@ -2,6 +2,7 @@ package source
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -69,6 +70,7 @@ func FromLLB(op *pb.Op_Source) (Identifier, error) {
|
|||
}
|
||||
if id, ok := id.(*LocalIdentifier); ok {
|
||||
for k, v := range op.Source.Attrs {
|
||||
fmt.Printf("kv %q %q\n", k, v)
|
||||
switch k {
|
||||
case pb.AttrLocalSessionID:
|
||||
id.SessionID = v
|
||||
|
@ -88,6 +90,13 @@ func FromLLB(op *pb.Op_Source) (Identifier, error) {
|
|||
return nil, err
|
||||
}
|
||||
id.ExcludePatterns = patterns
|
||||
case pb.AttrFollowPaths:
|
||||
var paths []string
|
||||
if err := json.Unmarshal([]byte(v), &paths); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id.FollowPaths = paths
|
||||
fmt.Printf("FollowPaths %#v\n", paths)
|
||||
case pb.AttrSharedKeyHint:
|
||||
id.SharedKeyHint = v
|
||||
}
|
||||
|
@ -153,6 +162,7 @@ type LocalIdentifier struct {
|
|||
SessionID string
|
||||
IncludePatterns []string
|
||||
ExcludePatterns []string
|
||||
FollowPaths []string
|
||||
SharedKeyHint string
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,7 @@ func (ls *localSourceHandler) Snapshot(ctx context.Context) (out cache.Immutable
|
|||
Name: ls.src.Name,
|
||||
IncludePatterns: ls.src.IncludePatterns,
|
||||
ExcludePatterns: ls.src.ExcludePatterns,
|
||||
FollowPaths: ls.src.FollowPaths,
|
||||
OverrideExcludes: false,
|
||||
DestDir: dest,
|
||||
CacheUpdater: &cacheUpdater{cc},
|
||||
|
|
Loading…
Reference in New Issue