Implement error-specific exit codes

This commit is contained in:
2024-08-11 20:21:01 -04:00
parent 06b9527a33
commit ed9c4e91ff
18 changed files with 102 additions and 88 deletions
+14
View File
@@ -13,3 +13,17 @@ const (
AnsiReset = "\033[0m"
LibmuttonVersion = "0.2.B" // untagged releases feature a letter suffix corresponding to the eventual release version, e.g "0.2.A" -> "0.2.0", "0.2.B" -> "0.2.1"
)
// numeric error codes legend
// 0: no error
// 101: read error
// 102: write error
// 103: sync process error
// 104: server connection error
// 105: target not found
// 106: target already exists
// 107: target wrong type (file/directory)
// 108: decryption error
// 109: encryption error
// 110: clipboard error
// 111: other error
+3 -3
View File
@@ -13,7 +13,7 @@ func loadConfig() *ini.File {
cfg, err := ini.Load(ConfigPath)
if err != nil {
fmt.Println(AnsiError + "Failed to load libmutton.ini: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(101)
}
return cfg
}
@@ -40,7 +40,7 @@ func ParseConfig(valuesRequested [][2]string, missingValueError string) []string
default:
fmt.Println(AnsiError + missingValueError + AnsiReset)
}
os.Exit(1)
os.Exit(101)
}
config = append(config, value)
@@ -81,6 +81,6 @@ func WriteConfig(valuesToWrite [][3]string, append bool) {
err := cfg.SaveTo(ConfigPath)
if err != nil {
fmt.Println(AnsiError + "Failed to save libmutton.ini: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(102)
}
}
+4 -4
View File
@@ -24,7 +24,7 @@ func CopyArgument(executableName, targetLocation string, field int) {
// ensure field is not empty
if decryptedEntry[field] == "" {
fmt.Println(AnsiError + "Field is empty" + AnsiReset)
os.Exit(1)
os.Exit(105)
}
if field != 2 {
@@ -40,7 +40,7 @@ func CopyArgument(executableName, targetLocation string, field int) {
secret = decryptedEntry[2]
}
fmt.Println("TOTP code has been copied to the clipboard - your clipboard will be kept up to date with the current code until this process is closed")
fmt.Println("TOTP code has been copied to the clipboard - Your clipboard will be kept up to date with the current code until this process is closed")
for { // keep field copied to clipboard, refresh on 30-second intervals
currentTime := time.Now()
@@ -51,7 +51,7 @@ func CopyArgument(executableName, targetLocation string, field int) {
}
} else {
fmt.Println(AnsiError + "Field does not exist in entry" + AnsiReset)
os.Exit(1)
os.Exit(105)
}
// copy field to clipboard, launch clipboard clearing process
@@ -84,7 +84,7 @@ func GenTOTP(secret string, time time.Time, forSteam bool) string {
if err != nil {
fmt.Println(AnsiError + "Error generating TOTP code" + AnsiReset)
os.Exit(1)
os.Exit(111)
}
return totpToken
+5 -5
View File
@@ -17,7 +17,7 @@ func copyField(executableName, copySubject string) {
err := cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
// launch clipboard clearing process if executableName is provided
@@ -26,8 +26,8 @@ func copyField(executableName, copySubject string) {
writeToStdin(cmd, copySubject)
err = cmd.Start()
if err != nil {
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - Does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(110)
}
Exit(0) // only exit if clipboard clearing process is launched, otherwise assume continuous clipboard refresh
}
@@ -41,7 +41,7 @@ func clipClear(oldContents string) {
newContents, err := cmd.Output()
if err != nil {
fmt.Println(AnsiError + "Failed to read clipboard contents: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
if oldContents == strings.TrimRight(string(newContents), "\r\n") {
@@ -50,7 +50,7 @@ func clipClear(oldContents string) {
err = cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to clear clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
}
os.Exit(0) // use os.Exit instead of core.Exit, as this function runs out of a background subprocess that is invisible to the user (will never appear in GUI/TUI environment)
+5 -5
View File
@@ -17,7 +17,7 @@ func copyField(executableName, copySubject string) {
err := cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
// launch clipboard clearing process if executableName is provided
@@ -26,8 +26,8 @@ func copyField(executableName, copySubject string) {
writeToStdin(cmd, copySubject)
err = cmd.Start()
if err != nil {
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - Does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(110)
}
Exit(0) // only exit if clipboard clearing process is launched, otherwise assume continuous clipboard refresh
}
@@ -41,7 +41,7 @@ func clipClear(oldContents string) {
newContents, err := cmd.Output()
if err != nil {
fmt.Println(AnsiError + "Failed to read clipboard contents: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
if oldContents == strings.TrimRight(string(newContents), "\r\n") {
@@ -50,7 +50,7 @@ func clipClear(oldContents string) {
err = cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to clear clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
}
os.Exit(0) // use os.Exit instead of core.Exit, as this function runs out of a background subprocess that is invisible to the user (will never appear in GUI/TUI environment)
+9 -9
View File
@@ -20,15 +20,15 @@ func copyField(executableName, copySubject string) {
} else if _, envSet = os.LookupEnv("DISPLAY"); envSet {
cmd = exec.Command("xclip", "-sel", "c")
} else {
fmt.Println(AnsiError + "Clipboard platform could not be determined - note that the clipboard does not function in a raw TTY" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Clipboard platform could not be determined - Note that the clipboard does not function in a raw TTY" + AnsiReset)
os.Exit(110)
}
writeToStdin(cmd, copySubject)
err := cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
// launch clipboard clearing process if executableName is provided
@@ -37,8 +37,8 @@ func copyField(executableName, copySubject string) {
writeToStdin(cmd, copySubject)
err = cmd.Start()
if err != nil {
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - Does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(110)
}
Exit(0) // only exit if clipboard clearing process is launched, otherwise assume continuous clipboard refresh
}
@@ -58,15 +58,15 @@ func clipClear(oldContents string) {
cmdClear = exec.Command("xclip", "-i", "/dev/null", "-sel", "c")
cmdPaste = exec.Command("xclip", "-o", "-sel", "c")
} else {
fmt.Println(AnsiError + "Clipboard platform could not be determined - neither $WAYLAND_DISPLAY nor $DISPLAY are set" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Clipboard platform could not be determined - Neither $WAYLAND_DISPLAY nor $DISPLAY are set" + AnsiReset)
os.Exit(110)
}
// read current clipboard contents
newContents, err := cmdPaste.Output()
if err != nil {
fmt.Println(AnsiError + "Failed to read clipboard contents: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
// clear clipboard if contents have not been modified
@@ -74,7 +74,7 @@ func clipClear(oldContents string) {
err = cmdClear.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to clear clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
}
os.Exit(0) // use os.Exit instead of core.Exit, as this function runs out of a background subprocess that is invisible to the user (will never appear in GUI/TUI environment)
+5 -5
View File
@@ -16,7 +16,7 @@ func copyField(executableName, copySubject string) {
err := cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to copy to clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
// launch clipboard clearing process if executableName is provided
@@ -25,8 +25,8 @@ func copyField(executableName, copySubject string) {
writeToStdin(cmd, copySubject)
err = cmd.Start()
if err != nil {
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Failed to launch automated clipboard clearing process - Does this libmutton implementation support the \"clipclear\" argument?" + AnsiReset)
os.Exit(110)
}
Exit(0) // only exit if clipboard clearing process is launched, otherwise assume continuous clipboard refresh
}
@@ -40,7 +40,7 @@ func clipClear(oldContents string) {
newContents, err := cmd.Output()
if err != nil {
fmt.Println(AnsiError + "Failed to read clipboard contents: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
if oldContents == strings.TrimRight(string(newContents), "\r\n") {
@@ -48,7 +48,7 @@ func clipClear(oldContents string) {
err = cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to clear clipboard: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(110)
}
}
os.Exit(0) // use os.Exit instead of core.Exit, as this function runs out of a background subprocess that is invisible to the user (will never appear in GUI/TUI environment)
+5 -5
View File
@@ -7,7 +7,7 @@ import (
"strings"
)
// TODO GPG support is a temporary feature - it will be replaced with a different encryption scheme in the future
// TODO GPG support is a temporary feature - It will be replaced with a different encryption scheme in the future
// DecryptGPG decrypts a GPG-encrypted file and returns the contents as a slice of (trimmed) strings.
func DecryptGPG(targetLocation string) []string {
@@ -18,8 +18,8 @@ func DecryptGPG(targetLocation string) []string {
enableVirtualTerminalProcessing()
if err != nil {
fmt.Println(AnsiError + "Failed to decrypt \"" + targetLocation + "\" - ensure it is a valid GPG-encrypted file and that you entered your passphrase correctly" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Failed to decrypt \"" + targetLocation + "\" - Ensure it is a valid GPG-encrypted file and that you entered your passphrase correctly" + AnsiReset)
os.Exit(108)
}
outputSlice := strings.Split(string(output), "\n")
@@ -32,8 +32,8 @@ func EncryptGPG(input []string) []byte {
writeToStdin(cmd, strings.Join(input, "\n"))
encryptedBytes, err := cmd.Output()
if err != nil {
fmt.Println(AnsiError + "Failed to encrypt data - ensure that your GPG key is valid and that you have a valid GPG ID set in libmutton.ini" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Failed to encrypt data - Ensure that your GPG key is valid and that you have a valid GPG ID set in libmutton.ini" + AnsiReset)
os.Exit(109)
}
return encryptedBytes
}
+4 -4
View File
@@ -46,7 +46,7 @@ func GpgKeyGen() string {
err := cmd.Run()
if err != nil {
fmt.Println(AnsiError + "Failed to generate GPG key: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(111)
}
return "libmutton-" + unixTime + " (gpg-libmutton) <github.com/rwinkhart/libmutton>"
@@ -58,7 +58,7 @@ func DirInit(preserveOldConfigDir bool) {
err := os.MkdirAll(EntryRoot, 0700)
if err != nil {
fmt.Println(AnsiError + "Failed to create \"" + EntryRoot + "\":" + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(102)
}
// remove existing config directory (if it exists and not in append mode)
@@ -68,7 +68,7 @@ func DirInit(preserveOldConfigDir bool) {
err = os.RemoveAll(ConfigDir)
if err != nil {
fmt.Println(AnsiError + "Failed to remove existing config directory: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(102)
}
}
}
@@ -77,6 +77,6 @@ func DirInit(preserveOldConfigDir bool) {
err = os.MkdirAll(ConfigDir+PathSeparator+"devices", 0700)
if err != nil {
fmt.Println(AnsiError + "Failed to create \"" + ConfigDir + "\":" + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(102)
}
}
+8 -8
View File
@@ -18,8 +18,8 @@ func TargetIsFile(targetLocation string, errorOnFail bool, failCondition uint8)
targetInfo, err := os.Stat(targetLocation)
if err != nil {
if errorOnFail {
fmt.Println(AnsiError + "Failed to access \"" + targetLocation + "\" - ensure it exists and has the correct permissions" + AnsiReset)
os.Exit(1)
fmt.Println(AnsiError + "Failed to access \"" + targetLocation + "\" - Ensure it exists and has the correct permissions" + AnsiReset)
os.Exit(105)
} else {
return false, false
}
@@ -27,13 +27,13 @@ func TargetIsFile(targetLocation string, errorOnFail bool, failCondition uint8)
if targetInfo.IsDir() {
if errorOnFail && failCondition == 2 {
fmt.Println(AnsiError + "\"" + targetLocation + "\" is a directory" + AnsiReset)
os.Exit(1)
os.Exit(107)
}
return false, true
} else {
if errorOnFail && failCondition == 1 {
fmt.Println(AnsiError + "\"" + targetLocation + "\" is a file" + AnsiReset)
os.Exit(1)
os.Exit(107)
}
return true, true
}
@@ -45,7 +45,7 @@ func WriteEntry(targetLocation string, entryData []string, verifyEntryDoesNotExi
_, isAccessible := TargetIsFile(targetLocation, false, 0)
if isAccessible {
fmt.Println(AnsiError + "Target location already exists" + AnsiReset)
os.Exit(1)
os.Exit(106)
}
}
@@ -53,7 +53,7 @@ func WriteEntry(targetLocation string, entryData []string, verifyEntryDoesNotExi
err := os.WriteFile(targetLocation, encryptedBytes, 0600)
if err != nil {
fmt.Println(AnsiError + "Failed to write to file: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(102)
}
}
@@ -62,7 +62,7 @@ func writeToStdin(cmd *exec.Cmd, input string) {
stdin, err := cmd.StdinPipe()
if err != nil {
fmt.Println(AnsiError + "Failed to access stdin for system command: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(111)
}
go func() {
@@ -78,7 +78,7 @@ func CreateTempFile() *os.File {
tempFile, err := os.CreateTemp("", "*.markdown")
if err != nil {
fmt.Println(AnsiError + "Failed to create temporary file: " + err.Error() + AnsiReset)
os.Exit(1)
os.Exit(102)
}
return tempFile
}