From 2feeeb74d7813dbbb75795d5ccdd817bbcea3602 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Sun, 29 Dec 2024 16:23:08 -0500 Subject: [PATCH] Return errors from ParseConfig (facilitates GUI development) --- core/configParser.go | 23 +++++++++++++++-------- core/gpg.go | 3 ++- sync/client.go | 4 ++-- wiki/developers.md | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/core/configParser.go b/core/configParser.go index 8e9d80e..9754168 100644 --- a/core/configParser.go +++ b/core/configParser.go @@ -22,8 +22,10 @@ func loadConfig() *ini.File { // ParseConfig reads the libmutton.ini file and returns a slice of values for the specified keys. // Requires: valuesRequested (a slice of length 2 arrays each containing a section and a key name), // missingValueError (an error message to display if a key is missing a value, set to "" for auto-generated or "0" to exit/return silently with code 0). -// Returns: config (slice of values for the specified keys). -func ParseConfig(valuesRequested [][2]string, missingValueError string) []string { +// Returns: config (slice of values for the specified keys), +// error (nil if no error occurred, otherwise an error using the generated or provided message). +func ParseConfig(valuesRequested [][2]string, missingValueError string) ([]string, error) { + var err error cfg := loadConfig() var config []string @@ -35,19 +37,23 @@ func ParseConfig(valuesRequested [][2]string, missingValueError string) []string if value == "" { switch missingValueError { case "": - fmt.Println(AnsiError + "Failed to find value for key \"" + pair[1] + "\" in section \"[" + pair[0] + "]\" in libmutton.ini" + AnsiReset) + err = fmt.Errorf("Failed to find value for key \"%s\" in section \"[%s]\" in libmutton.ini", pair[1], pair[0]) + fmt.Println(err.Error()) case "0": - Exit(0) + Exit(0) // hard (expected) exit for CLI; GUI/TUI continue silently default: - fmt.Println(AnsiError + missingValueError + AnsiReset) + err = fmt.Errorf("%s", missingValueError) + fmt.Println(err.Error()) } - os.Exit(ErrorRead) + Exit(ErrorRead) // hard exit for CLI; GUI/TUI continue silently + // if interactive (soft exit), return nil and the error to be handled by the caller + return nil, err } config = append(config, value) } - return config + return config, err } // GenDeviceIDList returns a pointer to a slice of all registered device IDs. @@ -67,7 +73,8 @@ func GenDeviceIDList(errorOnFail bool) *[]fs.DirEntry { } // WriteConfig writes the provided key-value pairs under the specified section headers in the libmutton.ini file. -// Requires: valuesToWrite (a slice of length 3 arrays each containing a section, a key name, and a value). +// Requires: valuesToWrite (a slice of length 3 arrays each containing a section, a key name, and a value), +// append (set to true to append to the existing libmutton.ini file, false to overwrite it). func WriteConfig(valuesToWrite [][3]string, append bool) { var cfg *ini.File diff --git a/core/gpg.go b/core/gpg.go index f633851..8828135 100644 --- a/core/gpg.go +++ b/core/gpg.go @@ -27,7 +27,8 @@ func DecryptGPG(targetLocation string) []string { // EncryptGPG encrypts a slice of strings using GPG and returns the encrypted data as a byte slice. func EncryptGPG(input []string) []byte { - cmd := exec.Command("gpg", "-q", "-r", ParseConfig([][2]string{{"LIBMUTTON", "gpgID"}}, "")[0], "-e") + gpgCfg, _ := ParseConfig([][2]string{{"LIBMUTTON", "gpgID"}}, "") + cmd := exec.Command("gpg", "-q", "-r", gpgCfg[0], "-e") writeToStdin(cmd, strings.Join(input, "\n")) encryptedBytes, err := cmd.Output() if err != nil { diff --git a/sync/client.go b/sync/client.go index 41445e9..b2cfacb 100644 --- a/sync/client.go +++ b/sync/client.go @@ -29,9 +29,9 @@ func GetSSHClient(manualSync bool) (*ssh.Client, string, bool) { if manualSync { missingValueError = joinErrorWithEXE("SSH settings not configured - Run \"", " init\" to configure") } else { - missingValueError = "0" + missingValueError = "0" // allow silent exit at this point in offline mode } - sshUserConfig = core.ParseConfig([][2]string{{"LIBMUTTON", "sshUser"}, {"LIBMUTTON", "sshIP"}, {"LIBMUTTON", "sshPort"}, {"LIBMUTTON", "sshKey"}, {"LIBMUTTON", "sshKeyProtected"}, {"LIBMUTTON", "sshEntryRoot"}, {"LIBMUTTON", "sshIsWindows"}}, missingValueError) + sshUserConfig, _ = core.ParseConfig([][2]string{{"LIBMUTTON", "sshUser"}, {"LIBMUTTON", "sshIP"}, {"LIBMUTTON", "sshPort"}, {"LIBMUTTON", "sshKey"}, {"LIBMUTTON", "sshKeyProtected"}, {"LIBMUTTON", "sshEntryRoot"}, {"LIBMUTTON", "sshIsWindows"}}, missingValueError) var user, ip, port, keyFile, keyFileProtected, entryRoot string var isWindows bool diff --git a/wiki/developers.md b/wiki/developers.md index 0e64ea2..fd47efd 100644 --- a/wiki/developers.md +++ b/wiki/developers.md @@ -11,7 +11,7 @@ If any functionality in these two packages proves to be difficult to implement i Custom build tags can (and sometimes must) be used to achieve desired results. These are as follows: -- `interactive`: If making an interactive interface (GUI/TUI/interactive CLI), you probably need to use this build tag. Without it, your entire program will exit after any given operation is completed. This behavior is only desired for non-interactive CLI implementations, such as MUTN. Currently, errors will result in the program exiting **even with this build tag**. This may be changed in the future (under evaluation). +- `interactive`: If making an interactive interface (GUI/TUI/interactive CLI), you probably need to use this build tag. Without it, your entire program will exit after any given operation is completed. This behavior is only desired for non-interactive CLI implementations, such as MUTN. Currently, most errors will result in the program exiting **even with this build tag**. Specific types of errors (such as config parsing errors) have been made exempt from this behavior. - `wsl`: Allows creating a Linux binary that can interact with the Windows clipboard (for WSL) - `termux`: Allows creating a Linux binary that can interact with the Termux clipboard (for Android)