mirror of https://github.com/rclone/rclone.git
98 lines
3.1 KiB
Go
98 lines
3.1 KiB
Go
// Package bilib provides common stuff for bisync and bisync_test
|
|
package bilib
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fs/operations"
|
|
)
|
|
|
|
// 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 StripHexString(CanonicalPath(FsPath(fs1))) + ".." + StripHexString(CanonicalPath(FsPath(fs2)))
|
|
}
|
|
|
|
// StripHexString strips the (first) canonical {hexstring} suffix
|
|
func StripHexString(path string) string {
|
|
open := strings.IndexRune(path, '{')
|
|
close := strings.IndexRune(path, '}')
|
|
if open >= 0 && close > open {
|
|
return path[:open] + path[close+1:] // (trailing underscore)
|
|
}
|
|
return path
|
|
}
|
|
|
|
// HasHexString returns true if path contains at least one canonical {hexstring} suffix
|
|
func HasHexString(path string) bool {
|
|
open := strings.IndexRune(path, '{')
|
|
if open >= 0 && strings.IndexRune(path, '}') > open {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// BasePath joins the workDir with the SessionName, stripping {hexstring} suffix if necessary
|
|
func BasePath(ctx context.Context, workDir string, fs1, fs2 fs.Fs) string {
|
|
suffixedSession := CanonicalPath(FsPath(fs1)) + ".." + CanonicalPath(FsPath(fs2))
|
|
suffixedBasePath := filepath.Join(workDir, suffixedSession)
|
|
listing1 := suffixedBasePath + ".path1.lst"
|
|
listing2 := suffixedBasePath + ".path2.lst"
|
|
|
|
sessionName := SessionName(fs1, fs2)
|
|
basePath := filepath.Join(workDir, sessionName)
|
|
|
|
// Normalize to non-canonical version for overridden configs
|
|
// to ensure that backend-specific flags don't change the listing filename.
|
|
// For backward-compatibility, we first check if we found a listing file with the suffixed version.
|
|
// If so, we rename it (and overwrite non-suffixed version, if any.)
|
|
// If not, we carry on with the non-suffixed version.
|
|
// We should only find a suffixed version if bisync v1.66 or older created it.
|
|
if HasHexString(suffixedSession) && FileExists(listing1) {
|
|
fs.Infof(listing1, "renaming to: %s", basePath+".path1.lst")
|
|
if !operations.SkipDestructive(ctx, listing1, "rename to "+basePath+".path1.lst") {
|
|
_ = os.Rename(listing1, basePath+".path1.lst")
|
|
}
|
|
}
|
|
if HasHexString(suffixedSession) && FileExists(listing2) {
|
|
fs.Infof(listing2, "renaming to: %s", basePath+".path2.lst")
|
|
if !operations.SkipDestructive(ctx, listing1, "rename to "+basePath+".path2.lst") {
|
|
_ = os.Rename(listing2, basePath+".path2.lst")
|
|
} else {
|
|
return suffixedBasePath
|
|
}
|
|
}
|
|
return basePath
|
|
}
|