Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for AlwaysReplaceExistingDestPaths in llb copy #4455

Merged
merged 1 commit into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ var allTests = []func(t *testing.T, sb integration.Sandbox){
testFileOpMkdirMkfile,
testFileOpCopyRm,
testFileOpCopyIncludeExclude,
testFileOpCopyAlwaysReplaceExistingDestPaths,
testFileOpRmWildcard,
testFileOpCopyUIDCache,
testCallDiskUsage,
Expand Down Expand Up @@ -1860,6 +1861,80 @@ func testFileOpCopyIncludeExclude(t *testing.T, sb integration.Sandbox) {
require.Equal(t, randBytes, randBytes2)
}

func testFileOpCopyAlwaysReplaceExistingDestPaths(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
c, err := New(sb.Context(), sb.Address())
require.NoError(t, err)
defer c.Close()

destDirHostPath := integration.Tmpdir(t,
fstest.CreateDir("root", 0755),
fstest.CreateDir("root/overwritedir", 0755),
fstest.CreateFile("root/overwritedir/subfile", nil, 0755),
fstest.CreateFile("root/overwritefile", nil, 0755),
fstest.Symlink("dir", "root/overwritesymlink"),
fstest.CreateDir("root/dir", 0755),
fstest.CreateFile("root/dir/dirfile1", nil, 0755),
fstest.CreateDir("root/dir/overwritesubdir", 0755),
fstest.CreateFile("root/dir/overwritesubfile", nil, 0755),
fstest.Symlink("dirfile1", "root/dir/overwritesymlink"),
)
destDir := llb.Local("destDir")

srcDirHostPath := integration.Tmpdir(t,
fstest.CreateDir("root", 0755),
fstest.CreateFile("root/overwritedir", nil, 0755),
fstest.CreateDir("root/overwritefile", 0755),
fstest.CreateFile("root/overwritefile/foo", nil, 0755),
fstest.CreateDir("root/overwritesymlink", 0755),
fstest.CreateDir("root/dir", 0755),
fstest.CreateFile("root/dir/dirfile2", nil, 0755),
fstest.CreateFile("root/dir/overwritesubdir", nil, 0755),
fstest.CreateDir("root/dir/overwritesubfile", 0755),
fstest.CreateDir("root/dir/overwritesymlink", 0755),
)
srcDir := llb.Local("srcDir")

resultDir := destDir.File(llb.Copy(srcDir, "/", "/", &llb.CopyInfo{
CopyDirContentsOnly: true,
AlwaysReplaceExistingDestPaths: true,
}))

def, err := resultDir.Marshal(sb.Context())
require.NoError(t, err)

resultDirHostPath := t.TempDir()

_, err = c.Solve(sb.Context(), def, SolveOpt{
Exports: []ExportEntry{
{
Type: ExporterLocal,
OutputDir: resultDirHostPath,
},
},
LocalDirs: map[string]string{
"destDir": destDirHostPath.Name,
"srcDir": srcDirHostPath.Name,
},
}, nil)
require.NoError(t, err)

err = fstest.CheckDirectoryEqualWithApplier(resultDirHostPath, fstest.Apply(
fstest.CreateDir("root", 0755),
fstest.CreateFile("root/overwritedir", nil, 0755),
fstest.CreateDir("root/overwritefile", 0755),
fstest.CreateFile("root/overwritefile/foo", nil, 0755),
fstest.CreateDir("root/overwritesymlink", 0755),
fstest.CreateDir("root/dir", 0755),
fstest.CreateFile("root/dir/dirfile1", nil, 0755),
fstest.CreateFile("root/dir/dirfile2", nil, 0755),
fstest.CreateFile("root/dir/overwritesubdir", nil, 0755),
fstest.CreateDir("root/dir/overwritesubfile", 0755),
fstest.CreateDir("root/dir/overwritesymlink", 0755),
))
require.NoError(t, err)
}

// testFileOpInputSwap is a regression test that cache is invalidated when subset of fileop is built
func testFileOpInputSwap(t *testing.T, sb integration.Sandbox) {
requiresLinux(t)
Expand Down
27 changes: 16 additions & 11 deletions client/llb/fileop.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,17 +488,18 @@ type CopyOption interface {
}

type CopyInfo struct {
Mode *os.FileMode
FollowSymlinks bool
CopyDirContentsOnly bool
IncludePatterns []string
ExcludePatterns []string
AttemptUnpack bool
CreateDestPath bool
AllowWildcard bool
AllowEmptyWildcard bool
ChownOpt *ChownOpt
CreatedTime *time.Time
Mode *os.FileMode
FollowSymlinks bool
CopyDirContentsOnly bool
IncludePatterns []string
ExcludePatterns []string
AttemptUnpack bool
CreateDestPath bool
AllowWildcard bool
AllowEmptyWildcard bool
ChownOpt *ChownOpt
CreatedTime *time.Time
AlwaysReplaceExistingDestPaths bool
}

func (mi *CopyInfo) SetCopyOption(mi2 *CopyInfo) {
Expand Down Expand Up @@ -533,6 +534,7 @@ func (a *fileActionCopy) toProtoAction(ctx context.Context, parent string, base
AttemptUnpackDockerCompatibility: a.info.AttemptUnpack,
CreateDestPath: a.info.CreateDestPath,
Timestamp: marshalTime(a.info.CreatedTime),
AlwaysReplaceExistingDestPaths: a.info.AlwaysReplaceExistingDestPaths,
}
if a.info.Mode != nil {
c.Mode = int32(*a.info.Mode)
Expand Down Expand Up @@ -565,6 +567,9 @@ func (a *fileActionCopy) addCaps(f *FileOp) {
if len(a.info.IncludePatterns) != 0 || len(a.info.ExcludePatterns) != 0 {
addCap(&f.constraints, pb.CapFileCopyIncludeExcludePatterns)
}
if a.info.AlwaysReplaceExistingDestPaths {
addCap(&f.constraints, pb.CapFileCopyAlwaysReplaceExistingDestPaths)
}
}

type CreatedTime time.Time
Expand Down
1 change: 1 addition & 0 deletions solver/llbsolver/file/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *
}
ci.CopyDirContents = action.DirCopyContents
ci.FollowLinks = action.FollowSymlink
ci.AlwaysReplaceExistingDestPaths = action.AlwaysReplaceExistingDestPaths
},
copy.WithXAttrErrorHandler(xattrErrorHandler),
}
Expand Down
15 changes: 11 additions & 4 deletions solver/pb/caps.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ const (
CapExecCgroupsMounted apicaps.CapID = "exec.cgroup"
CapExecSecretEnv apicaps.CapID = "exec.secretenv"

CapFileBase apicaps.CapID = "file.base"
CapFileRmWildcard apicaps.CapID = "file.rm.wildcard"
CapFileCopyIncludeExcludePatterns apicaps.CapID = "file.copy.includeexcludepatterns"
CapFileRmNoFollowSymlink apicaps.CapID = "file.rm.nofollowsymlink"
CapFileBase apicaps.CapID = "file.base"
CapFileRmWildcard apicaps.CapID = "file.rm.wildcard"
CapFileCopyIncludeExcludePatterns apicaps.CapID = "file.copy.includeexcludepatterns"
CapFileRmNoFollowSymlink apicaps.CapID = "file.rm.nofollowsymlink"
CapFileCopyAlwaysReplaceExistingDestPaths apicaps.CapID = "file.copy.alwaysreplaceexistingdestpaths"

CapConstraints apicaps.CapID = "constraints"
CapPlatform apicaps.CapID = "platform"
Expand Down Expand Up @@ -384,6 +385,12 @@ func init() {
Status: apicaps.CapStatusExperimental,
})

Caps.Init(apicaps.Cap{
ID: CapFileCopyAlwaysReplaceExistingDestPaths,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})

Caps.Init(apicaps.Cap{
ID: CapConstraints,
Enabled: true,
Expand Down
Loading