Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,20 @@ import (
)

func main() {
exitStatus, err := panicwrap.BasicWrap(panicHandler)
done, exitStatus, err := panicwrap.BasicWrap(panicHandler)
if err != nil {
// Something went wrong setting up the panic wrapper. Unlikely,
// but possible.
panic(err)
}

// If exitStatus >= 0, then we're the parent process and the panicwrap
// If done, then we're the parent process and the panicwrap
// re-executed ourselves and completed. Just exit with the proper status.
if exitStatus >= 0 {
if done {
os.Exit(exitStatus)
}

// Otherwise, exitStatus < 0 means we're the child. Continue executing as
// Otherwise, !done means we're the child. Continue executing as
// normal...

// Let's say we panic
Expand Down
20 changes: 10 additions & 10 deletions panicwrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ type WrapConfig struct {
// BasicWrap calls Wrap with the given handler function, using defaults
// for everything else. See Wrap and WrapConfig for more information on
// functionality and return values.
func BasicWrap(f HandlerFunc) (int, error) {
func BasicWrap(f HandlerFunc) (done bool, statusCode int, err error) {
return Wrap(&WrapConfig{
Handler: f,
})
Expand All @@ -87,7 +87,7 @@ func BasicWrap(f HandlerFunc) (int, error) {
// Wrap wraps the current executable in a handler to catch panics. It
// returns an error if there was an error during the wrapping process.
// If the error is nil, then the int result indicates the exit status of the
// child process. If the exit status is -1, then this is the child process,
// child process. If the done flag is false, then this is the child process,
// and execution should continue as normal. Otherwise, this is the parent
// process and the child successfully ran already, and you should exit the
// process with the returned exit status.
Expand All @@ -97,9 +97,9 @@ func BasicWrap(f HandlerFunc) (int, error) {
//
// Once this is called, the given WrapConfig shouldn't be modified or used
// any further.
func Wrap(c *WrapConfig) (int, error) {
func Wrap(c *WrapConfig) (done bool, statusCode int, err error) {
if c.Handler == nil {
return -1, errors.New("Handler must be set")
return false, -1, errors.New("Handler must be set")
}

if c.DetectDuration == 0 {
Expand All @@ -112,13 +112,13 @@ func Wrap(c *WrapConfig) (int, error) {

// If we're already wrapped, exit out.
if Wrapped(c) {
return -1, nil
return false, -1, nil
}

// Get the path to our current executable
exePath, err := os.Executable()
if err != nil {
return -1, err
return false, -1, err
}

// Pipe the stderr so we can read all the data as we look for panics
Expand Down Expand Up @@ -165,7 +165,7 @@ func Wrap(c *WrapConfig) (int, error) {
}

if err := cmd.Start(); err != nil {
return 1, err
return true, 1, err
}

// Listen to signals and capture them forever. We allow the child
Expand Down Expand Up @@ -197,7 +197,7 @@ func Wrap(c *WrapConfig) (int, error) {
exitErr, ok := err.(*exec.ExitError)
if !ok {
// This is some other kind of subprocessing error.
return 1, err
return true, 1, err
}

exitStatus := 1
Expand All @@ -218,10 +218,10 @@ func Wrap(c *WrapConfig) (int, error) {
c.Handler(panicTxt)
}

return exitStatus, nil
return true, exitStatus, nil
}

return 0, nil
return true, 0, nil
}

// Wrapped checks if we're already wrapped according to the configuration
Expand Down
22 changes: 11 additions & 11 deletions panicwrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ func TestHelperProcess(*testing.T) {
cmd, args := args[0], args[1:]
switch cmd {
case "no-panic-ordered-output":
exitStatus, err := BasicWrap(panicHandler)
done, exitStatus, err := BasicWrap(panicHandler)
if err != nil {
fmt.Fprintf(os.Stderr, "wrap error: %s", err)
os.Exit(1)
}

if exitStatus < 0 {
if !done {
for i := 0; i < 1000; i++ {
os.Stdout.Write([]byte("a"))
os.Stderr.Write([]byte("b"))
Expand All @@ -80,14 +80,14 @@ func TestHelperProcess(*testing.T) {
fmt.Fprint(os.Stderr, "stderr out")
os.Exit(0)
case "panic-boundary":
exitStatus, err := BasicWrap(panicHandler)
done, exitStatus, err := BasicWrap(panicHandler)

if err != nil {
fmt.Fprintf(os.Stderr, "wrap error: %s", err)
os.Exit(1)
}

if exitStatus < 0 {
if !done {
// Simulate a panic but on two boundaries...
fmt.Fprint(os.Stderr, "pan")
os.Stderr.Sync()
Expand All @@ -98,14 +98,14 @@ func TestHelperProcess(*testing.T) {

os.Exit(exitStatus)
case "panic-long":
exitStatus, err := BasicWrap(panicHandler)
done, exitStatus, err := BasicWrap(panicHandler)

if err != nil {
fmt.Fprintf(os.Stderr, "wrap error: %s", err)
os.Exit(1)
}

if exitStatus < 0 {
if !done {
// Make a fake panic by faking the header and adding a
// bunch of garbage.
fmt.Fprint(os.Stderr, "panic: foo\n\n")
Expand Down Expand Up @@ -133,14 +133,14 @@ func TestHelperProcess(*testing.T) {
HidePanic: hidePanic,
}

exitStatus, err := Wrap(config)
done, exitStatus, err := Wrap(config)

if err != nil {
fmt.Fprintf(os.Stderr, "wrap error: %s", err)
os.Exit(1)
}

if exitStatus < 0 {
if !done {
panic("uh oh")
}

Expand All @@ -154,13 +154,13 @@ func TestHelperProcess(*testing.T) {
Handler: panicHandler,
}

exitStatus, err := Wrap(config)
done, exitStatus, err := Wrap(config)
if err != nil {
fmt.Fprintf(os.Stderr, "wrap error: %s", err)
os.Exit(1)
}

if exitStatus < 0 {
if !done {
if child {
fmt.Printf("%v", Wrapped(nil))
}
Expand All @@ -181,7 +181,7 @@ func TestHelperProcess(*testing.T) {
os.Exit(0)
}

exitCode, err := Wrap(config)
_, exitCode, err := Wrap(config)
if err != nil {
fmt.Fprintf(os.Stderr, "wrap error: %s", err)
os.Exit(1)
Expand Down