diff --git a/src/backend/2globalsUNIX.go b/src/backend/2globalsUNIX.go index 4b645c4..caafb97 100644 --- a/src/backend/2globalsUNIX.go +++ b/src/backend/2globalsUNIX.go @@ -10,5 +10,5 @@ var ConfigPath = ConfigDir + "/libmutton.ini" // PathSeparator defines the character used to separate directories in a path (platform-specific) const ( PathSeparator = "/" - Windows = false // TODO temporary, remove after native sync is implemented + IsWindows = false ) diff --git a/src/backend/2globalsWIN.go b/src/backend/2globalsWIN.go index 991bdc2..5b92a53 100644 --- a/src/backend/2globalsWIN.go +++ b/src/backend/2globalsWIN.go @@ -10,5 +10,5 @@ var ConfigPath = ConfigDir + "\\libmutton.ini" // PathSeparator defines the character used to separate directories in a path (platform-specific) const ( PathSeparator = "\\" - Windows = true // TODO temporary, remove after native sync is implemented + IsWindows = true ) diff --git a/src/sync/client.go b/src/sync/client.go index 6da3ab3..672f7b0 100644 --- a/src/sync/client.go +++ b/src/sync/client.go @@ -12,11 +12,6 @@ import ( "strings" ) -// TODO it is likely that all of this breaks on Windows, since the server returns unpredictable paths -// See what libmuttonserver fetch returns on Windows -// If the path separators are different, then we'll have to save the server OS during init and adjust accordingly -// I would prefer not to unnecessarily replace the path separators if syncing from Unix->Unix or Windows->Windows - // global constants used only in this file const ( ansiDelete = "\033[38;5;1m" @@ -159,7 +154,7 @@ func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []str fmt.Println(backend.AnsiError + "Sync failed - No device ID found; run \"mutn init\" to generate a device ID" + backend.AnsiReset) os.Exit(1) } - output := GetSSHOutput("libmuttonserver fetch "+clientDeviceID[0].Name(), manualSync) + output := GetSSHOutput("libmuttonserver fetch "+clientDeviceID[0].Name()+" "+strconv.FormatBool(backend.IsWindows), manualSync) // split output into slice based on occurrences of "\x1d" outputSlice := strings.Split(output, "\x1d") diff --git a/src/sync/common.go b/src/sync/common.go index a27221c..2d6118c 100644 --- a/src/sync/common.go +++ b/src/sync/common.go @@ -90,7 +90,7 @@ func Shear(targetLocationIncomplete string, deviceID string) { } } } - } else { // if running on the client... (online mode determined dynamically in GetSSHOutput, will silently exit if not in online mode) + } else { // if running on the client... (online mode determined dynamically in GetSSHOutput, will silently exit if not in online mode) // TODO separate into own function to avoid server needing to build SSH // determine client device ID (to send to server, avoids creating a deletion file for the client device) deviceID = deviceIDList[0].Name() // below: deviceID and targetLocationIncomplete are separated by \x1d, path separators are replaced with \x1e, and spaces are replaced with \x1f @@ -116,7 +116,7 @@ func AddFolder(targetLocationIncomplete string, onServer bool) { } } - if !onServer { // if running on the client... (online mode determined dynamically in GetSSHOutput, will silently exit if not in online mode) + if !onServer { // if running on the client... (online mode determined dynamically in GetSSHOutput, will silently exit if not in online mode) // TODO separate into own function to avoid server needing to build SSH GetSSHOutput("libmuttonserver addfolder "+strings.ReplaceAll(targetLocationIncomplete, " ", "\x1f"), false) } diff --git a/src/sync/server.go b/src/sync/server.go index 5a33c95..3c95d02 100644 --- a/src/sync/server.go +++ b/src/sync/server.go @@ -10,7 +10,7 @@ import ( // GetRemoteDataFromServer prints to stdout the remote entries, mod times, folders, and deletions // lists in output are separated by "\x1d" // output is meant to be captured over SSH for interpretation by the client -func GetRemoteDataFromServer(clientDeviceID string) { +func GetRemoteDataFromServer(clientDeviceID string, clientIsWindows bool) { entryList, dirList := WalkEntryDir() modList := getModTimes(entryList) deletionsList, err := os.ReadDir(backend.ConfigDir + backend.PathSeparator + "deletions") @@ -19,19 +19,36 @@ func GetRemoteDataFromServer(clientDeviceID string) { os.Exit(1) } - // print the lists to stdout - for _, entry := range entryList { - fmt.Print("\x1f" + entry) + // determine path separator expected by the client + var clientPathSeparator string + switch clientIsWindows { + case false: + clientPathSeparator = "/" + case true: + clientPathSeparator = "\\" } + + // print the lists to stdout + + // entry list + for _, entry := range entryList { + printWithClientPathSeparator(entry, clientPathSeparator, clientIsWindows) + } + + // modification time list fmt.Print("\x1d") for _, mod := range modList { fmt.Print("\x1f") fmt.Print(mod) } + + // directory/folder list fmt.Print("\x1d") for _, dir := range dirList { - fmt.Print("\x1f" + dir) + printWithClientPathSeparator(dir, clientPathSeparator, clientIsWindows) } + + // deletions list fmt.Print("\x1d") for _, deletion := range deletionsList { // print deletion if it is relevant to the current client device @@ -44,3 +61,13 @@ func GetRemoteDataFromServer(clientDeviceID string) { } } } + +// printWithClientPathSeparator prints the given string with the client's path separator +// it does not alter the string if the client and server are of the same OS family +func printWithClientPathSeparator(printable, clientPathSeparator string, clientIsWindows bool) { + if clientIsWindows == backend.IsWindows { + fmt.Print("\x1f" + printable) + } else { + fmt.Print("\x1f" + strings.ReplaceAll(printable, backend.PathSeparator, clientPathSeparator)) + } +}