From 6283915f862814e73f32763e6527c378e20dd493 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Sun, 28 Jul 2024 09:08:10 -0400 Subject: [PATCH] main: format exit errors as JSON when using --json --- changelog/unreleased/issue-4948 | 6 +++++ cmd/restic/main.go | 42 ++++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 changelog/unreleased/issue-4948 diff --git a/changelog/unreleased/issue-4948 b/changelog/unreleased/issue-4948 new file mode 100644 index 000000000..3fd350d0d --- /dev/null +++ b/changelog/unreleased/issue-4948 @@ -0,0 +1,6 @@ +Enhancement: Format exit errors as JSON with --json + +Restic now prints any exit error messages as JSON when requested. + +https://github.com/restic/restic/issues/4948 +https://github.com/restic/restic/pull/4952 diff --git a/cmd/restic/main.go b/cmd/restic/main.go index 5818221a5..fda53ca0e 100644 --- a/cmd/restic/main.go +++ b/cmd/restic/main.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "context" + "encoding/json" "fmt" "log" "os" @@ -102,6 +103,30 @@ func tweakGoGC() { } } +func printExitError(code int, message string) { + if globalOptions.JSON { + type jsonExitError struct { + MessageType string `json:"message_type"` // exit_error + Code int `json:"code"` + Message string `json:"message"` + } + + jsonS := jsonExitError{ + MessageType: "exit_error", + Code: code, + Message: message, + } + + err := json.NewEncoder(globalOptions.stderr).Encode(jsonS) + if err != nil { + Warnf("JSON encode failed: %v\n", err) + return + } + } else { + fmt.Fprintf(globalOptions.stderr, "%v\n", message) + } +} + func main() { tweakGoGC() // install custom global logger into a buffer, if an error occurs @@ -131,21 +156,22 @@ func main() { err = nil } + var exitMessage string switch { case restic.IsAlreadyLocked(err): - fmt.Fprintf(os.Stderr, "%v\nthe `unlock` command can be used to remove stale locks\n", err) + exitMessage = fmt.Sprintf("%v\nthe `unlock` command can be used to remove stale locks", err) case err == ErrInvalidSourceData: - fmt.Fprintf(os.Stderr, "Warning: %v\n", err) + exitMessage = fmt.Sprintf("Warning: %v", err) case errors.IsFatal(err): - fmt.Fprintf(os.Stderr, "%v\n", err) + exitMessage = err.Error() case err != nil: - fmt.Fprintf(os.Stderr, "%+v\n", err) + exitMessage = fmt.Sprintf("%+v", err) if logBuffer.Len() > 0 { - fmt.Fprintf(os.Stderr, "also, the following messages were logged by a library:\n") + exitMessage += "also, the following messages were logged by a library:\n" sc := bufio.NewScanner(logBuffer) for sc.Scan() { - fmt.Fprintln(os.Stderr, sc.Text()) + exitMessage += fmt.Sprintln(sc.Text()) } } } @@ -165,5 +191,9 @@ func main() { default: exitCode = 1 } + + if exitCode != 0 { + printExitError(exitCode, exitMessage) + } Exit(exitCode) }