diff --git a/src/pkg/podman/podman.go b/src/pkg/podman/podman.go index 9099df1ea..39a7867c9 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,83 @@ 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) + // 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 + errMsgPartsRaw := strings.Split(errMsg, ": ") + // The parts of the err message still can have a whitespace at the + // beginning ar at the end. Trim them. + var errMsgParts []string + for _, part := range errMsgPartsRaw { + part = strings.TrimSpace(part) + // Podman error messages are usually prepended with the "Error: " string + // Sometimes the error contains errors in a bullet list. This list is + // usually prepended with a message equal to "errors:" + if part == "Error" || part == "errors:" { + continue + } + + errMsgParts = append(errMsgParts, part) + } + + return &internalError{errMsgParts} +}