From 9281abad904f7cfec3aea9f616066dc9a2e0b6b5 Mon Sep 17 00:00:00 2001 From: Qi Xiao Date: Sun, 29 Jan 2017 17:56:13 +0000 Subject: [PATCH] Don't make PipelineError when only one command in a pipeline errs. --- eval/builtin-fn.go | 2 +- eval/compile_op.go | 22 ++++------------------ eval/exception.go | 38 +++++++++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/eval/builtin-fn.go b/eval/builtin-fn.go index 1d0ca637..735c7661 100644 --- a/eval/builtin-fn.go +++ b/eval/builtin-fn.go @@ -1101,7 +1101,7 @@ func fg(ec *EvalCtx, pids ...int) { } } - throwCompositeError(errors) + maybeThrow(ComposeExceptionsFromPipeline(errors)) } func tildeAbbr(ec *EvalCtx, path string) { diff --git a/eval/compile_op.go b/eval/compile_op.go index 808aca41..5045df02 100644 --- a/eval/compile_op.go +++ b/eval/compile_op.go @@ -100,8 +100,9 @@ func (cp *compiler) pipeline(n *parse.Pipeline) OpFunc { go func() { wg.Wait() msg := "job " + n.SourceText() + " finished" - if !allok(errors) { - msg += ", errors = " + makeCompositeError(errors).Error() + err := ComposeExceptionsFromPipeline(errors) + if err != nil { + msg += ", errors = " + err.Error() } if !verdict { msg += ", pred = false" @@ -122,27 +123,12 @@ func (cp *compiler) pipeline(n *parse.Pipeline) OpFunc { }() } else { wg.Wait() - maybeThrow(makeCompositeError(errors)) + maybeThrow(ComposeExceptionsFromPipeline(errors)) ec.verdict = verdict } } } -func makeCompositeError(errors []*Exception) error { - if allok(errors) { - return nil - } - if len(errors) == 1 { - return errors[0] - } else { - return PipelineError{errors} - } -} - -func throwCompositeError(errors []*Exception) { - maybeThrow(makeCompositeError(errors)) -} - func (cp *compiler) form(n *parse.Form) OpFunc { var saveVarsOps []LValuesOp var assignmentOps []Op diff --git a/eval/exception.go b/eval/exception.go index bd3530fd..989352fb 100644 --- a/eval/exception.go +++ b/eval/exception.go @@ -105,6 +105,35 @@ func (pe PipelineError) Error() string { return b.String() } +// ComposeExceptionsFromPipeline takes a slice of Exception pointers and +// composes a suitable error. If all elements of the slice are either nil or OK, +// a nil is returned. If there is exactly non-nil non-OK Exception, it is +// returned. Otherwise, a PipelineError built from the slice is returned, with +// nil items turned into OK's for easier access from elvishscript. +func ComposeExceptionsFromPipeline(excs []*Exception) error { + newexcs := make([]*Exception, len(excs)) + notOK, lastNotOK := 0, 0 + for i, e := range excs { + if e == nil { + newexcs[i] = OK + } else { + newexcs[i] = e + if e.Cause != nil { + notOK++ + lastNotOK = i + } + } + } + switch notOK { + case 0: + return nil + case 1: + return newexcs[lastNotOK] + default: + return PipelineError{newexcs} + } +} + // Flow is a special type of error used for control flows. type Flow uint @@ -180,12 +209,3 @@ func (exit ExternalCmdExit) Error() string { return fmt.Sprint(quotedName, " has unknown WaitStatus ", ws) } } - -func allok(es []*Exception) bool { - for _, e := range es { - if e != nil && e.Cause != nil { - return false - } - } - return true -}