mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-08-28 04:46:41 -04:00
Implement synchronized renaming
This commit is contained in:
+8
-1
@@ -40,6 +40,13 @@ func main() {
|
||||
// print all information needed for syncing to stdout for interpretation by the client
|
||||
// stdin[0] is expected to be the device ID
|
||||
sync.GetRemoteDataFromServer(stdin[0])
|
||||
case "rename":
|
||||
// move an entry to a new location before using fallthrough to add its previous iteration to the deletions directory
|
||||
// stdin[0] is evaluated after fallthrough
|
||||
// stdin[1] is expected to be the OLD incomplete target location with "\x1d" representing path separators - always pass in UNIX format
|
||||
// stdin[2] is expected to be the NEW incomplete target location with "\x1d" representing path separators - always pass in UNIX format
|
||||
sync.Rename(strings.ReplaceAll(stdin[1], "\x1d", "/"), strings.ReplaceAll(stdin[2], "\x1d", "/"), true)
|
||||
fallthrough // fallthrough to add the old entry to the deletions directory
|
||||
case "shear":
|
||||
// shear an entry from the server and add it to the deletions directory
|
||||
// stdin[0] is expected to be the device ID
|
||||
@@ -73,7 +80,7 @@ This software exists under the MIT license; you may redistribute it under certai
|
||||
This program comes with absolutely no warranty; type "libmuttonserver version" for details.
|
||||
|
||||
` + cli.AnsiBold + "Usage:" + backend.AnsiReset + ` libmuttonserver <argument>
|
||||
|
||||
|
||||
` + cli.AnsiBold + "Arguments (user):" + backend.AnsiReset + `
|
||||
help|-h Bring up this menu
|
||||
version|-v Display version and license information
|
||||
|
||||
@@ -97,7 +97,7 @@ func main() {
|
||||
case "note", "-n":
|
||||
field = 4
|
||||
case "rename", "-r":
|
||||
cli.RenameCli(targetLocation)
|
||||
cli.RenameCli(args[1]) // pass the incomplete path as the server and all clients (reading from the deletions directory) will have a different home directory
|
||||
default:
|
||||
cli.HelpEdit()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetOldEntryData decrypts and returns old entry data (with all required lines present)
|
||||
func GetOldEntryData(targetLocation string, field int) []string {
|
||||
// ensure targetLocation exists
|
||||
@@ -21,25 +16,6 @@ func GetOldEntryData(targetLocation string, field int) []string {
|
||||
}
|
||||
}
|
||||
|
||||
// Rename renames oldLocation to newLocation
|
||||
func Rename(oldLocation, newLocation string) {
|
||||
// ensure newLocation does not exist
|
||||
_, isAccessible := TargetIsFile(newLocation, false, 0)
|
||||
if isAccessible {
|
||||
fmt.Println(AnsiError + "\"" + newLocation + "\" already exists" + AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// rename oldLocation to newLocation
|
||||
err := os.Rename(oldLocation, newLocation)
|
||||
if err != nil {
|
||||
fmt.Println(AnsiError + "Failed to rename - does the target containing directory exists?" + AnsiReset)
|
||||
}
|
||||
|
||||
// TODO implement synced renaming
|
||||
Exit(0)
|
||||
}
|
||||
|
||||
// EnsureSliceLength ensures slice is long enough to contain the specified index
|
||||
func EnsureSliceLength(slice []string, index int) []string {
|
||||
for len(slice) <= index {
|
||||
|
||||
+6
-8
@@ -4,22 +4,20 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"github.com/rwinkhart/MUTN/src/sync"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RenameCli renames an entry at oldLocation to a new location (user input)
|
||||
func RenameCli(oldLocation string) {
|
||||
// ensure targetLocation exists
|
||||
backend.TargetIsFile(oldLocation, true, 0)
|
||||
|
||||
// RenameCli renames an entry at oldLocation to a new location (user input) on both the client and the server
|
||||
func RenameCli(oldLocationIncomplete string) {
|
||||
// prompt user for new location and rename
|
||||
newLocation := backend.TargetLocationFormat(input("New location:"))
|
||||
backend.Rename(oldLocation, newLocation)
|
||||
newLocationIncomplete := input("New location:")
|
||||
sync.Rename(oldLocationIncomplete, newLocationIncomplete, false)
|
||||
|
||||
// exit is done from backend.Rename
|
||||
// exit is done from sync.Rename
|
||||
}
|
||||
|
||||
// EditEntryField edits a field of an entry at targetLocation (user input)
|
||||
|
||||
+55
-12
@@ -3,12 +3,13 @@ package sync
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// getModTimes returns a list of all entry modification times
|
||||
func getModTimes(entryList []string) []int64 {
|
||||
// get a list of all entry modification times
|
||||
var modList []int64
|
||||
for _, file := range entryList {
|
||||
modTime, _ := os.Stat(backend.TargetLocationFormat(file))
|
||||
@@ -18,6 +19,53 @@ func getModTimes(entryList []string) []int64 {
|
||||
return modList
|
||||
}
|
||||
|
||||
// genDeviceIDList returns a pointer to a slice of all registered device IDs
|
||||
func genDeviceIDList() *[]fs.DirEntry {
|
||||
// create a slice of all registered devices
|
||||
deviceIDList, err := os.ReadDir(backend.ConfigDir + backend.PathSeparator + "devices")
|
||||
if err != nil {
|
||||
fmt.Println(backend.AnsiError + "Failed to read the devices directory: " + err.Error() + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
return &deviceIDList
|
||||
}
|
||||
|
||||
// Rename renames oldLocation to newLocation
|
||||
// if running on the client, also calls the server to rename the entry and add the old entry name to the deletions list
|
||||
func Rename(oldLocationIncomplete, newLocationIncomplete string, onServer bool) {
|
||||
// get full paths for both locations
|
||||
oldLocation := backend.TargetLocationFormat(oldLocationIncomplete)
|
||||
newLocation := backend.TargetLocationFormat(newLocationIncomplete)
|
||||
|
||||
// ensure oldLocation exists
|
||||
backend.TargetIsFile(oldLocation, true, 0)
|
||||
|
||||
// ensure newLocation does not exist
|
||||
_, isAccessible := backend.TargetIsFile(newLocation, false, 0)
|
||||
if isAccessible {
|
||||
fmt.Println(backend.AnsiError + "\"" + newLocation + "\" already exists" + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// rename oldLocation to newLocation
|
||||
err := os.Rename(oldLocation, newLocation)
|
||||
if err != nil {
|
||||
fmt.Println(backend.AnsiError + "Failed to rename - does the target containing directory exist?" + backend.AnsiReset)
|
||||
}
|
||||
|
||||
// call server to complete rename
|
||||
if !onServer {
|
||||
deviceIDList := genDeviceIDList()
|
||||
if len(*deviceIDList) > 0 { // ensure a device ID exists (online mode)
|
||||
GetSSHOutput("libmuttonserver rename",
|
||||
(*deviceIDList)[0].Name()+"\n"+
|
||||
strings.ReplaceAll(oldLocationIncomplete, backend.PathSeparator, "\x1d")+"\n"+
|
||||
strings.ReplaceAll(newLocationIncomplete, backend.PathSeparator, "\x1d"), false)
|
||||
}
|
||||
backend.Exit(0) // do not exit program on server, as fallthrough is used to add the old entry name to the deletions list
|
||||
}
|
||||
}
|
||||
|
||||
// ShearLocal removes the target file or directory from the local system
|
||||
// returns: deviceID (on client), for use in ShearRemoteFromClient
|
||||
// if the local system is a server, it will also add the target to the deletions list for all clients (except the requesting client)
|
||||
@@ -29,18 +77,13 @@ func ShearLocal(targetLocationIncomplete, clientDeviceID string) string {
|
||||
onServer = true
|
||||
}
|
||||
|
||||
// create a slice of all registered devices
|
||||
deviceIDList, err := os.ReadDir(backend.ConfigDir + backend.PathSeparator + "devices")
|
||||
if err != nil {
|
||||
fmt.Println(backend.AnsiError + "Failed to read the devices directory: " + err.Error() + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
deviceIDList := genDeviceIDList()
|
||||
|
||||
// add the sheared target (incomplete, vanity) to the deletions list (if running on a server)
|
||||
if onServer {
|
||||
for _, device := range deviceIDList {
|
||||
for _, device := range *deviceIDList {
|
||||
if device.Name() != clientDeviceID {
|
||||
_, err = os.Create(backend.ConfigDir + backend.PathSeparator + "deletions" + backend.PathSeparator + device.Name() + "\x1e" + strings.ReplaceAll(targetLocationIncomplete, "/", "\x1d"))
|
||||
_, err := os.Create(backend.ConfigDir + backend.PathSeparator + "deletions" + backend.PathSeparator + device.Name() + "\x1e" + strings.ReplaceAll(targetLocationIncomplete, "/", "\x1d"))
|
||||
if err != nil {
|
||||
// do not print error as there is currently no way of seeing server-side errors
|
||||
// failure to add the target to the deletions list will exit the program and result in a client re-uploading the target (non-critical)
|
||||
@@ -55,14 +98,14 @@ func ShearLocal(targetLocationIncomplete, clientDeviceID string) string {
|
||||
if !onServer { // error if target does not exist on client, needed because os.RemoveAll does not return an error if target does not exist
|
||||
backend.TargetIsFile(targetLocationComplete, true, 0)
|
||||
}
|
||||
err = os.RemoveAll(targetLocationComplete)
|
||||
err := os.RemoveAll(targetLocationComplete)
|
||||
if err != nil {
|
||||
fmt.Println(backend.AnsiError + "Failed to remove local target: " + err.Error() + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !onServer && len(deviceIDList) > 0 { // return the device ID if running on the client and a device ID exists (online mode)
|
||||
return deviceIDList[0].Name()
|
||||
if !onServer && len(*deviceIDList) > 0 { // return the device ID if running on the client and a device ID exists (online mode)
|
||||
return (*deviceIDList)[0].Name()
|
||||
}
|
||||
return ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user