Skip to content

Commit 8478f02

Browse files
ajankovicmmatczuk
authored andcommitted
sync: add alrternative CopyDir implementation
Add sync.CopyDir2 which is coping files from directory to directory based on absolute paths from the root of file systems.
1 parent a08471e commit 8478f02

File tree

5 files changed

+54
-19
lines changed

5 files changed

+54
-19
lines changed

fs/fs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,7 @@ type Objects []Object
10611061
// operation.
10621062
type ObjectPair struct {
10631063
Src, Dst Object
1064+
Name string
10641065
}
10651066

10661067
// UnWrapFs unwraps f as much as possible and returns the base Fs

fs/march/march.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ type March struct {
2424
// parameters
2525
Ctx context.Context // context for background goroutines
2626
Fdst fs.Fs // source Fs
27+
DstDir string // destination directory
2728
Fsrc fs.Fs // dest Fs
28-
Dir string // directory
29+
SrcDir string // source directory
2930
NoTraverse bool // don't traverse the destination
3031
SrcIncludeAll bool // don't include all files in the src
3132
DstIncludeAll bool // don't include all files in the destination
@@ -49,9 +50,9 @@ type Marcher interface {
4950

5051
// init sets up a march over opt.Fsrc, and opt.Fdst calling back callback for each match
5152
func (m *March) init() {
52-
m.srcListDir = m.makeListDir(m.Fsrc, m.SrcIncludeAll)
53+
m.srcListDir = m.makeListDir(m.Fsrc, m.SrcDir, m.SrcIncludeAll)
5354
if !m.NoTraverse {
54-
m.dstListDir = m.makeListDir(m.Fdst, m.DstIncludeAll)
55+
m.dstListDir = m.makeListDir(m.Fdst, m.DstDir, m.DstIncludeAll)
5556
}
5657
// Now create the matching transform
5758
// ..normalise the UTF8 first
@@ -72,7 +73,7 @@ type listDirFn func(dir string) (entries fs.DirEntries, err error)
7273

7374
// makeListDir makes constructs a listing function for the given fs
7475
// and includeAll flags for marching through the file system.
75-
func (m *March) makeListDir(f fs.Fs, includeAll bool) listDirFn {
76+
func (m *March) makeListDir(f fs.Fs, remote string, includeAll bool) listDirFn {
7677
if !(fs.Config.UseListR && f.Features().ListR != nil) && // !--fast-list active and
7778
!(fs.Config.NoTraverse && filter.Active.HaveFilesFrom()) { // !(--files-from and --no-traverse)
7879
return func(dir string) (entries fs.DirEntries, err error) {
@@ -92,7 +93,7 @@ func (m *March) makeListDir(f fs.Fs, includeAll bool) listDirFn {
9293
mu.Lock()
9394
defer mu.Unlock()
9495
if !started {
95-
dirs, dirsErr = walk.NewDirTree(m.Ctx, f, m.Dir, includeAll, fs.Config.MaxDepth)
96+
dirs, dirsErr = walk.NewDirTree(m.Ctx, f, remote, includeAll, fs.Config.MaxDepth)
9697
started = true
9798
}
9899
if dirsErr != nil {
@@ -185,9 +186,9 @@ func (m *March) Run() error {
185186
// Start the process
186187
traversing.Add(1)
187188
in <- listDirJob{
188-
srcRemote: m.Dir,
189+
srcRemote: m.SrcDir,
189190
srcDepth: srcDepth - 1,
190-
dstRemote: m.Dir,
191+
dstRemote: m.DstDir,
191192
dstDepth: dstDepth - 1,
192193
noDst: m.NoCheckDest,
193194
}

fs/march/march_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ func TestMarch(t *testing.T) {
195195
m := &March{
196196
Ctx: ctx,
197197
Fdst: r.Fremote,
198+
DstDir: "",
198199
Fsrc: r.Flocal,
199-
Dir: "",
200+
SrcDir: "",
200201
NoTraverse: mt.noTraverse,
201202
Callback: mt,
202203
DstIncludeAll: filter.Active.Opt.DeleteExcluded,
@@ -262,8 +263,9 @@ func TestMarchNoTraverse(t *testing.T) {
262263
m := &March{
263264
Ctx: ctx,
264265
Fdst: r.Fremote,
266+
DstDir: "",
265267
Fsrc: r.Flocal,
266-
Dir: "",
268+
SrcDir: "",
267269
NoTraverse: mt.noTraverse,
268270
Callback: mt,
269271
DstIncludeAll: filter.Active.Opt.DeleteExcluded,

fs/operations/operations.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,6 @@ func CheckFn(ctx context.Context, fdst, fsrc fs.Fs, check checkFn, oneway bool)
869869
Ctx: ctx,
870870
Fdst: fdst,
871871
Fsrc: fsrc,
872-
Dir: "",
873872
Callback: c,
874873
}
875874
fs.Infof(fdst, "Waiting for checks to finish")

fs/sync/sync.go

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"path"
88
"sort"
9+
"strings"
910
"sync"
1011
"time"
1112

@@ -27,7 +28,8 @@ type syncCopyMove struct {
2728
DoMove bool
2829
copyEmptySrcDirs bool
2930
deleteEmptySrcDirs bool
30-
dir string
31+
dstDir string
32+
srcDir string
3133
// internal state
3234
ctx context.Context // internal context for controlling go-routines
3335
cancel func() // cancel the context
@@ -64,9 +66,10 @@ type syncCopyMove struct {
6466
renameCheck []fs.Object // accumulate files to check for rename here
6567
compareCopyDest fs.Fs // place to check for files to server side copy
6668
backupDir fs.Fs // place to store overwrites/deletes
69+
useSrcBaseName bool // use only source basename when coping or moving to destination directory
6770
}
6871

69-
func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.DeleteMode, DoMove bool, deleteEmptySrcDirs bool, copyEmptySrcDirs bool) (*syncCopyMove, error) {
72+
func newSyncCopyMove(ctx context.Context, fdst fs.Fs, remoteDst string, fsrc fs.Fs, remoteSrc string, deleteMode fs.DeleteMode, DoMove bool, deleteEmptySrcDirs bool, copyEmptySrcDirs bool, useSrcBaseName bool) (*syncCopyMove, error) {
7073
if (deleteMode != fs.DeleteModeOff || DoMove) && operations.Overlapping(fdst, fsrc) {
7174
return nil, fserrors.FatalError(fs.ErrorOverlapping)
7275
}
@@ -77,7 +80,8 @@ func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
7780
DoMove: DoMove,
7881
copyEmptySrcDirs: copyEmptySrcDirs,
7982
deleteEmptySrcDirs: deleteEmptySrcDirs,
80-
dir: "",
83+
dstDir: remoteDst,
84+
srcDir: remoteSrc,
8185
srcFilesChan: make(chan fs.Object, fs.Config.Checkers+fs.Config.Transfers),
8286
srcFilesResult: make(chan error, 1),
8387
dstFilesResult: make(chan error, 1),
@@ -89,6 +93,7 @@ func newSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
8993
trackRenames: fs.Config.TrackRenames,
9094
commonHash: fsrc.Hashes().Overlap(fdst.Hashes()).GetOne(),
9195
trackRenamesCh: make(chan fs.Object, fs.Config.Checkers),
96+
useSrcBaseName: useSrcBaseName,
9297
}
9398
var err error
9499
s.toBeChecked, err = newPipe(fs.Config.OrderBy, accounting.Stats(ctx).SetCheckQueue, fs.Config.MaxBacklog)
@@ -325,15 +330,32 @@ func (s *syncCopyMove) pairCopyOrMove(ctx context.Context, in *pipe, fdst fs.Fs,
325330
return
326331
}
327332
src := pair.Src
333+
name := s.dstObjectName(pair)
328334
if s.DoMove {
329-
_, err = operations.Move(ctx, fdst, pair.Dst, src.Remote(), src)
335+
_, err = operations.Move(ctx, fdst, pair.Dst, name, src)
330336
} else {
331-
_, err = operations.Copy(ctx, fdst, pair.Dst, src.Remote(), src)
337+
_, err = operations.Copy(ctx, fdst, pair.Dst, name, src)
332338
}
333339
s.processError(err)
334340
}
335341
}
336342

343+
// dstObjectName returns full name of the object as it should be on the
344+
// destination after copy or move.
345+
func (s *syncCopyMove) dstObjectName(pair fs.ObjectPair) string {
346+
if !s.useSrcBaseName {
347+
return pair.Src.Remote()
348+
}
349+
350+
// Example when coping:
351+
// data:test_keyspace/snapshots/123/bla/somefile.file
352+
// to
353+
// s3:bucket/backup/long/path/to/123
354+
// this should return backup/long/path/to/123/bla/somefile.file
355+
// So we get full path on the destination fs.
356+
return path.Join(s.dstDir, strings.TrimPrefix(pair.Src.Remote(), s.srcDir))
357+
}
358+
337359
// This starts the background checkers.
338360
func (s *syncCopyMove) startCheckers() {
339361
s.checkerWg.Add(fs.Config.Checkers)
@@ -696,8 +718,9 @@ func (s *syncCopyMove) run() error {
696718
m := &march.March{
697719
Ctx: s.ctx,
698720
Fdst: s.fdst,
721+
DstDir: s.dstDir,
699722
Fsrc: s.fsrc,
700-
Dir: s.dir,
723+
SrcDir: s.srcDir,
701724
NoTraverse: s.noTraverse,
702725
Callback: s,
703726
DstIncludeAll: filter.Active.Opt.DeleteExcluded,
@@ -899,7 +922,7 @@ func (s *syncCopyMove) Match(ctx context.Context, dst, src fs.DirEntry) (recurse
899922
// If DoMove is true then files will be moved instead of copied
900923
//
901924
// dir is the start directory, "" for root
902-
func runSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.DeleteMode, DoMove bool, deleteEmptySrcDirs bool, copyEmptySrcDirs bool) error {
925+
func runSyncCopyMove(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, deleteMode fs.DeleteMode, DoMove bool, deleteEmptySrcDirs bool, copyEmptySrcDirs bool) error {
903926
if deleteMode != fs.DeleteModeOff && DoMove {
904927
return fserrors.FatalError(errors.New("can't delete and move at the same time"))
905928
}
@@ -909,7 +932,7 @@ func runSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
909932
return fserrors.FatalError(errors.New("can't use --delete-before with --track-renames"))
910933
}
911934
// only delete stuff during in this pass
912-
do, err := newSyncCopyMove(ctx, fdst, fsrc, fs.DeleteModeOnly, false, deleteEmptySrcDirs, copyEmptySrcDirs)
935+
do, err := newSyncCopyMove(ctx, fdst, "", fsrc, "", fs.DeleteModeOnly, false, deleteEmptySrcDirs, copyEmptySrcDirs, false)
913936
if err != nil {
914937
return err
915938
}
@@ -920,7 +943,7 @@ func runSyncCopyMove(ctx context.Context, fdst, fsrc fs.Fs, deleteMode fs.Delete
920943
// Next pass does a copy only
921944
deleteMode = fs.DeleteModeOff
922945
}
923-
do, err := newSyncCopyMove(ctx, fdst, fsrc, deleteMode, DoMove, deleteEmptySrcDirs, copyEmptySrcDirs)
946+
do, err := newSyncCopyMove(ctx, fdst, "", fsrc, "", deleteMode, DoMove, deleteEmptySrcDirs, copyEmptySrcDirs, false)
924947
if err != nil {
925948
return err
926949
}
@@ -937,6 +960,15 @@ func CopyDir(ctx context.Context, fdst, fsrc fs.Fs, copyEmptySrcDirs bool) error
937960
return runSyncCopyMove(ctx, fdst, fsrc, fs.DeleteModeOff, false, false, copyEmptySrcDirs)
938961
}
939962

963+
// CopyDir2 copies files from fsrc/remoteSrc into fdst/remoteDst.
964+
func CopyDir2(ctx context.Context, fdst fs.Fs, remoteDst string, fsrc fs.Fs, remoteSrc string, copyEmptySrcDirs bool) error {
965+
do, err := newSyncCopyMove(ctx, fdst, remoteDst, fsrc, remoteSrc, fs.DeleteModeOff, false, false, copyEmptySrcDirs, true)
966+
if err != nil {
967+
return err
968+
}
969+
return do.run()
970+
}
971+
940972
// moveDir moves fsrc into fdst
941973
func moveDir(ctx context.Context, fdst, fsrc fs.Fs, deleteEmptySrcDirs bool, copyEmptySrcDirs bool) error {
942974
return runSyncCopyMove(ctx, fdst, fsrc, fs.DeleteModeOff, true, deleteEmptySrcDirs, copyEmptySrcDirs)

0 commit comments

Comments
 (0)