mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-09-03 23:57:23 -04:00
Fix Windows sync (WalkEntryDir now returns only UNIX-style separators); fix setting remote mod time on remote files when downloading; fix server binary compilation; fix init failing silently during SSH configuration
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ func main() {
|
|||||||
fmt.Print(backend.EntryRoot + "\x1d" + strconv.FormatBool(backend.IsWindows))
|
fmt.Print(backend.EntryRoot + "\x1d" + strconv.FormatBool(backend.IsWindows))
|
||||||
case "init":
|
case "init":
|
||||||
// create the necessary directories for libmuttonserver to function
|
// create the necessary directories for libmuttonserver to function
|
||||||
backend.DirInit()
|
backend.DirInit(false)
|
||||||
os.MkdirAll(backend.ConfigDir+backend.PathSeparator+"deletions", 0700)
|
os.MkdirAll(backend.ConfigDir+backend.PathSeparator+"deletions", 0700)
|
||||||
case "version", "-v":
|
case "version", "-v":
|
||||||
versionServer()
|
versionServer()
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ func determineIndentation(skippedDirList []bool, dirList []string, currentDirInd
|
|||||||
var lastPrefixIndex int // tracks the index (in both skippedDirList and dirList) of the last displayed parent directory
|
var lastPrefixIndex int // tracks the index (in both skippedDirList and dirList) of the last displayed parent directory
|
||||||
var trimmedDirectory = dirList[currentDirIndex]
|
var trimmedDirectory = dirList[currentDirIndex]
|
||||||
|
|
||||||
// determine initial indentation multiplier based on PathSeparator occurrences
|
// determine initial indentation multiplier based on "/" occurrences
|
||||||
indent := strings.Count(trimmedDirectory, backend.PathSeparator) - 1 // subtract 1 to avoid indenting root-level directories
|
indent := strings.Count(trimmedDirectory, "/") - 1 // subtract 1 to avoid indenting root-level directories
|
||||||
|
|
||||||
for i, skipped := range skippedDirList[:currentDirIndex] { // checks each skipped directory to determine if it is a parent to the current directory
|
for i, skipped := range skippedDirList[:currentDirIndex] { // checks each skipped directory to determine if it is a parent to the current directory
|
||||||
if strings.HasPrefix(trimmedDirectory, dirList[i]+backend.PathSeparator) { // if the current directory is the child of this iteration's directory...
|
if strings.HasPrefix(trimmedDirectory, dirList[i]+"/") { // if the current directory is the child of this iteration's directory...
|
||||||
if skipped { // ...and this iteration's directory was skipped...
|
if skipped { // ...and this iteration's directory was skipped...
|
||||||
subtractor++ // increment the subtractor to indicate that the visual indentation should be reduced
|
subtractor++ // increment the subtractor to indicate that the visual indentation should be reduced
|
||||||
} else {
|
} else {
|
||||||
@@ -106,7 +106,7 @@ func EntryListGen() {
|
|||||||
|
|
||||||
// check if next directory is within the current one
|
// check if next directory is within the current one
|
||||||
if dirListLength > i+1 {
|
if dirListLength > i+1 {
|
||||||
if nextDir := dirList[i+1]; directory == nextDir[:strings.LastIndex(nextDir, backend.PathSeparator)] {
|
if nextDir := dirList[i+1]; directory == nextDir[:strings.LastIndex(nextDir, "/")] {
|
||||||
containsSubdirectory = true
|
containsSubdirectory = true
|
||||||
} else {
|
} else {
|
||||||
containsSubdirectory = false
|
containsSubdirectory = false
|
||||||
@@ -120,14 +120,14 @@ func EntryListGen() {
|
|||||||
for _, file := range fileList {
|
for _, file := range fileList {
|
||||||
|
|
||||||
// print the current file if it belongs in the current directory - otherwise, break the loop and move on to the next directory
|
// print the current file if it belongs in the current directory - otherwise, break the loop and move on to the next directory
|
||||||
if lastSlash := strings.LastIndex(file, backend.PathSeparator) + 1; file[:lastSlash-1] == directory {
|
if lastSlash := strings.LastIndex(file, "/") + 1; file[:lastSlash-1] == directory {
|
||||||
|
|
||||||
// print directory header if this is the first run of the loop
|
// print directory header if this is the first run of the loop
|
||||||
if !containsFiles {
|
if !containsFiles {
|
||||||
containsFiles = true
|
containsFiles = true
|
||||||
skippedDirList[i] = false // the directory header is being printed, indicate that it is not being skipped
|
skippedDirList[i] = false // the directory header is being printed, indicate that it is not being skipped
|
||||||
indent, vanityDirectory = determineIndentation(skippedDirList, dirList, i) // calculate the final indentation multiplier
|
indent, vanityDirectory = determineIndentation(skippedDirList, dirList, i) // calculate the final indentation multiplier
|
||||||
printDirectoryHeader(vanityDirectory, indent)
|
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", vanityDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
charCounter, colorAlternator = printFileEntry(file, lastSlash, charCounter, indent, colorAlternator)
|
charCounter, colorAlternator = printFileEntry(file, lastSlash, charCounter, indent, colorAlternator)
|
||||||
@@ -139,7 +139,7 @@ func EntryListGen() {
|
|||||||
if dirListLength > 1 { // and directories besides the root-level exist... display directory header and empty directory warning
|
if dirListLength > 1 { // and directories besides the root-level exist... display directory header and empty directory warning
|
||||||
skippedDirList[i] = false // the directory header is being printed, indicate that it is not being skipped
|
skippedDirList[i] = false // the directory header is being printed, indicate that it is not being skipped
|
||||||
indent, vanityDirectory = determineIndentation(skippedDirList, dirList, i) // calculate the final indentation multiplier
|
indent, vanityDirectory = determineIndentation(skippedDirList, dirList, i) // calculate the final indentation multiplier
|
||||||
printDirectoryHeader(vanityDirectory, indent)
|
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", vanityDirectory)
|
||||||
fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + backend.AnsiReset)
|
fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + backend.AnsiReset)
|
||||||
} else { // warn if the only thing that exists is the root-level directory
|
} else { // warn if the only thing that exists is the root-level directory
|
||||||
fmt.Print("\n\nNothing's here! For help creating your first entry, run \"mutn help\".")
|
fmt.Print("\n\nNothing's here! For help creating your first entry, run \"mutn help\".")
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
//go:build !windows
|
|
||||||
|
|
||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func printDirectoryHeader(vanityDirectory string, indent int) {
|
|
||||||
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", vanityDirectory)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func printDirectoryHeader(vanityDirectory string, indent int) {
|
|
||||||
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", strings.ReplaceAll(vanityDirectory, backend.PathSeparator, "/"))
|
|
||||||
}
|
|
||||||
+1
-1
@@ -40,7 +40,7 @@ func TempInitCli() {
|
|||||||
sshKeyProtected := inputBinary("Is the identity file password-protected?")
|
sshKeyProtected := inputBinary("Is the identity file password-protected?")
|
||||||
|
|
||||||
// write config file
|
// write config file
|
||||||
backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID, "sshUser": sshUser, "sshIP": sshIP, "sshPort": sshPort, "sshKey": sshKey, "sshKeyProtected": strconv.FormatBool(sshKeyProtected)}, false)
|
backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID, "sshUser": sshUser, "sshIP": sshIP, "sshPort": sshPort, "sshKey": sshKey, "sshKeyProtected": strconv.FormatBool(sshKeyProtected), "sshEntryRoot": "null", "sshIsWindows": "null"}, false)
|
||||||
|
|
||||||
// generate device ID
|
// generate device ID
|
||||||
sshEntryRoot, sshIsWindows := sync.DeviceIDGen()
|
sshEntryRoot, sshIsWindows := sync.DeviceIDGen()
|
||||||
|
|||||||
+1
-1
@@ -260,7 +260,7 @@ func sftpSync(downloadList, uploadList []string, manualSync bool) {
|
|||||||
localFile.Close()
|
localFile.Close()
|
||||||
|
|
||||||
// set the modification time of the local file to match the value saved from the remote file (from before the download)
|
// set the modification time of the local file to match the value saved from the remote file (from before the download)
|
||||||
err = os.Chtimes(remoteEntryFullPath, time.Now(), modTime)
|
err = os.Chtimes(localEntryFullPath, time.Now(), modTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if filesTransfered {
|
if filesTransfered {
|
||||||
|
|||||||
@@ -3,49 +3,10 @@ package sync
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
"io/fs"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WalkEntryDir walks the entry directory and returns lists of all files and directories found (two separate lists)
|
|
||||||
func WalkEntryDir() ([]string, []string) {
|
|
||||||
// define file/directory containing slices so that they may be accessed by the anonymous WalkDir function
|
|
||||||
var fileList []string
|
|
||||||
var dirList []string
|
|
||||||
|
|
||||||
// walk entry directory
|
|
||||||
_ = filepath.WalkDir(backend.EntryRoot,
|
|
||||||
func(fullPath string, entry fs.DirEntry, err error) error {
|
|
||||||
|
|
||||||
// check for errors encountered while walking directory
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
fmt.Println(backend.AnsiError+"The entry directory does not exist - run \""+os.Args[0], "init"+"\" to create it"+backend.AnsiReset) // TODO implement init command for libmuttonserver
|
|
||||||
} else {
|
|
||||||
// otherwise, print the source of the error
|
|
||||||
fmt.Println(backend.AnsiError + "An unexpected error occurred while generating the entry list: " + err.Error() + backend.AnsiReset)
|
|
||||||
}
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim root path from each path before storing
|
|
||||||
trimmedPath := fullPath[rootLength:]
|
|
||||||
|
|
||||||
// create separate slices for entries and directories
|
|
||||||
if !entry.IsDir() {
|
|
||||||
fileList = append(fileList, trimmedPath)
|
|
||||||
} else {
|
|
||||||
dirList = append(dirList, trimmedPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return fileList, dirList
|
|
||||||
}
|
|
||||||
|
|
||||||
func getModTimes(entryList []string) []int64 {
|
func getModTimes(entryList []string) []int64 {
|
||||||
// get a list of all entry modification times
|
// get a list of all entry modification times
|
||||||
var modList []int64
|
var modList []int64
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WalkEntryDir walks the entry directory and returns lists of all files and directories found (two separate lists)
|
||||||
|
// regardless of platform, all paths are stored with forward slashes (UNIX-style)
|
||||||
|
func WalkEntryDir() ([]string, []string) {
|
||||||
|
// define file/directory containing slices so that they may be accessed by the anonymous WalkDir function
|
||||||
|
var fileList []string
|
||||||
|
var dirList []string
|
||||||
|
|
||||||
|
// walk entry directory
|
||||||
|
_ = filepath.WalkDir(backend.EntryRoot,
|
||||||
|
func(fullPath string, entry fs.DirEntry, err error) error {
|
||||||
|
|
||||||
|
// check for errors encountered while walking directory
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
fmt.Println(backend.AnsiError+"The entry directory does not exist - run \""+os.Args[0], "init"+"\" to create it"+backend.AnsiReset) // TODO implement init command for libmuttonserver
|
||||||
|
} else {
|
||||||
|
// otherwise, print the source of the error
|
||||||
|
fmt.Println(backend.AnsiError + "An unexpected error occurred while generating the entry list: " + err.Error() + backend.AnsiReset)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim root path from each path before storing
|
||||||
|
trimmedPath := fullPath[rootLength:]
|
||||||
|
|
||||||
|
// append the path to the appropriate slice
|
||||||
|
if !entry.IsDir() {
|
||||||
|
fileList = append(fileList, trimmedPath)
|
||||||
|
} else {
|
||||||
|
dirList = append(dirList, trimmedPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return fileList, dirList
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WalkEntryDir walks the entry directory and returns lists of all files and directories found (two separate lists)
|
||||||
|
// regardless of platform, all paths are stored with forward slashes (UNIX-style)
|
||||||
|
func WalkEntryDir() ([]string, []string) {
|
||||||
|
// define file/directory containing slices so that they may be accessed by the anonymous WalkDir function
|
||||||
|
var fileList []string
|
||||||
|
var dirList []string
|
||||||
|
|
||||||
|
// walk entry directory
|
||||||
|
_ = filepath.WalkDir(backend.EntryRoot,
|
||||||
|
func(fullPath string, entry fs.DirEntry, err error) error {
|
||||||
|
|
||||||
|
// check for errors encountered while walking directory
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
fmt.Println(backend.AnsiError+"The entry directory does not exist - run \""+os.Args[0], "init"+"\" to create it"+backend.AnsiReset) // TODO implement init command for libmuttonserver
|
||||||
|
} else {
|
||||||
|
// otherwise, print the source of the error
|
||||||
|
fmt.Println(backend.AnsiError + "An unexpected error occurred while generating the entry list: " + err.Error() + backend.AnsiReset)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim root path from each path before storing and replace backslashes with forward slashes
|
||||||
|
trimmedPath := strings.ReplaceAll(fullPath[rootLength:], "\\", "/")
|
||||||
|
|
||||||
|
// append the path to the appropriate slice
|
||||||
|
if !entry.IsDir() {
|
||||||
|
fileList = append(fileList, trimmedPath)
|
||||||
|
} else {
|
||||||
|
dirList = append(dirList, trimmedPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return fileList, dirList
|
||||||
|
}
|
||||||
+2
-2
@@ -14,8 +14,8 @@ func DeviceIDGen() (string, string) {
|
|||||||
deviceIDPrefix, _ := os.Hostname()
|
deviceIDPrefix, _ := os.Hostname()
|
||||||
deviceIDSuffix := backend.StringGen(rand.Intn(48)+48, false, 0) // TODO consider using complex string generator and removing unsafe characters manually
|
deviceIDSuffix := backend.StringGen(rand.Intn(48)+48, false, 0) // TODO consider using complex string generator and removing unsafe characters manually
|
||||||
deviceID := deviceIDPrefix + "-" + deviceIDSuffix
|
deviceID := deviceIDPrefix + "-" + deviceIDSuffix
|
||||||
os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + deviceID) // TODO remove existing device ID file if it exists (from both client and server)
|
os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + deviceID) // TODO remove existing device ID file if it exists (from both client and server)
|
||||||
sshEntryRootSSHIsWindows := strings.Split(GetSSHOutput("libmuttonserver register "+deviceID, false), "\x1d") // register device ID with server and fetch remote EntryRoot and OS type
|
sshEntryRootSSHIsWindows := strings.Split(GetSSHOutput("libmuttonserver register "+deviceID, true), "\x1d") // register device ID with server and fetch remote EntryRoot and OS type; manualSync is true so the user is alerted if device ID registration fails
|
||||||
|
|
||||||
return sshEntryRootSSHIsWindows[0], sshEntryRootSSHIsWindows[1]
|
return sshEntryRootSSHIsWindows[0], sshEntryRootSSHIsWindows[1]
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -23,7 +23,7 @@ func GetRemoteDataFromServer(clientDeviceID string) {
|
|||||||
|
|
||||||
// entry list
|
// entry list
|
||||||
for _, entry := range entryList {
|
for _, entry := range entryList {
|
||||||
printToStdout(entry)
|
fmt.Print("\x1f" + entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// modification time list
|
// modification time list
|
||||||
@@ -36,7 +36,7 @@ func GetRemoteDataFromServer(clientDeviceID string) {
|
|||||||
// directory/folder list
|
// directory/folder list
|
||||||
fmt.Print("\x1d")
|
fmt.Print("\x1d")
|
||||||
for _, dir := range dirList {
|
for _, dir := range dirList {
|
||||||
printToStdout(dir)
|
fmt.Print("\x1f" + dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deletions list
|
// deletions list
|
||||||
@@ -45,7 +45,7 @@ func GetRemoteDataFromServer(clientDeviceID string) {
|
|||||||
// print deletion if it is relevant to the current client device
|
// print deletion if it is relevant to the current client device
|
||||||
affectedIDTargetLocationIncomplete := strings.Split(deletion.Name(), "\x1d")
|
affectedIDTargetLocationIncomplete := strings.Split(deletion.Name(), "\x1d")
|
||||||
if affectedIDTargetLocationIncomplete[0] == clientDeviceID {
|
if affectedIDTargetLocationIncomplete[0] == clientDeviceID {
|
||||||
fmt.Print("\x1f" + strings.ReplaceAll(affectedIDTargetLocationIncomplete[1], "\x1e", "/")) // do not use printToStdout as separators are filling in for \x1e
|
fmt.Print("\x1f" + strings.ReplaceAll(affectedIDTargetLocationIncomplete[1], "\x1e", "/"))
|
||||||
|
|
||||||
// assume successful client deletion and remove deletions file (if assumption is somehow false, worst case scenario is that the client will re-upload the deleted entry)
|
// assume successful client deletion and remove deletions file (if assumption is somehow false, worst case scenario is that the client will re-upload the deleted entry)
|
||||||
os.Remove(backend.ConfigDir + backend.PathSeparator + "deletions" + backend.PathSeparator + deletion.Name())
|
os.Remove(backend.ConfigDir + backend.PathSeparator + "deletions" + backend.PathSeparator + deletion.Name())
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
//go:build !windows
|
|
||||||
|
|
||||||
package sync
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// printToStdout prints a string to stdout with UNIX path separators
|
|
||||||
func printToStdout(targetLocationIncomplete string) {
|
|
||||||
fmt.Print("\x1f" + targetLocationIncomplete)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package sync
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// printToStdout prints a string to stdout with UNIX path separators
|
|
||||||
func printToStdout(targetLocationIncomplete string) {
|
|
||||||
fmt.Print("\x1f" + strings.ReplaceAll(targetLocationIncomplete, "\\", "/"))
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user