From 99fc1b7548c053c114e0ee0aaa6a65bc9d0e487f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= Date: Mon, 7 Jun 2021 14:11:27 +0200 Subject: [PATCH] pkg/podman: Add error parsing method This new helper type serves for parsing the output of Podman in stderr into a form that can be further analyzed. The most significant part is the method Is() that lexically compares error strings. This is needed because there are no defined errors to catch errors coming from Podman. https://github.com/containers/toolbox/pull/786 --- src/pkg/podman/podman.go | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/pkg/podman/podman.go b/src/pkg/podman/podman.go index 9099df1ea..caa34248e 100644 --- a/src/pkg/podman/podman.go +++ b/src/pkg/podman/podman.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "io" + "strings" "github.com/HarryMichal/go-version" "github.com/containers/toolbox/pkg/shell" @@ -332,3 +333,76 @@ func SystemMigrate(ociRuntimeRequired string) error { return nil } + +// internalError serves for representing errors printed by Podman to stderr +type internalError struct { + errors []string +} + +func (e *internalError) Error() string { + if e.errors == nil || len(e.errors) == 0 { + return "" + } + + var builder strings.Builder + for i, part := range e.errors { + if i != 0 { + builder.WriteString(": ") + } + builder.WriteString(part) + } + return builder.String() +} + +// Is lexically compares errors +// +// The comparison is done for every part in the error chain not across. +func (e *internalError) Is(target error) bool { + if target == nil { + return false + } + + if e.errors == nil || len(e.errors) == 0 { + return false + } + + for { + if e.errors[0] == target.Error() { + return true + } + + if e = e.Unwrap(); e == nil { + return false + } + } +} + +func (e internalError) Unwrap() *internalError { + if e.errors == nil || len(e.errors) <= 1 { + return nil + } + + return &internalError{e.errors[1:]} +} + +// parseErrorMsg serves for converting error output of Podman into an error +// that can be further used in Go +func parseErrorMsg(stderr *bytes.Buffer) error { + errMsg := stderr.String() + errMsg = strings.TrimSpace(errMsg) + // Podman error messages are usually prepended with the "Error: " string + errMsg = strings.TrimPrefix(errMsg, "Error: ") + // Sometimes an error contains a newline (e.g. responses from Docker + // registry). Normalize them into further parseable error message. + errMsg = strings.ReplaceAll(errMsg, "\n", "") + // Wrapped error messages are usually separated by a colon followed by + // a single space character + errMsgParts := strings.Split(errMsg, ": ") + // The parts of the err message still can have a whitespace at the + // beginning ar at the end. Trim them. + for i := range errMsgParts { + errMsgParts[i] = strings.TrimSpace(errMsgParts[i]) + } + + return &internalError{errMsgParts} +}