From a3fbf30512c30a8c9fac051063954f5a64eff9f3 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Tue, 22 Dec 2020 19:12:46 +0100 Subject: Return package-specific error messages Instead of passing errors through to clients, wrap them with a "browserenv" error message to add context. Add new error types that can be matched against. --- browserenv.go | 17 ++++++++----- error.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 error.go diff --git a/browserenv.go b/browserenv.go index 6812700..eaff96e 100644 --- a/browserenv.go +++ b/browserenv.go @@ -50,7 +50,7 @@ func OpenFile(path string) error { if envCommand != "" { path, err := filepath.Abs(path) if err != nil { - return err + return &PathResolutionError{path, err} } url := "file://" + path @@ -70,12 +70,12 @@ func OpenReader(r io.Reader) error { if envCommand != "" { tempFile, err := ioutil.TempFile("", "browserenv") if err != nil { - return err + return &TempFileError{err} } _, err = io.Copy(tempFile, r) if err != nil { - return err + return &CopyError{err} } return OpenFile(tempFile.Name()) @@ -110,18 +110,23 @@ func runBrowserCommand(commands, url string) error { commandList := strings.Split(commands, commandSeparator) var err error + var lastCommand string for _, command := range commandList { cmd := browserCommand(command, url) // Keep running commands from left to right until one of them exits // successfully. err = cmd.Run() - if err == nil || cmd.ProcessState.ExitCode() == 0 { - return err + if err == nil { + return nil + } else if cmd.ProcessState.ExitCode() == 0 { + return &ExecZeroError{command, err} } + + lastCommand = command } - return err + return &ExecError{lastCommand, err} } // browserCommand sets up an exec.Cmd to run command, attaching Stdout and diff --git a/error.go b/error.go new file mode 100644 index 0000000..d90d1b8 --- /dev/null +++ b/error.go @@ -0,0 +1,76 @@ +package browserenv + +import "fmt" + +const errorPrefix = "browserenv: " + +// CopyError represents a failure to copy data. +type CopyError struct { + err error +} + +func (e *CopyError) Error() string { + return fmt.Sprintf(errorPrefix+"can't copy from reader: %v", e.err) +} + +func (e *CopyError) Unwrap() error { return e.err } + +// ExecError results from executing an external command. +type ExecError struct { + command string + err error +} + +func (e *ExecError) Error() string { + return fmt.Sprintf( + errorPrefix+"failed to run BROWSER command %q: %v", + e.command, + e.err, + ) +} + +func (e *ExecError) Unwrap() error { return e.err } + +// ExecZeroError results from executing an external command that produces an +// error with an exit code of 0. +type ExecZeroError struct { + command string + err error +} + +func (e *ExecZeroError) Error() string { + return fmt.Sprintf( + errorPrefix+"error running command %q: %v", + e.command, + e.err, + ) +} + +func (e *ExecZeroError) Unwrap() error { return e.err } + +// PathResolutionError means the given path couldn't be resolved. +type PathResolutionError struct { + path string + err error +} + +func (e *PathResolutionError) Error() string { + return fmt.Sprintf( + errorPrefix+"can't resolve path for %q: %v", + e.path, + e.err, + ) +} + +func (e *PathResolutionError) Unwrap() error { return e.err } + +// TempFileError corresponds to an error while creating a temporary file. +type TempFileError struct { + err error +} + +func (e *TempFileError) Error() string { + return fmt.Sprintf(errorPrefix+"can't create temporary file: %v", e.err) +} + +func (e *TempFileError) Unwrap() error { return e.err } -- cgit v1.2.3