Files
backrest/pkg/restic/error.go

97 lines
1.8 KiB
Go

package restic
import (
"bytes"
"fmt"
"os/exec"
)
const outputBufferLimit = 1000
type CmdError struct {
Command string
Err error
}
func (e *CmdError) Error() string {
m := fmt.Sprintf("command %q failed: %s", e.Command, e.Err.Error())
return m
}
func (e *CmdError) Unwrap() error {
return e.Err
}
func (e *CmdError) Is(target error) bool {
_, ok := target.(*CmdError)
return ok
}
// newCmdError creates a new error indicating that running a command failed.
func newCmdError(cmd *exec.Cmd, err error) *CmdError {
shortCmd := cmd.String()
if len(shortCmd) > 100 {
shortCmd = shortCmd[:100] + "..."
}
cerr := &CmdError{
Command: shortCmd,
Err: err,
}
return cerr
}
type ErrorWithOutput struct {
Err error
Output string
}
func (e *ErrorWithOutput) Error() string {
return fmt.Sprintf("%v\nOutput:\n%s", e.Err, e.Output)
}
func (e *ErrorWithOutput) Unwrap() error {
return e.Err
}
func (e *ErrorWithOutput) Is(target error) bool {
_, ok := target.(*ErrorWithOutput)
return ok
}
type errorMessageCollector struct {
Output *bytes.Buffer
DroppedBytes int
}
func (e *errorMessageCollector) Write(p []byte) (int, error) {
if e.Output == nil {
e.Output = &bytes.Buffer{}
}
if e.Output.Len() >= outputBufferLimit {
e.DroppedBytes += len(p)
return len(p), nil
}
return e.Output.Write(p)
}
func (e *errorMessageCollector) AddOutputToError(err error) error {
if e.Output == nil {
return err
}
if e.DroppedBytes > 0 {
return &ErrorWithOutput{
Err: err,
Output: fmt.Sprintf("%s\n... %d bytes truncated ...", e.Output.String(), e.DroppedBytes),
}
}
return &ErrorWithOutput{
Err: err,
Output: e.Output.String(),
}
}
func (e *errorMessageCollector) AddCmdOutputToError(cmd *exec.Cmd, err error) error {
return newCmdError(cmd, e.AddOutputToError(err))
}