978cbf9360
Before this change, if there were changes to sync, bisync listed each path twice: once before the sync and once after. The second listing caused quite a lot of problems, in addition to making each run much slower and more expensive. A serious side-effect was that file changes could slip through undetected, if they happened to occur while a sync was running (between the first and second listing snapshots.) After this change, the second listing is eliminated by getting the underlying sync operation to report back a list of what it changed. Not only is this more efficient, but also much more robust to concurrent modifications. It should no longer be necessary to avoid make changes while it's running -- bisync will simply learn about those changes next time and handle them on the next run. Additionally, this also makes --check-sync usable again. For further discussion, see: https://forum.rclone.org/t/bisync-bugs-and-feature-requests/37636#:~:text=5.%20Final%20listings%20should%20be%20created%20from%20initial%20snapshot%20%2B%20deltas%2C%20not%20full%20re%2Dscans%2C%20to%20avoid%20errors%20if%20files%20changed%20during%20sync
42 lines
1 KiB
Go
42 lines
1 KiB
Go
// Package bilib provides common stuff for bisync and bisync_test
|
|
package bilib
|
|
|
|
import (
|
|
"os"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/rclone/rclone/fs"
|
|
)
|
|
|
|
// FsPath converts Fs to a suitable rclone argument
|
|
func FsPath(f fs.Info) string {
|
|
name, path, slash := f.Name(), f.Root(), "/"
|
|
if name == "local" {
|
|
slash = string(os.PathSeparator)
|
|
if runtime.GOOS == "windows" {
|
|
path = strings.ReplaceAll(path, "/", slash)
|
|
path = strings.TrimPrefix(path, `\\?\`)
|
|
}
|
|
} else {
|
|
path = name + ":" + path
|
|
}
|
|
if !strings.HasSuffix(path, slash) {
|
|
path += slash
|
|
}
|
|
return path
|
|
}
|
|
|
|
// CanonicalPath converts a remote to a suitable base file name
|
|
func CanonicalPath(remote string) string {
|
|
trimmed := strings.Trim(remote, `\/`)
|
|
return nonCanonicalChars.ReplaceAllString(trimmed, "_")
|
|
}
|
|
|
|
var nonCanonicalChars = regexp.MustCompile(`[\s\\/:?*]`)
|
|
|
|
// SessionName makes a unique base name for the sync operation
|
|
func SessionName(fs1, fs2 fs.Fs) string {
|
|
return CanonicalPath(FsPath(fs1)) + ".." + CanonicalPath(FsPath(fs2))
|
|
}
|