mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-09-03 07:37:23 -04:00
Initial groundwork for native sync support
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
"github.com/rwinkhart/MUTN/src/cli"
|
"github.com/rwinkhart/MUTN/src/cli"
|
||||||
|
"github.com/rwinkhart/MUTN/src/sync"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -162,6 +163,8 @@ func main() {
|
|||||||
fmt.Println(backend.AnsiError + "\"sync\" is not yet implemented" + backend.AnsiReset)
|
fmt.Println(backend.AnsiError + "\"sync\" is not yet implemented" + backend.AnsiReset)
|
||||||
}
|
}
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
case "synctest": // TODO Remove after native sync is implemented
|
||||||
|
sync.RunJob(true)
|
||||||
case "init":
|
case "init":
|
||||||
cli.TempInitCli()
|
cli.TempInitCli()
|
||||||
case "tweak":
|
case "tweak":
|
||||||
|
|||||||
+18
-11
@@ -6,10 +6,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadConfig reads the libmutton.ini file and returns a map of the requested values
|
// ReadConfig reads the libmutton.ini file and returns a slice of values for the specified keys
|
||||||
// requires readMap: a map of section names to key names (indicates requested values)
|
// requires readKeys: a slice of key names (indicates requested values)
|
||||||
// returns configMap: a map of key names to values (sections are irrelevant)
|
// requires missingValueError: an error message to display if a key is missing a value, set to "" for auto-generated or "0" to exit silently with status 0
|
||||||
func ReadConfig(readKeys []string) []string {
|
// returns config: a slice of values for the specified keys
|
||||||
|
func ReadConfig(readKeys []string, missingValueError string) []string {
|
||||||
cfg, err := ini.Load(ConfigPath)
|
cfg, err := ini.Load(ConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(AnsiError + "Failed to load libmutton.ini" + AnsiReset)
|
fmt.Println(AnsiError + "Failed to load libmutton.ini" + AnsiReset)
|
||||||
@@ -23,7 +24,14 @@ func ReadConfig(readKeys []string) []string {
|
|||||||
|
|
||||||
// ensure specified key has a value
|
// ensure specified key has a value
|
||||||
if keyConfig == "" {
|
if keyConfig == "" {
|
||||||
fmt.Println(AnsiError + "Failed to find value for key \"" + key + "\" in section \"[LIBMUTTON]\" in libmutton.ini" + AnsiReset)
|
switch missingValueError {
|
||||||
|
case "":
|
||||||
|
fmt.Println(AnsiError + "Failed to find value for key \"" + key + "\" in section \"[LIBMUTTON]\" in libmutton.ini" + AnsiReset)
|
||||||
|
case "0":
|
||||||
|
os.Exit(0)
|
||||||
|
default:
|
||||||
|
fmt.Println(AnsiError + missingValueError + AnsiReset)
|
||||||
|
}
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,10 +45,9 @@ func ReadConfig(readKeys []string) []string {
|
|||||||
// [LIBMUTTON]
|
// [LIBMUTTON]
|
||||||
// gpgID = <gpg key id>
|
// gpgID = <gpg key id>
|
||||||
// textEditor = <editor command>
|
// textEditor = <editor command>
|
||||||
// onlineMode = <true/false>
|
// sshUser = <remote user>
|
||||||
// sshError = <true/false>
|
// sshIP = <remote ip>
|
||||||
|
// sshPort = <remote ssh port>
|
||||||
|
// sshIdentity = <ssh private key identity file path>
|
||||||
// netPinEnabled = <true/false>
|
// netPinEnabled = <true/false>
|
||||||
// remoteUser = <ssh user>
|
// deviceID = <device id> TODO remove from config file
|
||||||
// remoteIP = <ssh ip>
|
|
||||||
// remotePort = <ssh port>
|
|
||||||
// identityFile = <path to private key>
|
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ func DecryptGPG(targetLocation string) []string {
|
|||||||
|
|
||||||
// EncryptGPG encrypts a slice of strings using GPG and returns the encrypted data as a byte slice
|
// EncryptGPG encrypts a slice of strings using GPG and returns the encrypted data as a byte slice
|
||||||
func EncryptGPG(input []string) []byte {
|
func EncryptGPG(input []string) []byte {
|
||||||
cmd := exec.Command("gpg", "-q", "-r", ReadConfig([]string{"gpgID"})[0], "-e")
|
cmd := exec.Command("gpg", "-q", "-r", ReadConfig([]string{"gpgID"}, "")[0], "-e")
|
||||||
writeToStdin(cmd, strings.Join(input, "\n"))
|
writeToStdin(cmd, strings.Join(input, "\n"))
|
||||||
encryptedBytes, err := cmd.Output()
|
encryptedBytes, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
|
||||||
termy "golang.org/x/crypto/ssh/terminal"
|
termy "golang.org/x/crypto/ssh/terminal"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// global variables used across multiple files
|
// global variables used across multiple files
|
||||||
var (
|
var (
|
||||||
rootLength = len(backend.EntryRoot)
|
|
||||||
width, _, _ = termy.GetSize(int(os.Stdout.Fd()))
|
width, _, _ = termy.GetSize(int(os.Stdout.Fd()))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ func GenUpdate(targetLocation string, hidePassword bool) {
|
|||||||
func editNote(baseNote []string) ([]string, bool) {
|
func editNote(baseNote []string) ([]string, bool) {
|
||||||
tempFile := backend.CreateTempFile()
|
tempFile := backend.CreateTempFile()
|
||||||
defer os.Remove(tempFile.Name())
|
defer os.Remove(tempFile.Name())
|
||||||
editor := backend.ReadConfig([]string{"textEditor"})[0]
|
editor := backend.ReadConfig([]string{"textEditor"}, "")[0]
|
||||||
|
|
||||||
// write baseNote to tempFile (if it is not empty)
|
// write baseNote to tempFile (if it is not empty)
|
||||||
if len(baseNote) > 0 {
|
if len(baseNote) > 0 {
|
||||||
|
|||||||
+2
-33
@@ -3,9 +3,8 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
"io/fs"
|
"github.com/rwinkhart/MUTN/src/sync"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -79,37 +78,7 @@ func printFileEntry(entry string, lastSlash int, charCounter int, colorAlternato
|
|||||||
|
|
||||||
// EntryListGen generates and displays full libmutton entry list
|
// EntryListGen generates and displays full libmutton entry list
|
||||||
func EntryListGen() {
|
func EntryListGen() {
|
||||||
// define file/directory containing slices so that they may be accessed by the anonymous WalkDir function
|
fileList, dirList := sync.WalkEntryDir()
|
||||||
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 + "\nThe entry directory does not exist - run \"mutn init\" to create it" + backend.AnsiReset)
|
|
||||||
} else {
|
|
||||||
// otherwise, print the source of the error
|
|
||||||
fmt.Println(backend.AnsiError + "\nAn 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
|
|
||||||
})
|
|
||||||
|
|
||||||
// print header bar w/total entry count
|
// print header bar w/total entry count
|
||||||
fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+backend.AnsiReset)
|
fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+backend.AnsiReset)
|
||||||
|
|||||||
+22
-1
@@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,5 +27,25 @@ func TempInitCli() {
|
|||||||
// textEditor
|
// textEditor
|
||||||
textEditor := input("Text editor (leave blank for $EDITOR, falls back to \"" + backend.FallbackEditor + "\"):")
|
textEditor := input("Text editor (leave blank for $EDITOR, falls back to \"" + backend.FallbackEditor + "\"):")
|
||||||
|
|
||||||
backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID})
|
// SSH info
|
||||||
|
configSSH := inputBinary("Configure SSH settings (for synchronization)?")
|
||||||
|
if configSSH {
|
||||||
|
// client device ID
|
||||||
|
deviceIDPrefix, _ := os.Hostname()
|
||||||
|
deviceIDSuffix := backend.StringGen(rand.Intn(48)+48, true, 0.2)
|
||||||
|
deviceID := deviceIDPrefix + "-" + deviceIDSuffix // TODO do not save in config file, encrypt in config directory
|
||||||
|
|
||||||
|
// necessary SSH info
|
||||||
|
sshUser := input("Remote SSH username:")
|
||||||
|
sshIP := input("Remote SSH IP address:")
|
||||||
|
sshPort := input("Remote SSH port:")
|
||||||
|
sshIdentity := input("SSH private identity file path:") // TODO implement generator and selector
|
||||||
|
|
||||||
|
// write config file
|
||||||
|
backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID, "deviceID": deviceID, "sshUser": sshUser, "sshIP": sshIP, "sshPort": sshPort, "sshIdentity": sshIdentity})
|
||||||
|
} else {
|
||||||
|
// write config file
|
||||||
|
backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,8 +142,8 @@ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|||||||
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " // \\\\ /|\\\n" +
|
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " // \\\\ /|\\\n" +
|
||||||
ansiVersionOutline + "<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" +
|
ansiVersionOutline + "<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" +
|
||||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " MUTN Version 0.1.0 " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " MUTN Version 0.2.X " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " The Butchered Update " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " The Placeholder Update " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " Copyright (c) 2024 Randall Winkhart " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " Copyright (c) 2024 Randall Winkhart " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import "github.com/rwinkhart/MUTN/src/backend"
|
||||||
|
|
||||||
|
// RootLength store length of backend.EntryRoot string
|
||||||
|
var rootLength = len(backend.EntryRoot)
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/rwinkhart/MUTN/src/backend"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// returns lists of local entries and mod times (two separate lists)
|
||||||
|
func getLocalData() {
|
||||||
|
fileList, _ := WalkEntryDir()
|
||||||
|
fmt.Println(fileList) // TODO placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunJob runs the SSH sync job
|
||||||
|
func RunJob(manualSync bool) {
|
||||||
|
// get SSH config info, exit if not configured (displaying an error if the sync job was called manually)
|
||||||
|
var sshUserIPPortIdentity []string
|
||||||
|
if manualSync {
|
||||||
|
sshUserIPPortIdentity = backend.ReadConfig([]string{"sshUser", "sshIP", "sshPort", "sshIdentity"}, "SSH settings not configured - run \"mutn init\" to configure")
|
||||||
|
} else {
|
||||||
|
sshUserIPPortIdentity = backend.ReadConfig([]string{"sshUser", "sshIP", "sshPort", "sshIdentity"}, "0")
|
||||||
|
}
|
||||||
|
|
||||||
|
var sshUser, sshIP, sshPort, sshIdentity string
|
||||||
|
for i, key := range sshUserIPPortIdentity {
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
sshUser = key
|
||||||
|
case 1:
|
||||||
|
sshIP = key
|
||||||
|
case 2:
|
||||||
|
sshPort = key
|
||||||
|
case 3:
|
||||||
|
sshIdentity = key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(sshUser, sshIP, sshPort, sshIdentity) // TODO placeholder
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
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)
|
||||||
|
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 + "\nThe entry directory does not exist - run \"mutn init\" to create it" + backend.AnsiReset)
|
||||||
|
} else {
|
||||||
|
// otherwise, print the source of the error
|
||||||
|
fmt.Println(backend.AnsiError + "\nAn 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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user