diff --git a/cmd/bisync/bilib/names.go b/cmd/bisync/bilib/names.go index 3093dff55..70d3d61be 100644 --- a/cmd/bisync/bilib/names.go +++ b/cmd/bisync/bilib/names.go @@ -5,6 +5,8 @@ import ( "os" "sort" "strconv" + "strings" + "time" ) // Names comprises a set of file names @@ -83,3 +85,81 @@ func (am AliasMap) Alias(name1 string) string { } return name1 } + +// ParseGlobs determines whether a string contains {brackets} +// and returns the substring (including both brackets) for replacing +// substring is first opening bracket to last closing bracket -- +// good for {{this}} but not {this}{this} +func ParseGlobs(s string) (hasGlobs bool, substring string) { + open := strings.Index(s, "{") + close := strings.LastIndex(s, "}") + if open >= 0 && close > open { + return true, s[open : close+1] + } + return false, "" +} + +// TrimBrackets converts {{this}} to this +func TrimBrackets(s string) string { + return strings.Trim(s, "{}") +} + +// TimeFormat converts a user-supplied string to a Go time constant, if possible +func TimeFormat(timeFormat string) string { + switch timeFormat { + case "Layout": + timeFormat = time.Layout + case "ANSIC": + timeFormat = time.ANSIC + case "UnixDate": + timeFormat = time.UnixDate + case "RubyDate": + timeFormat = time.RubyDate + case "RFC822": + timeFormat = time.RFC822 + case "RFC822Z": + timeFormat = time.RFC822Z + case "RFC850": + timeFormat = time.RFC850 + case "RFC1123": + timeFormat = time.RFC1123 + case "RFC1123Z": + timeFormat = time.RFC1123Z + case "RFC3339": + timeFormat = time.RFC3339 + case "RFC3339Nano": + timeFormat = time.RFC3339Nano + case "Kitchen": + timeFormat = time.Kitchen + case "Stamp": + timeFormat = time.Stamp + case "StampMilli": + timeFormat = time.StampMilli + case "StampMicro": + timeFormat = time.StampMicro + case "StampNano": + timeFormat = time.StampNano + case "DateTime": + // timeFormat = time.DateTime // missing in go1.19 + timeFormat = "2006-01-02 15:04:05" + case "DateOnly": + // timeFormat = time.DateOnly // missing in go1.19 + timeFormat = "2006-01-02" + case "TimeOnly": + // timeFormat = time.TimeOnly // missing in go1.19 + timeFormat = "15:04:05" + case "MacFriendlyTime", "macfriendlytime", "mac": + timeFormat = "2006-01-02 0304PM" // not actually a Go constant -- but useful as macOS filenames can't have colons + } + return timeFormat +} + +// AppyTimeGlobs converts "myfile-{DateOnly}.txt" to "myfile-2006-01-02.txt" +func AppyTimeGlobs(s string, t time.Time) string { + hasGlobs, substring := ParseGlobs(s) + if !hasGlobs { + return s + } + timeString := t.Local().Format(TimeFormat(TrimBrackets(substring))) + return strings.ReplaceAll(s, substring, timeString) +} diff --git a/cmd/bisync/bisync_test.go b/cmd/bisync/bisync_test.go index 68df96838..a1d21845c 100644 --- a/cmd/bisync/bisync_test.go +++ b/cmd/bisync/bisync_test.go @@ -118,6 +118,9 @@ var logHoppers = []string{ // Test case `normalization` can have random order of fix-case files. `(?:INFO |NOTICE): .*: Fixed case by renaming to: .*`, + + // order of files re-checked prior to a conflict rename + `ERROR : .*: md5 differ.*`, } // Some log lines can contain Windows path separator that must be @@ -853,6 +856,12 @@ func (b *bisyncTest) runBisync(ctx context.Context, args []string) (err error) { ci.NoUnicodeNormalization = false ci.IgnoreCaseSync = true ci.FixCase = true + case "conflict-resolve": + _ = opt.ConflictResolve.Set(val) + case "conflict-loser": + _ = opt.ConflictLoser.Set(val) + case "conflict-suffix": + opt.ConflictSuffixFlag = val default: return fmt.Errorf("invalid bisync option %q", arg) } diff --git a/cmd/bisync/cmd.go b/cmd/bisync/cmd.go index 6e5b95912..17442c9ea 100644 --- a/cmd/bisync/cmd.go +++ b/cmd/bisync/cmd.go @@ -55,6 +55,11 @@ type Options struct { CompareFlag string DebugName string MaxLock time.Duration + ConflictResolve Prefer + ConflictLoser ConflictLoserAction + ConflictSuffixFlag string + ConflictSuffix1 string + ConflictSuffix2 string } // Default values @@ -141,6 +146,9 @@ func init() { flags.BoolVarP(cmdFlags, &Opt.Compare.SlowHashSyncOnly, "slow-hash-sync-only", "", Opt.Compare.SlowHashSyncOnly, "Ignore slow checksums for listings and deltas, but still consider them during sync calls.", "") flags.BoolVarP(cmdFlags, &Opt.Compare.DownloadHash, "download-hash", "", Opt.Compare.DownloadHash, "Compute hash by downloading when otherwise unavailable. (warning: may be slow and use lots of data!)", "") flags.DurationVarP(cmdFlags, &Opt.MaxLock, "max-lock", "", Opt.MaxLock, "Consider lock files older than this to be expired (default: 0 (never expire)) (minimum: 2m)", "") + flags.FVarP(cmdFlags, &Opt.ConflictResolve, "conflict-resolve", "", "Automatically resolve conflicts by preferring the version that is: "+ConflictResolveList+" (default: none)", "") + flags.FVarP(cmdFlags, &Opt.ConflictLoser, "conflict-loser", "", "Action to take on the loser of a sync conflict (when there is a winner) or on both files (when there is no winner): "+ConflictLoserList+" (default: num)", "") + flags.StringVarP(cmdFlags, &Opt.ConflictSuffixFlag, "conflict-suffix", "", Opt.ConflictSuffixFlag, "Suffix to use when renaming a --conflict-loser. Can be either one string or two comma-separated strings to assign different suffixes to Path1/Path2. (default: 'conflict')", "") } // bisync command definition @@ -154,6 +162,8 @@ var commandDefinition = &cobra.Command{ "status": "Beta", }, RunE: func(command *cobra.Command, args []string) error { + // NOTE: avoid putting too much handling here, as it won't apply to the rc. + // Generally it's best to put init-type stuff in Bisync() (operations.go) cmd.CheckArgs(2, 2, command, args) fs1, file1, fs2, file2 := cmd.NewFsSrcDstFiles(args) if file1 != "" || file2 != "" { diff --git a/cmd/bisync/deltas.go b/cmd/bisync/deltas.go index 323d1c799..167bd70fd 100644 --- a/cmd/bisync/deltas.go +++ b/cmd/bisync/deltas.go @@ -8,11 +8,11 @@ import ( "path/filepath" "sort" "strings" + "time" "github.com/rclone/rclone/cmd/bisync/bilib" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/filter" - "github.com/rclone/rclone/fs/operations" "github.com/rclone/rclone/lib/terminal" "golang.org/x/text/unicode/norm" ) @@ -46,6 +46,7 @@ func (d delta) is(cond delta) bool { type deltaSet struct { deltas map[string]delta size map[string]int64 + time map[string]time.Time hash map[string]string opt *Options fs fs.Fs // base filesystem @@ -170,6 +171,7 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string, ds = &deltaSet{ deltas: map[string]delta{}, size: map[string]int64{}, + time: map[string]time.Time{}, hash: map[string]string{}, fs: f, msg: msg, @@ -183,6 +185,7 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string, d := deltaZero s := int64(0) h := "" + var t time.Time if !now.has(file) { b.indent(msg, file, Color(terminal.RedFg, "File was deleted")) ds.deleted++ @@ -215,6 +218,7 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string, whatchanged = append(whatchanged, Color(terminal.MagentaFg, "time (older)")) d |= deltaOlder } + t = now.getTime(file) } } if b.opt.Compare.Checksum { @@ -238,6 +242,9 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string, if b.opt.Compare.Size { ds.size[file] = s } + if b.opt.Compare.Modtime { + ds.time[file] = t + } if b.opt.Compare.Checksum { ds.hash[file] = h } @@ -258,6 +265,9 @@ func (b *bisyncRun) findDeltas(fctx context.Context, f fs.Fs, oldListing string, if b.opt.Compare.Size { ds.size[file] = now.getSize(file) } + if b.opt.Compare.Modtime { + ds.time[file] = now.getTime(file) + } if b.opt.Compare.Checksum { ds.hash[file] = now.getHash(file) } @@ -287,12 +297,11 @@ func (b *bisyncRun) applyDeltas(ctx context.Context, ds1, ds2 *deltaSet) (change delete1 := bilib.Names{} delete2 := bilib.Names{} handled := bilib.Names{} - renamed1 := bilib.Names{} - renamed2 := bilib.Names{} renameSkipped := bilib.Names{} deletedonboth := bilib.Names{} skippedDirs1 := newFileList() skippedDirs2 := newFileList() + b.renames = renames{} ctxMove := b.opt.setDryRun(ctx) @@ -422,34 +431,10 @@ func (b *bisyncRun) applyDeltas(ctx context.Context, ds1, ds2 *deltaSet) (change } } else { fs.Debugf(nil, "Files are NOT equal: %s", file) - b.indent("!Path1", p1+"..path1", "Renaming Path1 copy") - ctxMove = b.setBackupDir(ctxMove, 1) // in case already a file with new name - if err = operations.MoveFile(ctxMove, b.fs1, b.fs1, file+"..path1", file); err != nil { - err = fmt.Errorf("path1 rename failed for %s: %w", p1, err) - b.critical = true + err = b.resolve(ctxMove, path1, path2, file, alias, &renameSkipped, ©1to2, ©2to1, ds1, ds2) + if err != nil { return } - if b.opt.DryRun { - renameSkipped.Add(file) - } else { - renamed1.Add(file) - } - b.indent("!Path1", p2+"..path1", "Queue copy to Path2") - copy1to2.Add(file + "..path1") - - b.indent("!Path2", p2+"..path2", "Renaming Path2 copy") - ctxMove = b.setBackupDir(ctxMove, 2) // in case already a file with new name - if err = operations.MoveFile(ctxMove, b.fs2, b.fs2, alias+"..path2", alias); err != nil { - err = fmt.Errorf("path2 rename failed for %s: %w", alias, err) - return - } - if b.opt.DryRun { - renameSkipped.Add(alias) - } else { - renamed2.Add(alias) - } - b.indent("!Path2", p1+"..path2", "Queue copy to Path1") - copy2to1.Add(alias + "..path2") } } handled.Add(file) @@ -554,8 +539,6 @@ func (b *bisyncRun) applyDeltas(ctx context.Context, ds1, ds2 *deltaSet) (change queues.copy1to2 = copy1to2 queues.copy2to1 = copy2to1 - queues.renamed1 = renamed1 - queues.renamed2 = renamed2 queues.renameSkipped = renameSkipped queues.deletedonboth = deletedonboth queues.skippedDirs1 = skippedDirs1 diff --git a/cmd/bisync/listing.go b/cmd/bisync/listing.go index 827a2e14c..8f6d8eb19 100644 --- a/cmd/bisync/listing.go +++ b/cmd/bisync/listing.go @@ -77,6 +77,10 @@ func (ls *fileList) empty() bool { } func (ls *fileList) has(file string) bool { + if file == "" { + fs.Debugf(nil, "called ls.has() with blank string") + return false + } _, found := ls.info[file] if !found { //try unquoting @@ -467,11 +471,9 @@ func ConvertPrecision(Modtime time.Time, dst fs.Fs) time.Time { // modifyListing will modify the listing based on the results of the sync func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, results []Results, queues queues, is1to2 bool) (err error) { queue := queues.copy2to1 - renames := queues.renamed2 direction := "2to1" if is1to2 { queue = queues.copy1to2 - renames = queues.renamed1 direction = "1to2" } @@ -596,37 +598,39 @@ func (b *bisyncRun) modifyListing(ctx context.Context, src fs.Fs, dst fs.Fs, res dstList.remove(file) } } - if renames.NotEmpty() && !b.opt.DryRun { + if b.renames.NotEmpty() && !b.opt.DryRun { // renamed on src and copied to dst - renamesList := renames.ToList() - for _, file := range renamesList { + for _, rename := range b.renames { + srcOldName, srcNewName, dstOldName, dstNewName := rename.getNames(is1to2) + fs.Debugf(nil, "%s: srcOldName: %v srcNewName: %v dstOldName: %v dstNewName: %v", direction, srcOldName, srcNewName, dstOldName, dstNewName) // we'll handle the other side when we go the other direction - newName := file + "..path2" - oppositeName := file + "..path1" - if is1to2 { - newName = file + "..path1" - oppositeName = file + "..path2" - } var new *fileInfo - // we prefer to get the info from the ..path1 / ..path2 versions + // we prefer to get the info from the newNamed versions // since they were actually copied as opposed to operations.MoveFile()'d. // the size/time/hash info is therefore fresher on the renames // but we'll settle for the original if we have to. - if srcList.has(newName) { - new = srcList.get(newName) - } else if srcList.has(oppositeName) { - new = srcList.get(oppositeName) - } else if srcList.has(file) { - new = srcList.get(file) + if srcList.has(srcNewName) { + new = srcList.get(srcNewName) + } else if srcList.has(dstNewName) { + new = srcList.get(dstNewName) + } else if srcList.has(srcOldName) { + new = srcList.get(srcOldName) } else { - if err := filterRecheck.AddFile(file); err != nil { - fs.Debugf(file, "error adding file to recheck filter: %v", err) + // something's odd, so let's recheck + if err := filterRecheck.AddFile(srcOldName); err != nil { + fs.Debugf(srcOldName, "error adding file to recheck filter: %v", err) } } - srcList.put(newName, new.size, new.time, new.hash, new.id, new.flags) - dstList.put(newName, new.size, ConvertPrecision(new.time, src), new.hash, new.id, new.flags) - srcList.remove(file) - dstList.remove(file) + if srcNewName != "" { // if it was renamed and not deleted + srcList.put(srcNewName, new.size, new.time, new.hash, new.id, new.flags) + dstList.put(srcNewName, new.size, ConvertPrecision(new.time, src), new.hash, new.id, new.flags) + } + if srcNewName != srcOldName { + srcList.remove(srcOldName) + } + if srcNewName != dstOldName { + dstList.remove(dstOldName) + } } } diff --git a/cmd/bisync/operations.go b/cmd/bisync/operations.go index 15c9e32ff..4d5aa9b75 100644 --- a/cmd/bisync/operations.go +++ b/cmd/bisync/operations.go @@ -49,13 +49,12 @@ type bisyncRun struct { CancelSync context.CancelFunc DebugName string lockFile string + renames renames } type queues struct { copy1to2 bilib.Names copy2to1 bilib.Names - renamed1 bilib.Names // renamed on 1 and copied to 2 - renamed2 bilib.Names // renamed on 2 and copied to 1 renameSkipped bilib.Names // not renamed because it was equal skippedDirs1 *fileList skippedDirs2 *fileList @@ -86,6 +85,10 @@ func Bisync(ctx context.Context, fs1, fs2 fs.Fs, optArg *Options) (err error) { if err != nil { return err } + err = b.setResolveDefaults(ctx) + if err != nil { + return err + } if b.workDir, err = filepath.Abs(opt.Workdir); err != nil { return fmt.Errorf("failed to make workdir absolute: %w", err) diff --git a/cmd/bisync/resolve.go b/cmd/bisync/resolve.go new file mode 100644 index 000000000..4daa9527b --- /dev/null +++ b/cmd/bisync/resolve.go @@ -0,0 +1,450 @@ +package bisync + +import ( + "context" + "fmt" + "math" + "mime" + "path" + "strings" + "time" + + "github.com/rclone/rclone/cmd/bisync/bilib" + "github.com/rclone/rclone/fs" + "github.com/rclone/rclone/fs/operations" + "github.com/rclone/rclone/lib/terminal" +) + +// Prefer describes strategies for resolving sync conflicts +type Prefer = fs.Enum[preferChoices] + +// Supported --conflict-resolve strategies +const ( + PreferNone Prefer = iota + PreferPath1 + PreferPath2 + PreferNewer + PreferOlder + PreferLarger + PreferSmaller +) + +type preferChoices struct{} + +func (preferChoices) Choices() []string { + return []string{ + PreferNone: "none", + PreferNewer: "newer", + PreferOlder: "older", + PreferLarger: "larger", + PreferSmaller: "smaller", + PreferPath1: "path1", + PreferPath2: "path2", + } +} + +func (preferChoices) Type() string { + return "Prefer" +} + +// ConflictResolveList is a list of --conflict-resolve flag choices used in the help +var ConflictResolveList = Opt.ConflictResolve.Help() + +// ConflictLoserAction describes possible actions to take on the loser of a sync conflict +type ConflictLoserAction = fs.Enum[conflictLoserChoices] + +// Supported --conflict-loser actions +const ( + ConflictLoserSkip ConflictLoserAction = iota // Reserved as zero but currently unused + ConflictLoserNumber // file.conflict1, file.conflict2, file.conflict3, etc. + ConflictLoserPathname // file.path1, file.path2 + ConflictLoserDelete // delete the loser, keep winner only +) + +type conflictLoserChoices struct{} + +func (conflictLoserChoices) Choices() []string { + return []string{ + ConflictLoserNumber: "num", + ConflictLoserPathname: "pathname", + ConflictLoserDelete: "delete", + } +} + +func (conflictLoserChoices) Type() string { + return "ConflictLoserAction" +} + +// ConflictLoserList is a list of --conflict-loser flag choices used in the help +var ConflictLoserList = Opt.ConflictLoser.Help() + +func (b *bisyncRun) setResolveDefaults(ctx context.Context) error { + if b.opt.ConflictLoser == ConflictLoserSkip { + b.opt.ConflictLoser = ConflictLoserNumber + } + if b.opt.ConflictSuffixFlag == "" { + b.opt.ConflictSuffixFlag = "conflict" + } + suffixes := strings.Split(b.opt.ConflictSuffixFlag, ",") + if len(suffixes) == 1 { + b.opt.ConflictSuffix1 = suffixes[0] + b.opt.ConflictSuffix2 = suffixes[0] + } else if len(suffixes) == 2 { + b.opt.ConflictSuffix1 = suffixes[0] + b.opt.ConflictSuffix2 = suffixes[1] + } else { + return fmt.Errorf("--conflict-suffix cannot have more than 2 comma-separated values. Received %v: %v", len(suffixes), suffixes) + } + // replace glob variables, if any + t := time.Now() // capture static time here so it is the same for all files throughout this run + b.opt.ConflictSuffix1 = bilib.AppyTimeGlobs(b.opt.ConflictSuffix1, t) + b.opt.ConflictSuffix2 = bilib.AppyTimeGlobs(b.opt.ConflictSuffix2, t) + + // append dot (intentionally allow more than one) + b.opt.ConflictSuffix1 = "." + b.opt.ConflictSuffix1 + b.opt.ConflictSuffix2 = "." + b.opt.ConflictSuffix2 + + // checks and warnings + if (b.opt.ConflictResolve == PreferNewer || b.opt.ConflictResolve == PreferOlder) && (b.fs1.Precision() == fs.ModTimeNotSupported || b.fs2.Precision() == fs.ModTimeNotSupported) { + fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --conflict-resolve %s as at least one remote does not support modtimes."), b.opt.ConflictResolve.String()) + b.opt.ConflictResolve = PreferNone + } else if (b.opt.ConflictResolve == PreferNewer || b.opt.ConflictResolve == PreferOlder) && !b.opt.Compare.Modtime { + fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --conflict-resolve %s as --compare does not include modtime."), b.opt.ConflictResolve.String()) + b.opt.ConflictResolve = PreferNone + } + if (b.opt.ConflictResolve == PreferLarger || b.opt.ConflictResolve == PreferSmaller) && !b.opt.Compare.Size { + fs.Logf(nil, Color(terminal.YellowFg, "WARNING: ignoring --conflict-resolve %s as --compare does not include size."), b.opt.ConflictResolve.String()) + b.opt.ConflictResolve = PreferNone + } + + return nil +} + +type renames map[string]renamesInfo // [originalName]newName (remember the originalName may have an alias) +// the newName may be the same as the old name (if winner), but should not be blank, unless we're deleting. +// the oldNames may not match each other, if we're normalizing case or unicode +// all names should be "remotes" (relative names, without base path) +type renamesInfo struct { + path1 namePair + path2 namePair +} +type namePair struct { + oldName string + newName string +} + +func (b *bisyncRun) resolve(ctxMove context.Context, path1, path2, file, alias string, renameSkipped, copy1to2, copy2to1 *bilib.Names, ds1, ds2 *deltaSet) error { + winningPath := 0 + if b.opt.ConflictResolve != PreferNone { + winningPath = b.conflictWinner(ds1, ds2, file, alias) + if winningPath > 0 { + fs.Infof(file, Color(terminal.GreenFg, "The winner is: Path%d"), winningPath) + } else { + fs.Infof(file, Color(terminal.RedFg, "A winner could not be determined.")) + } + } + + suff1 := b.opt.ConflictSuffix1 // copy to new var to make sure our changes here don't persist + suff2 := b.opt.ConflictSuffix2 + if b.opt.ConflictLoser == ConflictLoserPathname && b.opt.ConflictSuffix1 == b.opt.ConflictSuffix2 { + // numerate, but not if user supplied two different suffixes + suff1 += "1" + suff2 += "2" + } + + r := renamesInfo{ + path1: namePair{ + oldName: file, + newName: SuffixName(ctxMove, file, suff1), + }, + path2: namePair{ + oldName: alias, + newName: SuffixName(ctxMove, alias, suff2), + }, + } + + // handle auto-numbering + // note that we still queue copies for both files, whether or not we renamed + // we also set these for ConflictLoserDelete in case there is no winner. + if b.opt.ConflictLoser == ConflictLoserNumber || b.opt.ConflictLoser == ConflictLoserDelete { + num := b.numerate(ctxMove, 1, file, alias) + switch winningPath { + case 1: // keep path1, rename path2 + r.path1.newName = r.path1.oldName + r.path2.newName = SuffixName(ctxMove, r.path2.oldName, b.opt.ConflictSuffix2+fmt.Sprint(num)) + case 2: // keep path2, rename path1 + r.path1.newName = SuffixName(ctxMove, r.path1.oldName, b.opt.ConflictSuffix1+fmt.Sprint(num)) + r.path2.newName = r.path2.oldName + default: // no winner, so rename both to different numbers (unless suffixes are already different) + if b.opt.ConflictSuffix1 == b.opt.ConflictSuffix2 { + r.path1.newName = SuffixName(ctxMove, r.path1.oldName, b.opt.ConflictSuffix1+fmt.Sprint(num)) + // let's just make sure num + 1 is available... + num2 := b.numerate(ctxMove, num+1, file, alias) + r.path2.newName = SuffixName(ctxMove, r.path2.oldName, b.opt.ConflictSuffix2+fmt.Sprint(num2)) + } else { + // suffixes are different, so numerate independently + num = b.numerateSingle(ctxMove, 1, file, alias, 1) + r.path1.newName = SuffixName(ctxMove, r.path1.oldName, b.opt.ConflictSuffix1+fmt.Sprint(num)) + num = b.numerateSingle(ctxMove, 1, file, alias, 2) + r.path2.newName = SuffixName(ctxMove, r.path2.oldName, b.opt.ConflictSuffix2+fmt.Sprint(num)) + } + } + } + + // when winningPath == 0 (no winner), we ignore settings and rename both, do not delete + // note also that deletes and renames are mutually exclusive -- we never delete one path and rename the other. + if b.opt.ConflictLoser == ConflictLoserDelete && winningPath == 1 { + // delete 2, copy 1 to 2 + err = b.delete(ctxMove, r.path2, path2, path1, b.fs2, 2, 1, renameSkipped) + if err != nil { + return err + } + r.path2.newName = "" + // copy the one that wasn't deleted + b.indent("Path1", r.path1.oldName, "Queue copy to Path2") + copy1to2.Add(r.path1.oldName) + } else if b.opt.ConflictLoser == ConflictLoserDelete && winningPath == 2 { + // delete 1, copy 2 to 1 + err = b.delete(ctxMove, r.path1, path1, path2, b.fs1, 1, 2, renameSkipped) + if err != nil { + return err + } + r.path1.newName = "" + // copy the one that wasn't deleted + b.indent("Path2", r.path2.oldName, "Queue copy to Path1") + copy2to1.Add(r.path2.oldName) + } else { + err = b.rename(ctxMove, r.path1, path1, path2, b.fs1, 1, 2, winningPath, copy1to2, renameSkipped) + if err != nil { + return err + } + err = b.rename(ctxMove, r.path2, path2, path1, b.fs2, 2, 1, winningPath, copy2to1, renameSkipped) + if err != nil { + return err + } + } + + b.renames[r.path1.oldName] = r // note map index is path1's oldName, which may be different from path2 if aliases + return nil +} + +// SuffixName adds the current --conflict-suffix to the remote, obeying +// --suffix-keep-extension if set +// It is a close cousin of operations.SuffixName, but we don't want to +// use ci.Suffix for this because it might be used for --backup-dir. +func SuffixName(ctx context.Context, remote, suffix string) string { + if suffix == "" { + return remote + } + ci := fs.GetConfig(ctx) + if ci.SuffixKeepExtension { + var ( + base = remote + exts = "" + first = true + ext = path.Ext(remote) + ) + for ext != "" { + // Look second and subsequent extensions in mime types. + // If they aren't found then don't keep it as an extension. + if !first && mime.TypeByExtension(ext) == "" { + break + } + base = base[:len(base)-len(ext)] + exts = ext + exts + first = false + ext = path.Ext(base) + } + return base + suffix + exts + } + return remote + suffix +} + +// NotEmpty checks whether set is not empty +func (r renames) NotEmpty() bool { + return len(r) > 0 +} + +func (ri *renamesInfo) getNames(is1to2 bool) (srcOldName, srcNewName, dstOldName, dstNewName string) { + if is1to2 { + return ri.path1.oldName, ri.path1.newName, ri.path2.oldName, ri.path2.newName + } + return ri.path2.oldName, ri.path2.newName, ri.path1.oldName, ri.path1.newName +} + +// work out the lowest number that niether side has, return it for suffix +func (b *bisyncRun) numerate(ctx context.Context, startnum int, file, alias string) int { + for i := startnum; i < math.MaxInt; i++ { + iStr := fmt.Sprint(i) + if !ls1.has(SuffixName(ctx, file, b.opt.ConflictSuffix1+iStr)) && + !ls1.has(SuffixName(ctx, alias, b.opt.ConflictSuffix1+iStr)) && + !ls2.has(SuffixName(ctx, file, b.opt.ConflictSuffix2+iStr)) && + !ls2.has(SuffixName(ctx, alias, b.opt.ConflictSuffix2+iStr)) { + // make sure it still holds true with suffixes switched (it should) + if !ls1.has(SuffixName(ctx, file, b.opt.ConflictSuffix2+iStr)) && + !ls1.has(SuffixName(ctx, alias, b.opt.ConflictSuffix2+iStr)) && + !ls2.has(SuffixName(ctx, file, b.opt.ConflictSuffix1+iStr)) && + !ls2.has(SuffixName(ctx, alias, b.opt.ConflictSuffix1+iStr)) { + fs.Debugf(file, "The first available suffix is: %s", iStr) + return i + } + } + } + return 0 // not really possible, as no one has 9223372036854775807 conflicts, and if they do, they have bigger problems +} + +// like numerate, but consider only one side's suffix (for when suffixes are different) +func (b *bisyncRun) numerateSingle(ctx context.Context, startnum int, file, alias string, path int) int { + lsA, lsB := ls1, ls2 + suffix := b.opt.ConflictSuffix1 + if path == 2 { + lsA, lsB = ls2, ls1 + suffix = b.opt.ConflictSuffix2 + } + for i := startnum; i < math.MaxInt; i++ { + iStr := fmt.Sprint(i) + if !lsA.has(SuffixName(ctx, file, suffix+iStr)) && + !lsA.has(SuffixName(ctx, alias, suffix+iStr)) && + !lsB.has(SuffixName(ctx, file, suffix+iStr)) && + !lsB.has(SuffixName(ctx, alias, suffix+iStr)) { + fs.Debugf(file, "The first available suffix is: %s", iStr) + return i + } + } + return 0 // not really possible, as no one has 9223372036854775807 conflicts, and if they do, they have bigger problems +} + +func (b *bisyncRun) rename(ctx context.Context, thisNamePair namePair, thisPath, thatPath string, thisFs fs.Fs, thisPathNum, thatPathNum, winningPath int, q, renameSkipped *bilib.Names) error { + if winningPath == thisPathNum { + b.indent(fmt.Sprintf("!Path%d", thisPathNum), thisPath+thisNamePair.newName, fmt.Sprintf("Not renaming Path%d copy, as it was determined the winner", thisPathNum)) + } else { + skip := operations.SkipDestructive(ctx, thisNamePair.oldName, "rename") + if !skip { + b.indent(fmt.Sprintf("!Path%d", thisPathNum), thisPath+thisNamePair.newName, fmt.Sprintf("Renaming Path%d copy", thisPathNum)) + ctx = b.setBackupDir(ctx, thisPathNum) // in case already a file with new name + if err = operations.MoveFile(ctx, thisFs, thisFs, thisNamePair.newName, thisNamePair.oldName); err != nil { + err = fmt.Errorf("%s rename failed for %s: %w", thisPath, thisPath+thisNamePair.oldName, err) + b.critical = true + return err + } + } else { + renameSkipped.Add(thisNamePair.oldName) // (due to dry-run, not equality) + } + } + b.indent(fmt.Sprintf("!Path%d", thisPathNum), thatPath+thisNamePair.newName, fmt.Sprintf("Queue copy to Path%d", thatPathNum)) + q.Add(thisNamePair.newName) + return nil +} + +func (b *bisyncRun) delete(ctx context.Context, thisNamePair namePair, thisPath, thatPath string, thisFs fs.Fs, thisPathNum, thatPathNum int, renameSkipped *bilib.Names) error { + skip := operations.SkipDestructive(ctx, thisNamePair.oldName, "delete") + if !skip { + b.indent(fmt.Sprintf("!Path%d", thisPathNum), thisPath+thisNamePair.oldName, fmt.Sprintf("Deleting Path%d copy", thisPathNum)) + ctx = b.setBackupDir(ctx, thisPathNum) + ci := fs.GetConfig(ctx) + var backupDir fs.Fs + if ci.BackupDir != "" { + backupDir, err = operations.BackupDir(ctx, thisFs, thisFs, thisNamePair.oldName) + if err != nil { + b.critical = true + return err + } + } + obj, err := thisFs.NewObject(ctx, thisNamePair.oldName) + if err != nil { + b.critical = true + return err + } + if err = operations.DeleteFileWithBackupDir(ctx, obj, backupDir); err != nil { + err = fmt.Errorf("%s delete failed for %s: %w", thisPath, thisPath+thisNamePair.oldName, err) + b.critical = true + return err + } + } else { + renameSkipped.Add(thisNamePair.oldName) // (due to dry-run, not equality) + } + return nil +} + +func (b *bisyncRun) conflictWinner(ds1, ds2 *deltaSet, remote1, remote2 string) int { + switch b.opt.ConflictResolve { + case PreferPath1: + return 1 + case PreferPath2: + return 2 + case PreferNewer, PreferOlder: + return b.resolveNewerOlder(ds1, ds2, remote1, remote2, b.opt.ConflictResolve) + case PreferLarger, PreferSmaller: + return b.resolveLargerSmaller(ds1, ds2, remote1, remote2, b.opt.ConflictResolve) + default: + return 0 + } +} + +// returns the winning path number, or 0 if winner can't be determined +func (b *bisyncRun) resolveNewerOlder(ds1, ds2 *deltaSet, remote1, remote2 string, prefer Prefer) int { + if fs.GetModifyWindow(b.octx, b.fs1, b.fs2) == fs.ModTimeNotSupported { + fs.Infof(remote1, "Winner cannot be determined as at least one path lacks modtime support.") + return 0 + } + t1, t2 := ds1.time[remote1], ds2.time[remote2] + if t1.IsZero() || t2.IsZero() { + fs.Infof(remote1, "Winner cannot be determined as at least one modtime is missing. Path1: %v, Path2: %v", t1, t2) + return 0 + } + if t1.After(t2) { + if prefer == PreferNewer { + fs.Infof(remote1, "Path1 is newer. Path1: %v, Path2: %v, Difference: %s", t1, t2, t1.Sub(t2)) + return 1 + } else if prefer == PreferOlder { + fs.Infof(remote1, "Path2 is older. Path1: %v, Path2: %v, Difference: %s", t1, t2, t1.Sub(t2)) + return 2 + } + } else if t1.Before(t2) { + if prefer == PreferNewer { + fs.Infof(remote1, "Path2 is newer. Path1: %v, Path2: %v, Difference: %s", t1, t2, t2.Sub(t1)) + return 2 + } else if prefer == PreferOlder { + fs.Infof(remote1, "Path1 is older. Path1: %v, Path2: %v, Difference: %s", t1, t2, t2.Sub(t1)) + return 1 + } + } + if t1.Equal(t2) { + fs.Infof(remote1, "Winner cannot be determined as times are equal. Path1: %v, Path2: %v, Difference: %s", t1, t2, t2.Sub(t1)) + return 0 + } + fs.Errorf(remote1, "Winner cannot be determined. Path1: %v, Path2: %v", t1, t2) // shouldn't happen unless prefer is of wrong type + return 0 +} + +// returns the winning path number, or 0 if winner can't be determined +func (b *bisyncRun) resolveLargerSmaller(ds1, ds2 *deltaSet, remote1, remote2 string, prefer Prefer) int { + s1, s2 := ds1.size[remote1], ds2.size[remote2] + if s1 < 0 || s2 < 0 { + fs.Infof(remote1, "Winner cannot be determined as at least one size is unknown. Path1: %v, Path2: %v", s1, s2) + return 0 + } + if s1 > s2 { + if prefer == PreferLarger { + fs.Infof(remote1, "Path1 is larger. Path1: %v, Path2: %v, Difference: %v", s1, s2, s1-s2) + return 1 + } else if prefer == PreferSmaller { + fs.Infof(remote1, "Path2 is smaller. Path1: %v, Path2: %v, Difference: %v", s1, s2, s1-s2) + return 2 + } + } else if s1 < s2 { + if prefer == PreferLarger { + fs.Infof(remote1, "Path2 is larger. Path1: %v, Path2: %v, Difference: %v", s1, s2, s2-s1) + return 2 + } else if prefer == PreferSmaller { + fs.Infof(remote1, "Path1 is smaller. Path1: %v, Path2: %v, Difference: %v", s1, s2, s2-s1) + return 1 + } + } + if s1 == s2 { + fs.Infof(remote1, "Winner cannot be determined as sizes are equal. Path1: %v, Path2: %v, Difference: %v", s1, s2, s1-s2) + return 0 + } + fs.Errorf(remote1, "Winner cannot be determined. Path1: %v, Path2: %v", s1, s2) // shouldn't happen unless prefer is of wrong type + return 0 +} diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que index 5725b8184..74c4ff68a 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -1,5 +1,5 @@ "file11.txt" "file2.txt" "file4.txt" -"file5.txt..path1" +"file5.txt.conflict1" "file7.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que index 3b79e78bd..8097bfd9d 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -1,5 +1,5 @@ "file1.txt" "file10.txt" "file3.txt" -"file5.txt..path2" +"file5.txt.conflict2" "file6.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-err @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-new @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path1.lst-old @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-err @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-new @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old +++ b/cmd/bisync/testdata/test_backupdir/golden/_testdir_path1.._testdir_path2.path2.lst-old @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_backupdir/golden/test.log b/cmd/bisync/testdata/test_backupdir/golden/test.log index ab8170d50..e398af723 100644 --- a/cmd/bisync/testdata/test_backupdir/golden/test.log +++ b/cmd/bisync/testdata/test_backupdir/golden/test.log @@ -101,10 +101,10 @@ INFO : - Path1 Queue copy to Path2 - { INFO : - Path1 Queue copy to Path2 - {path2/}file2.txt INFO : - Path2 Queue delete - {path2/}file4.txt NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt.conflict1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt.conflict2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict2 INFO : - Path2 Queue copy to Path1 - {path1/}file6.txt INFO : - Path1 Queue copy to Path2 - {path2/}file7.txt INFO : - Path2 Queue copy to Path1 - {path1/}file1.txt diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que index 5725b8184..74c4ff68a 100644 --- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -1,5 +1,5 @@ "file11.txt" "file2.txt" "file4.txt" -"file5.txt..path1" +"file5.txt.conflict1" "file7.txt" diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que index 3b79e78bd..8097bfd9d 100644 --- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -1,5 +1,5 @@ "file1.txt" "file10.txt" "file3.txt" -"file5.txt..path2" +"file5.txt.conflict2" "file6.txt" diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst +++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path1.lst @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst +++ b/cmd/bisync/testdata/test_changes/golden/_testdir_path1.._testdir_path2.path2.lst @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_changes/golden/test.log b/cmd/bisync/testdata/test_changes/golden/test.log index 3d678b67a..535042521 100644 --- a/cmd/bisync/testdata/test_changes/golden/test.log +++ b/cmd/bisync/testdata/test_changes/golden/test.log @@ -101,10 +101,10 @@ INFO : - Path1 Queue copy to Path2 - { INFO : - Path1 Queue copy to Path2 - {path2/}file2.txt INFO : - Path2 Queue delete - {path2/}file4.txt NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt.conflict1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt.conflict2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict2 INFO : - Path2 Queue copy to Path1 - {path1/}file6.txt INFO : - Path1 Queue copy to Path2 - {path2/}file7.txt INFO : - Path2 Queue copy to Path1 - {path1/}file1.txt diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que index 5725b8184..74c4ff68a 100644 --- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -1,5 +1,5 @@ "file11.txt" "file2.txt" "file4.txt" -"file5.txt..path1" +"file5.txt.conflict1" "file7.txt" diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que index 3b79e78bd..8097bfd9d 100644 --- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -1,5 +1,5 @@ "file1.txt" "file10.txt" "file3.txt" -"file5.txt..path2" +"file5.txt.conflict2" "file6.txt" diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst index ddb01f4a7..c691a789b 100644 --- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst +++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path1.lst @@ -4,7 +4,7 @@ - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 md5:fb3ecfb2800400fb01b0bfd39903e9fb - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst index ddb01f4a7..c691a789b 100644 --- a/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst +++ b/cmd/bisync/testdata/test_compare_all/golden/_testdir_path1.._testdir_path2.path2.lst @@ -4,7 +4,7 @@ - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 md5:fb3ecfb2800400fb01b0bfd39903e9fb - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 md5:0860a03592626642f8fd6c8bfb447d2a - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 md5:979a803b15d27df0c31ad7d29006d10b - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 md5:7fe98ed88552b828777d8630900346b8 - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_compare_all/golden/test.log b/cmd/bisync/testdata/test_compare_all/golden/test.log index fc2674d79..760cb69f6 100644 --- a/cmd/bisync/testdata/test_compare_all/golden/test.log +++ b/cmd/bisync/testdata/test_compare_all/golden/test.log @@ -94,10 +94,10 @@ INFO : - Path1 Queue copy to Path2 - { INFO : - Path1 Queue copy to Path2 - {path2/}file2.txt INFO : - Path2 Queue delete - {path2/}file4.txt NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt.conflict1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt.conflict2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict2 INFO : - Path2 Queue copy to Path1 - {path1/}file6.txt INFO : - Path1 Queue copy to Path2 - {path2/}file7.txt INFO : - Path2 Queue copy to Path1 - {path1/}file1.txt diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que index 5725b8184..74c4ff68a 100644 --- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -1,5 +1,5 @@ "file11.txt" "file2.txt" "file4.txt" -"file5.txt..path1" +"file5.txt.conflict1" "file7.txt" diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que index 3b79e78bd..8097bfd9d 100644 --- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -1,5 +1,5 @@ "file1.txt" "file10.txt" "file3.txt" -"file5.txt..path2" +"file5.txt.conflict2" "file6.txt" diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst +++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path1.lst @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst index 19e9623a5..28bcb7af7 100644 --- a/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst +++ b/cmd/bisync/testdata/test_dry_run/golden/_testdir_path1.._testdir_path2.path2.lst @@ -4,7 +4,7 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "file10.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file11.txt" - 13 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file6.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "file7.txt" diff --git a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que index 5725b8184..74c4ff68a 100644 --- a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy1to2.que @@ -1,5 +1,5 @@ "file11.txt" "file2.txt" "file4.txt" -"file5.txt..path1" +"file5.txt.conflict1" "file7.txt" diff --git a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que index 3b79e78bd..8097bfd9d 100644 --- a/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_dry_run/golden/dryrun._testdir_path1.._testdir_path2.copy2to1.que @@ -1,5 +1,5 @@ "file1.txt" "file10.txt" "file3.txt" -"file5.txt..path2" +"file5.txt.conflict2" "file6.txt" diff --git a/cmd/bisync/testdata/test_dry_run/golden/test.log b/cmd/bisync/testdata/test_dry_run/golden/test.log index 1736942d4..9b5f48d90 100644 --- a/cmd/bisync/testdata/test_dry_run/golden/test.log +++ b/cmd/bisync/testdata/test_dry_run/golden/test.log @@ -123,12 +123,10 @@ INFO : - Path1 Queue copy to Path2 - { INFO : - Path1 Queue copy to Path2 - {path2/}file2.txt INFO : - Path2 Queue delete - {path2/}file4.txt NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: file5.txt: Skipped move as --dry-run is set (size 39) -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: file5.txt: Skipped move as --dry-run is set (size 39) -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: file5.txt: Skipped rename as --dry-run is set +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict1 +NOTICE: file5.txt: Skipped rename as --dry-run is set +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict2 INFO : - Path2 Queue copy to Path1 - {path1/}file6.txt INFO : - Path1 Queue copy to Path2 - {path2/}file7.txt INFO : - Path2 Queue copy to Path1 - {path1/}file1.txt @@ -190,10 +188,10 @@ INFO : - Path1 Queue copy to Path2 - { INFO : - Path1 Queue copy to Path2 - {path2/}file2.txt INFO : - Path2 Queue delete - {path2/}file4.txt NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt.conflict1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt.conflict2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict2 INFO : - Path2 Queue copy to Path1 - {path1/}file6.txt INFO : - Path1 Queue copy to Path2 - {path2/}file7.txt INFO : - Path2 Queue copy to Path1 - {path1/}file1.txt diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que index d988a5ab1..91974e009 100644 --- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -1 +1 @@ -"file1.txt..path1" +"file1.txt.conflict1" diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que index 7f99cd1ce..172a192aa 100644 --- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -1 +1 @@ -"file1.txt..path2" +"file1.txt.conflict2" diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst index 3e93d92de..2e181c871 100644 --- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst +++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path1.lst @@ -1,5 +1,5 @@ # bisync listing v1 from test - 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" -- 33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt..path1" -- 33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt.conflict1" +- 33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt.conflict2" - 37 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" diff --git a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst index 3e93d92de..2e181c871 100644 --- a/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst +++ b/cmd/bisync/testdata/test_equal/golden/_testdir_path1.._testdir_path2.path2.lst @@ -1,5 +1,5 @@ # bisync listing v1 from test - 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" -- 33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt..path1" -- 33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2001-03-04T00:00:00.000000000+0000 "file1.txt.conflict1" +- 33 - - 2001-01-02T00:00:00.000000000+0000 "file1.txt.conflict2" - 37 - - 2001-01-02T00:00:00.000000000+0000 "file2.txt" diff --git a/cmd/bisync/testdata/test_equal/golden/test.log b/cmd/bisync/testdata/test_equal/golden/test.log index e496bc95e..f52018acd 100644 --- a/cmd/bisync/testdata/test_equal/golden/test.log +++ b/cmd/bisync/testdata/test_equal/golden/test.log @@ -63,10 +63,10 @@ NOTICE: {path2String}: 1 errors while checking NOTICE: {path2String}: 1 matching files INFO : Finished checking the potential conflicts. 1 differences found NOTICE: - WARNING New or changed in both paths - file1.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file1.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file1.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file1.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file1.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file1.txt.conflict1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file1.txt.conflict1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file1.txt.conflict2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file1.txt.conflict2 NOTICE: - WARNING New or changed in both paths - file2.txt INFO : Files are equal! Skipping: file2.txt INFO : - Path2 Do queued copies to - Path1 diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que index 75c663f86..390061065 100644 --- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -1,6 +1,6 @@ "file1_with white space.txt" "filename_contains_ࢺ_p1m.txt" "subdir_with_ࢺ_/file_with_測試_.txt" -"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1" +"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1" "subdir_with_ࢺ_/mañana_funcionará.txt" "subdir_with_ࢺ_/test.txt" diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que index 5c39d3955..cd4932019 100644 --- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -3,7 +3,7 @@ "filename_contains_ࢺ_.txt" "subdir with␊white space.txt/file2 with␊white space.txt" "subdir_rawchars_␙_\x81_\xfe/file3_␙_\x81_\xfe" -"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2" +"subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2" "subdir_with_ࢺ_/filename_contains_ě_.txt" "subdir_with_ࢺ_/filename_contains_ࢺ_p2s.txt" "Русский.txt" diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst index 348c62c3d..619c3a8a2 100644 --- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst +++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path1.lst @@ -11,8 +11,8 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir with␊white space.txt/file2 with␊white space.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_rawchars_␙_\x81_\xfe/file3_␙_\x81_\xfe" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/file_with_測試_.txt" -- 19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1" -- 42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2" +- 19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1" +- 42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2" - 272 - - 2000-01-01T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_p2s.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/mañana_funcionará.txt" diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst index 348c62c3d..619c3a8a2 100644 --- a/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst +++ b/cmd/bisync/testdata/test_extended_filenames/golden/_testdir_path1.._testdir_path2.path2.lst @@ -11,8 +11,8 @@ - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir with␊white space.txt/file2 with␊white space.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_rawchars_␙_\x81_\xfe/file3_␙_\x81_\xfe" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/file_with_測試_.txt" -- 19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1" -- 42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2" +- 19 - - 2001-01-03T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1" +- 42 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2" - 272 - - 2000-01-01T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/filename_contains_ࢺ_p2s.txt" - 19 - - 2001-01-02T00:00:00.000000000+0000 "subdir_with_ࢺ_/mañana_funcionará.txt" diff --git a/cmd/bisync/testdata/test_extended_filenames/golden/test.log b/cmd/bisync/testdata/test_extended_filenames/golden/test.log index 5f5e31959..25bf9ea43 100644 --- a/cmd/bisync/testdata/test_extended_filenames/golden/test.log +++ b/cmd/bisync/testdata/test_extended_filenames/golden/test.log @@ -96,10 +96,10 @@ INFO : - Path1 Queue copy to Path2 - { INFO : - Path1 Queue copy to Path2 - {path2/}filename_contains_ࢺ_p1m.txt INFO : - Path1 Queue copy to Path2 - {path2/}subdir_with_ࢺ_/file_with_測試_.txt NOTICE: - WARNING New or changed in both paths - subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}subdir_with_ࢺ_/filechangedbothpaths_ࢺ_.txt.conflict2 INFO : - Path1 Queue copy to Path2 - {path2/}subdir_with_ࢺ_/mañana_funcionará.txt INFO : - Path1 Queue copy to Path2 - {path2/}subdir_with_ࢺ_/test.txt INFO : - Path2 Queue copy to Path1 - {path1/}Русский.txt diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy1to2.que new file mode 100644 index 000000000..029f3e190 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -0,0 +1 @@ +"file1.txt" diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy2to1.que new file mode 100644 index 000000000..9ed593ba3 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -0,0 +1 @@ +"file2.txt" diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst new file mode 100644 index 000000000..57872a027 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst @@ -0,0 +1,10 @@ +# bisync listing v1 from test +- 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" +- 33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1" +- 33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1" +- 33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1" diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-new b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-new new file mode 100644 index 000000000..454d9344c --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-new @@ -0,0 +1,11 @@ +# bisync listing v1 from test +- 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" +- 33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1" +- 33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1" +- 33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1" +- 33 - - 2005-01-02T00:00:00.000000000+0000 "file2.txt" diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-old b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-old new file mode 100644 index 000000000..2779be7ab --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path1.lst-old @@ -0,0 +1,10 @@ +# bisync listing v1 from test +- 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1" +- 33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1" +- 33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1" +- 0 - - 2000-01-01T00:00:00.000000000+0000 "file2.txt" diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst new file mode 100644 index 000000000..57872a027 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst @@ -0,0 +1,10 @@ +# bisync listing v1 from test +- 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" +- 33 - - 2006-03-04T00:00:00.000000000+0000 "file1.txt" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1" +- 33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1" +- 33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1" diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-new b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-new new file mode 100644 index 000000000..8b02b6d6a --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-new @@ -0,0 +1,11 @@ +# bisync listing v1 from test +- 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" +- 33 - - 2005-01-02T00:00:00.000000000+0000 "file1.txt" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1" +- 33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1" +- 33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1" +- 33 - - 2006-03-04T00:00:00.000000000+0000 "file2.txt" diff --git a/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-old b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-old new file mode 100644 index 000000000..2779be7ab --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/_testdir_path1.._testdir_path2.path2.lst-old @@ -0,0 +1,10 @@ +# bisync listing v1 from test +- 109 - - 2000-01-01T00:00:00.000000000+0000 "RCLONE_TEST" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path1" +- 33 - - 2004-07-23T00:00:00.000000000+0000 "file1.txt..path2" +- 33 - - 2002-08-26T00:00:00.000000000+0000 "file1.txt.apple1" +- 33 - - 2002-07-23T00:00:00.000000000+0000 "file1.txt.apple2" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.cloud1" +- 33 - - 2001-08-26T00:00:00.000000000+0000 "file1.txt.dinosaur1" +- 33 - - 2003-07-23T00:00:00.000000000+0000 "file1.txt.local1" +- 0 - - 2000-01-01T00:00:00.000000000+0000 "file2.txt" diff --git a/cmd/bisync/testdata/test_resolve/golden/test.log b/cmd/bisync/testdata/test_resolve/golden/test.log new file mode 100644 index 000000000..a8e129259 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/golden/test.log @@ -0,0 +1,304 @@ +(01) : test resolve + + +(02) : test initial bisync +(03) : bisync resync +INFO : Setting --ignore-listing-checksum as neither --checksum nor --compare checksum are set. +INFO : Bisyncing with Comparison Settings: +{ +"Modtime": true, +"Size": true, +"Checksum": false, +"NoSlowHash": false, +"SlowHashSyncOnly": false, +"DownloadHash": false +} +INFO : Synching Path1 "{path1/}" with Path2 "{path2/}" +INFO : Copying unique Path2 files to Path1 +INFO : - Path2 Resync is copying UNIQUE files to - Path1 +INFO : - Path1 Resync is copying UNIQUE OR DIFFERING files to - Path2 +INFO : Resync updating listings +INFO : Bisync successful + +(04) : test changed on both paths and NOT identical - file1 (file1R, file1L) +(05) : touch-glob 2001-01-02 {datadir/} file1R.txt +(06) : copy-as {datadir/}file1R.txt {path2/} file1.txt +(07) : touch-glob 2001-03-04 {datadir/} file1L.txt +(08) : copy-as {datadir/}file1L.txt {path1/} file1.txt + +(09) : test bisync run with --conflict-resolve=newer --conflict-loser=delete --conflict-suffix=potato + +(10) : bisync conflict-resolve=newer conflict-loser=delete conflict-suffix=potato +INFO : Setting --ignore-listing-checksum as neither --checksum nor --compare checksum are set. +INFO : Bisyncing with Comparison Settings: +{ +"Modtime": true, +"Size": true, +"Checksum": false, +"NoSlowHash": false, +"SlowHashSyncOnly": false, +"DownloadHash": false +} +INFO : Synching Path1 "{path1/}" with Path2 "{path2/}" +INFO : Building Path1 and Path2 listings +INFO : Path1 checking for diffs +INFO : - Path1 File changed: size (larger), time (newer) - file1.txt +INFO : Path1: 1 changes:  0 new,  1 modified,  0 deleted +INFO : (Modified:  1 newer,  0 older,  1 larger,  0 smaller) +INFO : Path2 checking for diffs +INFO : - Path2 File changed: size (larger), time (newer) - file1.txt +INFO : Path2: 1 changes:  0 new,  1 modified,  0 deleted +INFO : (Modified:  1 newer,  0 older,  1 larger,  0 smaller) +INFO : Applying changes +INFO : Checking potential conflicts... +ERROR : file1.txt: md5 differ +NOTICE: {path2String}: 1 differences found +NOTICE: {path2String}: 1 errors while checking +INFO : Finished checking the potential conflicts. 1 differences found +NOTICE: - WARNING New or changed in both paths - file1.txt +INFO : file1.txt: Path1 is newer. Path1: 2001-03-04 00:00:00 +0000 UTC, Path2: 2001-01-02 00:00:00 +0000 UTC, Difference: 1464h0m0s +INFO : file1.txt: The winner is: Path1 +NOTICE: - Path2 Deleting Path2 copy - {path2/}file1.txt +INFO : - Path1 Queue copy to Path2 - file1.txt +INFO : - Path1 Do queued copies to - Path2 +INFO : Updating listings +INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}" +INFO : Bisync successful + +(11) : test changed on both paths and NOT identical - file1 (file1R, file1L) +(12) : touch-glob 2001-07-23 {datadir/} file1R.txt +(13) : copy-as {datadir/}file1R.txt {path2/} file1.txt +(14) : touch-glob 2001-08-26 {datadir/} file1L.txt +(15) : copy-as {datadir/}file1L.txt {path1/} file1.txt + +(16) : test bisync run with --conflict-resolve=path2 --conflict-loser=num --conflict-suffix=dinosaur + +(17) : bisync conflict-resolve=path2 conflict-loser=num conflict-suffix=dinosaur +INFO : Setting --ignore-listing-checksum as neither --checksum nor --compare checksum are set. +INFO : Bisyncing with Comparison Settings: +{ +"Modtime": true, +"Size": true, +"Checksum": false, +"NoSlowHash": false, +"SlowHashSyncOnly": false, +"DownloadHash": false +} +INFO : Synching Path1 "{path1/}" with Path2 "{path2/}" +INFO : Building Path1 and Path2 listings +INFO : Path1 checking for diffs +INFO : - Path1 File changed: time (newer) - file1.txt +INFO : Path1: 1 changes:  0 new,  1 modified,  0 deleted +INFO : (Modified:  1 newer,  0 older) +INFO : Path2 checking for diffs +INFO : - Path2 File changed: time (newer) - file1.txt +INFO : Path2: 1 changes:  0 new,  1 modified,  0 deleted +INFO : (Modified:  1 newer,  0 older) +INFO : Applying changes +INFO : Checking potential conflicts... +ERROR : file1.txt: md5 differ +NOTICE: {path2String}: 1 differences found +NOTICE: {path2String}: 1 errors while checking +INFO : Finished checking the potential conflicts. 1 differences found +NOTICE: - WARNING New or changed in both paths - file1.txt +INFO : file1.txt: The winner is: Path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file1.txt.dinosaur1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file1.txt.dinosaur1 +NOTICE: - Path2 Not renaming Path2 copy, as it was determined the winner - {path2/}file1.txt +NOTICE: - Path2 Queue copy to Path1 - {path1/}file1.txt +INFO : - Path2 Do queued copies to - Path1 +INFO : - Path1 Do queued copies to - Path2 +INFO : Updating listings +INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}" +INFO : Bisync successful + +(18) : test changed on both paths and NOT identical - file1 (file1R, file1L) +(19) : touch-glob 2002-07-23 {datadir/} file1R.txt +(20) : copy-as {datadir/}file1R.txt {path2/} file1.txt +(21) : touch-glob 2002-08-26 {datadir/} file1L.txt +(22) : copy-as {datadir/}file1L.txt {path1/} file1.txt + +(23) : test bisync run with --conflict-resolve=larger --conflict-loser=num --conflict-suffix=apple + +(24) : bisync conflict-resolve=larger conflict-loser=num conflict-suffix=apple +INFO : Setting --ignore-listing-checksum as neither --checksum nor --compare checksum are set. +INFO : Bisyncing with Comparison Settings: +{ +"Modtime": true, +"Size": true, +"Checksum": false, +"NoSlowHash": false, +"SlowHashSyncOnly": false, +"DownloadHash": false +} +INFO : Synching Path1 "{path1/}" with Path2 "{path2/}" +INFO : Building Path1 and Path2 listings +INFO : Path1 checking for diffs +INFO : - Path1 File is new - file1.txt +INFO : Path1: 1 changes:  1 new,  0 modified,  0 deleted +INFO : Path2 checking for diffs +INFO : - Path2 File is new - file1.txt +INFO : Path2: 1 changes:  1 new,  0 modified,  0 deleted +INFO : Applying changes +INFO : Checking potential conflicts... +ERROR : file1.txt: md5 differ +NOTICE: {path2String}: 1 differences found +NOTICE: {path2String}: 1 errors while checking +INFO : Finished checking the potential conflicts. 1 differences found +NOTICE: - WARNING New or changed in both paths - file1.txt +INFO : file1.txt: Winner cannot be determined as sizes are equal. Path1: 33, Path2: 33, Difference: 0 +INFO : file1.txt: A winner could not be determined. +NOTICE: - Path1 Renaming Path1 copy - {path1/}file1.txt.apple1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file1.txt.apple1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file1.txt.apple2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file1.txt.apple2 +INFO : - Path2 Do queued copies to - Path1 +INFO : - Path1 Do queued copies to - Path2 +INFO : Updating listings +INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}" +INFO : Bisync successful + +(25) : test different suffixes +(26) : touch-glob 2003-07-23 {datadir/} file1R.txt +(27) : copy-as {datadir/}file1R.txt {path2/} file1.txt +(28) : touch-glob 2003-07-23 {datadir/} file1L.txt +(29) : copy-as {datadir/}file1L.txt {path1/} file1.txt + +(30) : test bisync run with --conflict-resolve=older --conflict-loser=num --conflict-suffix=cloud,local + +(31) : bisync conflict-resolve=older conflict-loser=num conflict-suffix=cloud,local +INFO : Setting --ignore-listing-checksum as neither --checksum nor --compare checksum are set. +INFO : Bisyncing with Comparison Settings: +{ +"Modtime": true, +"Size": true, +"Checksum": false, +"NoSlowHash": false, +"SlowHashSyncOnly": false, +"DownloadHash": false +} +INFO : Synching Path1 "{path1/}" with Path2 "{path2/}" +INFO : Building Path1 and Path2 listings +INFO : Path1 checking for diffs +INFO : - Path1 File is new - file1.txt +INFO : Path1: 1 changes:  1 new,  0 modified,  0 deleted +INFO : Path2 checking for diffs +INFO : - Path2 File is new - file1.txt +INFO : Path2: 1 changes:  1 new,  0 modified,  0 deleted +INFO : Applying changes +INFO : Checking potential conflicts... +ERROR : file1.txt: md5 differ +NOTICE: {path2String}: 1 differences found +NOTICE: {path2String}: 1 errors while checking +INFO : Finished checking the potential conflicts. 1 differences found +NOTICE: - WARNING New or changed in both paths - file1.txt +INFO : file1.txt: Winner cannot be determined as times are equal. Path1: 2003-07-23 00:00:00 +0000 UTC, Path2: 2003-07-23 00:00:00 +0000 UTC, Difference: 0s +INFO : file1.txt: A winner could not be determined. +NOTICE: - Path1 Renaming Path1 copy - {path1/}file1.txt.cloud1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file1.txt.cloud1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file1.txt.local1 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file1.txt.local1 +INFO : - Path2 Do queued copies to - Path1 +INFO : - Path1 Do queued copies to - Path2 +INFO : Updating listings +INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}" +INFO : Bisync successful + +(32) : test legacy +(33) : touch-glob 2004-07-23 {datadir/} file1R.txt +(34) : copy-as {datadir/}file1R.txt {path2/} file1.txt +(35) : touch-glob 2004-07-23 {datadir/} file1L.txt +(36) : copy-as {datadir/}file1L.txt {path1/} file1.txt + +(37) : test bisync run with --conflict-resolve=none --conflict-loser=pathname --conflict-suffix=.path + +(38) : bisync conflict-resolve=none conflict-loser=pathname conflict-suffix=.path +INFO : Setting --ignore-listing-checksum as neither --checksum nor --compare checksum are set. +INFO : Bisyncing with Comparison Settings: +{ +"Modtime": true, +"Size": true, +"Checksum": false, +"NoSlowHash": false, +"SlowHashSyncOnly": false, +"DownloadHash": false +} +INFO : Synching Path1 "{path1/}" with Path2 "{path2/}" +INFO : Building Path1 and Path2 listings +INFO : Path1 checking for diffs +INFO : - Path1 File is new - file1.txt +INFO : Path1: 1 changes:  1 new,  0 modified,  0 deleted +INFO : Path2 checking for diffs +INFO : - Path2 File is new - file1.txt +INFO : Path2: 1 changes:  1 new,  0 modified,  0 deleted +INFO : Applying changes +INFO : Checking potential conflicts... +ERROR : file1.txt: md5 differ +NOTICE: {path2String}: 1 differences found +NOTICE: {path2String}: 1 errors while checking +INFO : Finished checking the potential conflicts. 1 differences found +NOTICE: - WARNING New or changed in both paths - file1.txt +NOTICE: - Path1 Renaming Path1 copy - {path1/}file1.txt..path1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file1.txt..path1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file1.txt..path2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file1.txt..path2 +INFO : - Path2 Do queued copies to - Path1 +INFO : - Path1 Do queued copies to - Path2 +INFO : Updating listings +INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}" +INFO : Bisync successful + +(39) : test deletes on both sides with default suffix +(40) : touch-glob 2005-01-02 {datadir/} file1R.txt +(41) : copy-as {datadir/}file1R.txt {path2/} file1.txt +(42) : copy-as {datadir/}file1R.txt {path1/} file2.txt +(43) : touch-glob 2006-03-04 {datadir/} file1L.txt +(44) : copy-as {datadir/}file1L.txt {path1/} file1.txt +(45) : copy-as {datadir/}file1L.txt {path2/} file2.txt + +(46) : test bisync run with --conflict-resolve=newer --conflict-loser=delete +(47) : bisync conflict-resolve=newer conflict-loser=delete +INFO : Setting --ignore-listing-checksum as neither --checksum nor --compare checksum are set. +INFO : Bisyncing with Comparison Settings: +{ +"Modtime": true, +"Size": true, +"Checksum": false, +"NoSlowHash": false, +"SlowHashSyncOnly": false, +"DownloadHash": false +} +INFO : Synching Path1 "{path1/}" with Path2 "{path2/}" +INFO : Building Path1 and Path2 listings +INFO : Path1 checking for diffs +INFO : - Path1 File changed: size (larger), time (newer) - file2.txt +INFO : - Path1 File is new - file1.txt +INFO : Path1: 2 changes:  1 new,  1 modified,  0 deleted +INFO : (Modified:  1 newer,  0 older,  1 larger,  0 smaller) +INFO : Path2 checking for diffs +INFO : - Path2 File changed: size (larger), time (newer) - file2.txt +INFO : - Path2 File is new - file1.txt +INFO : Path2: 2 changes:  1 new,  1 modified,  0 deleted +INFO : (Modified:  1 newer,  0 older,  1 larger,  0 smaller) +INFO : Applying changes +INFO : Checking potential conflicts... +ERROR : file1.txt: md5 differ +ERROR : file2.txt: md5 differ +NOTICE: {path2String}: 2 differences found +NOTICE: {path2String}: 2 errors while checking +INFO : Finished checking the potential conflicts. 2 differences found +NOTICE: - WARNING New or changed in both paths - file1.txt +INFO : file1.txt: Path1 is newer. Path1: 2006-03-04 00:00:00 +0000 UTC, Path2: 2005-01-02 00:00:00 +0000 UTC, Difference: 10224h0m0s +INFO : file1.txt: The winner is: Path1 +NOTICE: - Path2 Deleting Path2 copy - {path2/}file1.txt +INFO : - Path1 Queue copy to Path2 - file1.txt +NOTICE: - WARNING New or changed in both paths - file2.txt +INFO : file2.txt: Path2 is newer. Path1: 2005-01-02 00:00:00 +0000 UTC, Path2: 2006-03-04 00:00:00 +0000 UTC, Difference: 10224h0m0s +INFO : file2.txt: The winner is: Path2 +NOTICE: - Path1 Deleting Path1 copy - {path1/}file2.txt +INFO : - Path2 Queue copy to Path1 - file2.txt +INFO : - Path2 Do queued copies to - Path1 +INFO : - Path1 Do queued copies to - Path2 +INFO : Updating listings +INFO : Validating listings for Path1 "{path1/}" vs Path2 "{path2/}" +INFO : Bisync successful diff --git a/cmd/bisync/testdata/test_resolve/initial/RCLONE_TEST b/cmd/bisync/testdata/test_resolve/initial/RCLONE_TEST new file mode 100644 index 000000000..d8ca97c2a --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/initial/RCLONE_TEST @@ -0,0 +1 @@ +This file is used for testing the health of rclone accesses to the local/remote file system. Do not delete. diff --git a/cmd/bisync/testdata/test_resolve/initial/file1.txt b/cmd/bisync/testdata/test_resolve/initial/file1.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/bisync/testdata/test_resolve/initial/file2.txt b/cmd/bisync/testdata/test_resolve/initial/file2.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/bisync/testdata/test_resolve/modfiles/file1L.txt b/cmd/bisync/testdata/test_resolve/modfiles/file1L.txt new file mode 100644 index 000000000..6906ccb09 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/modfiles/file1L.txt @@ -0,0 +1 @@ +This file is NOT identical to 1R diff --git a/cmd/bisync/testdata/test_resolve/modfiles/file1R.txt b/cmd/bisync/testdata/test_resolve/modfiles/file1R.txt new file mode 100644 index 000000000..e49d06a94 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/modfiles/file1R.txt @@ -0,0 +1 @@ +This file is NOT identical to 1L diff --git a/cmd/bisync/testdata/test_resolve/modfiles/file2.txt b/cmd/bisync/testdata/test_resolve/modfiles/file2.txt new file mode 100644 index 000000000..2ee5fc1ee --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/modfiles/file2.txt @@ -0,0 +1 @@ +This file is identical on both sides diff --git a/cmd/bisync/testdata/test_resolve/scenario.txt b/cmd/bisync/testdata/test_resolve/scenario.txt new file mode 100644 index 000000000..1e72757f7 --- /dev/null +++ b/cmd/bisync/testdata/test_resolve/scenario.txt @@ -0,0 +1,67 @@ +test resolve +# Check conflict-resolution options +# - Changed on Path2 and on Path1, and NOT identical file1 (file1r, file1l) + +test initial bisync +bisync resync + +test changed on both paths and NOT identical - file1 (file1R, file1L) +touch-glob 2001-01-02 {datadir/} file1R.txt +copy-as {datadir/}file1R.txt {path2/} file1.txt +touch-glob 2001-03-04 {datadir/} file1L.txt +copy-as {datadir/}file1L.txt {path1/} file1.txt + +test bisync run with --conflict-resolve=newer --conflict-loser=delete --conflict-suffix=potato +# result should be "file1.txt", "file1.txt" (no potato) +bisync conflict-resolve=newer conflict-loser=delete conflict-suffix=potato + +test changed on both paths and NOT identical - file1 (file1R, file1L) +touch-glob 2001-07-23 {datadir/} file1R.txt +copy-as {datadir/}file1R.txt {path2/} file1.txt +touch-glob 2001-08-26 {datadir/} file1L.txt +copy-as {datadir/}file1L.txt {path1/} file1.txt + +test bisync run with --conflict-resolve=path2 --conflict-loser=num --conflict-suffix=dinosaur +# result should be "file1.txt.dinosaur1", "file1.txt" +bisync conflict-resolve=path2 conflict-loser=num conflict-suffix=dinosaur + +test changed on both paths and NOT identical - file1 (file1R, file1L) +touch-glob 2002-07-23 {datadir/} file1R.txt +copy-as {datadir/}file1R.txt {path2/} file1.txt +touch-glob 2002-08-26 {datadir/} file1L.txt +copy-as {datadir/}file1L.txt {path1/} file1.txt + +test bisync run with --conflict-resolve=larger --conflict-loser=num --conflict-suffix=apple +# result should be no winner -- "file1.txt.apple1", "file1.txt.apple2" +bisync conflict-resolve=larger conflict-loser=num conflict-suffix=apple + +test different suffixes +touch-glob 2003-07-23 {datadir/} file1R.txt +copy-as {datadir/}file1R.txt {path2/} file1.txt +touch-glob 2003-07-23 {datadir/} file1L.txt +copy-as {datadir/}file1L.txt {path1/} file1.txt + +test bisync run with --conflict-resolve=older --conflict-loser=num --conflict-suffix=cloud,local +# result should be no winner -- "file1.txt.cloud1", "file1.txt.local1" +bisync conflict-resolve=older conflict-loser=num conflict-suffix=cloud,local + +test legacy +touch-glob 2004-07-23 {datadir/} file1R.txt +copy-as {datadir/}file1R.txt {path2/} file1.txt +touch-glob 2004-07-23 {datadir/} file1L.txt +copy-as {datadir/}file1L.txt {path1/} file1.txt + +test bisync run with --conflict-resolve=none --conflict-loser=pathname --conflict-suffix=.path +# result should be no winner -- "file1.txt..path1", "file1.txt..path2" +bisync conflict-resolve=none conflict-loser=pathname conflict-suffix=.path + +test deletes on both sides with default suffix +touch-glob 2005-01-02 {datadir/} file1R.txt +copy-as {datadir/}file1R.txt {path2/} file1.txt +copy-as {datadir/}file1R.txt {path1/} file2.txt +touch-glob 2006-03-04 {datadir/} file1L.txt +copy-as {datadir/}file1L.txt {path1/} file1.txt +copy-as {datadir/}file1L.txt {path2/} file2.txt + +test bisync run with --conflict-resolve=newer --conflict-loser=delete +bisync conflict-resolve=newer conflict-loser=delete \ No newline at end of file diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que index cc3b08914..185e98b18 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy1to2.que @@ -1 +1 @@ -"file5.txt..path1" +"file5.txt.conflict5" diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que index 8457cd213..68562bb61 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.copy2to1.que @@ -1 +1 @@ -"file5.txt..path2" +"file5.txt.conflict6" diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst index 1a9f106fc..5c8d754bb 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst @@ -46,8 +46,12 @@ - 19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict5" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict6" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt" diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new index 9adf42243..18bfbb3d0 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-new @@ -47,8 +47,10 @@ - 19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt" - 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt" diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old index 1a9f106fc..8190c0300 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path1.lst-old @@ -46,8 +46,10 @@ - 19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt" diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst index 1a9f106fc..5c8d754bb 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst @@ -46,8 +46,12 @@ - 19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict5" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict6" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt" diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new index a8ce37fdc..968eeeae6 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-new @@ -47,8 +47,10 @@ - 19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt" - 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt" diff --git a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old index 1a9f106fc..8190c0300 100644 --- a/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old +++ b/cmd/bisync/testdata/test_volatile/golden/_testdir_path1.._testdir_path2.path2.lst-old @@ -46,8 +46,10 @@ - 19 - - 2023-08-26T00:00:00.000000000+0000 "file47.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file48.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file49.txt" -- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt..path1" -- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt..path2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict1" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict2" +- 39 - - 2001-03-04T00:00:00.000000000+0000 "file5.txt.conflict3" +- 39 - - 2001-01-02T00:00:00.000000000+0000 "file5.txt.conflict4" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file51.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file52.txt" - 19 - - 2023-08-26T00:00:00.000000000+0000 "file53.txt" diff --git a/cmd/bisync/testdata/test_volatile/golden/test.log b/cmd/bisync/testdata/test_volatile/golden/test.log index 7facb5980..d8af65a78 100644 --- a/cmd/bisync/testdata/test_volatile/golden/test.log +++ b/cmd/bisync/testdata/test_volatile/golden/test.log @@ -56,10 +56,10 @@ NOTICE: {path2String}: 1 differences found NOTICE: {path2String}: 1 errors while checking INFO : Finished checking the potential conflicts. 1 differences found NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt.conflict1 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict1 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt.conflict2 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict2 INFO : - Path2 Do queued copies to - Path1 INFO : - Path1 Do queued copies to - Path2 INFO : Updating listings @@ -201,10 +201,10 @@ NOTICE: {path2String}: 1 errors while checking INFO : Finished checking the potential conflicts. 1 differences found INFO : - Path1 Queue copy to Path2 - {path2/}file100.txt NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt.conflict3 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict3 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt.conflict4 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict4 INFO : - Path1 Queue copy to Path2 - {path2/}file51.txt INFO : - Path1 Queue copy to Path2 - {path2/}file52.txt INFO : - Path1 Queue copy to Path2 - {path2/}file53.txt @@ -343,10 +343,10 @@ NOTICE: {path2String}: 1 differences found NOTICE: {path2String}: 1 errors while checking INFO : Finished checking the potential conflicts. 1 differences found NOTICE: - WARNING New or changed in both paths - file5.txt -NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt..path1 -NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt..path1 -NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt..path2 -NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt..path2 +NOTICE: - Path1 Renaming Path1 copy - {path1/}file5.txt.conflict5 +NOTICE: - Path1 Queue copy to Path2 - {path2/}file5.txt.conflict5 +NOTICE: - Path2 Renaming Path2 copy - {path2/}file5.txt.conflict6 +NOTICE: - Path2 Queue copy to Path1 - {path1/}file5.txt.conflict6 INFO : - Path2 Do queued copies to - Path1 INFO : - Path1 Do queued copies to - Path2 INFO : Updating listings diff --git a/docs/content/bisync.md b/docs/content/bisync.md index 84b4a8735..a4ac4772c 100644 --- a/docs/content/bisync.md +++ b/docs/content/bisync.md @@ -422,6 +422,152 @@ of the current filters file and compares it to the hash stored in the `.md5` fil If they don't match, the run aborts with a critical error and thus forces you to do a `--resync`, likely avoiding a disaster. +### --conflict-resolve CHOICE {#conflict-resolve} + +In bisync, a "conflict" is a file that is *new* or *changed* on *both sides* +(relative to the prior run) AND is *not currently identical* on both sides. +`--conflict-resolve` controls how bisync handles such a scenario. The currently +supported options are: + +- `none` - (the default) - do not attempt to pick a winner, keep and rename +both files according to [`--conflict-loser`](#conflict-loser) and +[`--conflict-suffix`](#conflict-suffix) settings. For example, with the default +settings, `file.txt` on Path1 is renamed `file.txt.conflict1` and `file.txt` on +Path2 is renamed `file.txt.conflict2`. Both are copied to the opposite path +during the run, so both sides end up with a copy of both files. (As `none` is +the default, it is not necessary to specify `--conflict-resolve none` -- you +can just omit the flag.) +- `newer` - the newer file (by `modtime`) is considered the winner and is +copied without renaming. The older file (the "loser") is handled according to +`--conflict-loser` and `--conflict-suffix` settings (either renamed or +deleted.) For example, if `file.txt` on Path1 is newer than `file.txt` on +Path2, the result on both sides (with other default settings) will be `file.txt` +(winner from Path1) and `file.txt.conflict1` (loser from Path2). +- `older` - same as `newer`, except the older file is considered the winner, +and the newer file is considered the loser. +- `larger` - the larger file (by `size`) is considered the winner (regardless +of `modtime`, if any). +- `smaller` - the smaller file (by `size`) is considered the winner (regardless +of `modtime`, if any). +- `path1` - the version from Path1 is unconditionally considered the winner +(regardless of `modtime` and `size`, if any). This can be useful if one side is +usually more trusted or up-to-date than the other. +- `path2` - same as `path1`, except the path2 version is considered the +winner. + +For all of the above options, note the following: +- If either of the underlying remotes lacks support for the chosen method, it +will be ignored and fall back to `none`. (For example, if `--conflict-resolve +newer` is set, but one of the paths uses a remote that doesn't support +`modtime`.) +- If a winner can't be determined because the chosen method's attribute is +missing or equal, it will be ignored and fall back to `none`. (For example, if +`--conflict-resolve newer` is set, but the Path1 and Path2 modtimes are +identical, even if the sizes may differ.) +- If the file's content is currently identical on both sides, it is not +considered a "conflict", even if new or changed on both sides since the prior +sync. (For example, if you made a change on one side and then synced it to the +other side by other means.) Therefore, none of the conflict resolution flags +apply in this scenario. +- The conflict resolution flags do not apply during a `--resync`, as there is +no "prior run" to speak of (but see [`--resync-mode`](#resync-mode) for similar +options.) + +### --conflict-loser CHOICE {#conflict-loser} + +`--conflict-loser` determines what happens to the "loser" of a sync conflict +(when [`--conflict-resolve`](#conflict-resolve) determines a winner) or to both +files (when there is no winner.) The currently supported options are: + +- `num` - (the default) - auto-number the conflicts by automatically appending +the next available number to the `--conflict-suffix`, in chronological order. +For example, with the default settings, the first conflict for `file.txt` will +be renamed `file.txt.conflict1`. If `file.txt.conflict1` already exists, +`file.txt.conflict2` will be used instead (etc., up to a maximum of +9223372036854775807 conflicts.) +- `pathname` - rename the conflicts according to which side they came from, +which was the default behavior prior to `v1.66`. For example, with +`--conflict-suffix path`, `file.txt` from Path1 will be renamed +`file.txt.path1`, and `file.txt` from Path2 will be renamed `file.txt.path2`. +If two non-identical suffixes are provided (ex. `--conflict-suffix +cloud,local`), the trailing digit is omitted. Importantly, note that with +`pathname`, there is no auto-numbering beyond `2`, so if `file.txt.path2` +somehow already exists, it will be overwritten. Using a dynamic date variable +in your `--conflict-suffix` (see below) is one possible way to avoid this. Note +also that conflicts-of-conflicts are possible, if the original conflict is not +manually resolved -- for example, if for some reason you edited +`file.txt.path1` on both sides, and those edits were different, the result +would be `file.txt.path1.path1` and `file.txt.path1.path2` (in addition to +`file.txt.path2`.) +- `delete` - keep the winner only and delete the loser, instead of renaming it. +If a winner cannot be determined (see `--conflict-resolve` for details on how +this could happen), `delete` is ignored and the default `num` is used instead +(i.e. both versions are kept and renamed, and neither is deleted.) `delete` is +inherently the most destructive option, so use it only with care. + +For all of the above options, note that if a winner cannot be determined (see +`--conflict-resolve` for details on how this could happen), or if +`--conflict-resolve` is not in use, *both* files will be renamed. + +### --conflict-suffix STRING[,STRING] {#conflict-suffix} + +`--conflict-suffix` controls the suffix that is appended when bisync renames a +[`--conflict-loser`](#conflict-loser) (default: `conflict`). +`--conflict-suffix` will accept either one string or two comma-separated +strings to assign different suffixes to Path1 vs. Path2. This may be helpful +later in identifying the source of the conflict. (For example, +`--conflict-suffix dropboxconflict,laptopconflict`) + +With `--conflict-loser num`, a number is always appended to the suffix. With +`--conflict-loser pathname`, a number is appended only when one suffix is +specified (or when two identical suffixes are specified.) i.e. with +`--conflict-loser pathname`, all of the following would produce exactly the +same result: + +``` +--conflict-suffix path +--conflict-suffix path,path +--conflict-suffix path1,path2 +``` + +Suffixes may be as short as 1 character. By default, the suffix is appended +after any other extensions (ex. `file.jpg.conflict1`), however, this can be +changed with the [`--suffix-keep-extension`](/docs/#suffix-keep-extension) flag +(i.e. to instead result in `file.conflict1.jpg`). + +`--conflict-suffix` supports several *dynamic date variables* when enclosed in +curly braces as globs. This can be helpful to track the date and/or time that +each conflict was handled by bisync. For example: + +``` +--conflict-suffix {DateOnly}-conflict +// result: myfile.txt.2006-01-02-conflict1 +``` + +All of the formats described [here](https://pkg.go.dev/time#pkg-constants) and +[here](https://pkg.go.dev/time#example-Time.Format) are supported, but take +care to ensure that your chosen format does not use any characters that are +illegal on your remotes (for example, macOS does not allow colons in +filenames, and slashes are also best avoided as they are often interpreted as +directory separators.) To address this particular issue, an additional +`{MacFriendlyTime}` (or just `{mac}`) option is supported, which results in +`2006-01-02 0304PM`. + +Note that `--conflict-suffix` is entirely separate from rclone's main +[`--sufix`](/docs/#suffix-suffix) flag. This is intentional, as users may wish +to use both flags simultaneously, if also using +[`--backup-dir`](#backup-dir1-and-backup-dir2). + +Finally, note that the default in bisync prior to `v1.66` was to rename +conflicts with `..path1` and `..path2` (with two periods, and `path` instead of +`conflict`.) Bisync now defaults to a single dot instead of a double dot, but +additional dots can be added by including them in the specified suffix string. +For example, for behavior equivalent to the previous default, use: + +``` +[--conflict-resolve none] --conflict-loser pathname --conflict-suffix .path +``` + ### --check-sync Enabled by default, the check-sync function checks that all of the same @@ -610,7 +756,7 @@ the other side by moving the corresponding file from `gdrive:Bisync` to moves it from `/Users/someuser/some/local/path/Bisync` to `/Users/someuser/some/local/path/BackupDir`. -In the event of a `..path1` / `..path2` rename due to a sync conflict, the +In the event of a [rename due to a sync conflict](#conflict-loser), the rename is not considered a delete, unless a previous conflict with the same name already exists and would get overwritten. @@ -634,7 +780,8 @@ On each successive run it will: - Lock file prevents multiple simultaneous runs when taking a while. This can be particularly useful if bisync is run by cron scheduler. - Handle change conflicts non-destructively by creating - `..path1` and `..path2` file versions. + `.conflict1`, `.conflict2`, etc. file versions, according to + [`--conflict-resolve`](#conflict-resolve), [`--conflict-loser`](#conflict-loser), and [`--conflict-suffix`](#conflict-suffix) settings. - File system access health check using `RCLONE_TEST` files (see the `--check-access` flag). - Abort on excessive deletes - protects against a failed listing @@ -661,8 +808,8 @@ Path1 deleted | File no longer exists on Path1 | File is deleted Type | Description | Result | Implementation --------------------------------|---------------------------------------|------------------------------------|----------------------- Path1 new/changed AND Path2 new/changed AND Path1 == Path2 | File is new/changed on Path1 AND new/changed on Path2 AND Path1 version is currently identical to Path2 | No change | None -Path1 new AND Path2 new | File is new on Path1 AND new on Path2 (and Path1 version is NOT identical to Path2) | Files renamed to _Path1 and _Path2 | `rclone copy` _Path2 file to Path1, `rclone copy` _Path1 file to Path2 -Path2 newer AND Path1 changed | File is newer on Path2 AND also changed (newer/older/size) on Path1 (and Path1 version is NOT identical to Path2) | Files renamed to _Path1 and _Path2 | `rclone copy` _Path2 file to Path1, `rclone copy` _Path1 file to Path2 +Path1 new AND Path2 new | File is new on Path1 AND new on Path2 (and Path1 version is NOT identical to Path2) | Conflicts handled according to [`--conflict-resolve`](#conflict-resolve) & [`--conflict-loser`](#conflict-loser) settings | default: `rclone copy` renamed `Path2.conflict2` file to Path1, `rclone copy` renamed `Path1.conflict1` file to Path2 +Path2 newer AND Path1 changed | File is newer on Path2 AND also changed (newer/older/size) on Path1 (and Path1 version is NOT identical to Path2) | Conflicts handled according to [`--conflict-resolve`](#conflict-resolve) & [`--conflict-loser`](#conflict-loser) settings | default: `rclone copy` renamed `Path2.conflict2` file to Path1, `rclone copy` renamed `Path1.conflict1` file to Path2 Path2 newer AND Path1 deleted | File is newer on Path2 AND also deleted on Path1 | Path2 version survives | `rclone copy` Path2 to Path1 Path2 deleted AND Path1 changed | File is deleted on Path2 AND changed (newer/older/size) on Path1 | Path1 version survives |`rclone copy` Path1 to Path2 Path1 deleted AND Path2 changed | File is deleted on Path1 AND changed (newer/older/size) on Path2 | Path2 version survives | `rclone copy` Path2 to Path1 @@ -673,7 +820,7 @@ Now, when bisync comes to a file that it wants to rename (because it is new/chan it first checks whether the Path1 and Path2 versions are currently *identical* (using the same underlying function as [`check`](commands/rclone_check/).) If bisync concludes that the files are identical, it will skip them and move on. -Otherwise, it will create renamed `..Path1` and `..Path2` duplicates, as before. +Otherwise, it will create renamed duplicates, as before. This behavior also [improves the experience of renaming directories](https://forum.rclone.org/t/bisync-bugs-and-feature-requests/37636#:~:text=Renamed%20directories), as a `--resync` is no longer required, so long as the same change has been made on both sides. @@ -1604,6 +1751,7 @@ instead of of `--size-only`, when `check` is not available. * Bisync now supports a "Graceful Shutdown" mode to cleanly cancel a run early without requiring `--resync`. * New `--recover` flag allows robust recovery in the event of interruptions, without requiring `--resync`. * A new `--max-lock` setting allows lock files to automatically renew and expire, for better automatic recovery when a run is interrupted. +* Bisync now supports auto-resolving sync conflicts and customizing rename behavior with new [`--conflict-resolve`](#conflict-resolve), [`--conflict-loser`](#conflict-loser), and [`--conflict-suffix`](#conflict-suffix) flags. ### `v1.64` * Fixed an [issue](https://forum.rclone.org/t/bisync-bugs-and-feature-requests/37636#:~:text=1.%20Dry%20runs%20are%20not%20completely%20dry)