diff --git a/.gitignore b/.gitignore index 62f28681c..6e0986855 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +*.swp vendor .glide diff --git a/CHANGELOG.md b/CHANGELOG.md index 5af6d98c0..4fad695ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## Develop-Branch changes (unreleased) +BREAKING CHANGES: + +- [run] NewBaseService takes the new logger +- [cli] RunCaptureWithArgs now captures stderr and stdout + - +func RunCaptureWithArgs(cmd Executable, args []string, env map[string]string) (stdout, stderr string, err error) + - -func RunCaptureWithArgs(cmd Executable, args []string, env map[string]string) (output string, err error) + FEATURES: - [common] Date range parsing from string (ex. "2015-12-31:2017-12-31") diff --git a/cli/helper.go b/cli/helper.go index 79654bc34..845c17dbf 100644 --- a/cli/helper.go +++ b/cli/helper.go @@ -54,31 +54,40 @@ func RunWithArgs(cmd Executable, args []string, env map[string]string) error { return cmd.Execute() } -// RunCaptureWithArgs executes the given command with the specified command line args -// and environmental variables set. It returns whatever was writen to -// stdout along with any error returned from cmd.Execute() -func RunCaptureWithArgs(cmd Executable, args []string, env map[string]string) (output string, err error) { - old := os.Stdout // keep backup of the real stdout - r, w, _ := os.Pipe() - os.Stdout = w +// RunCaptureWithArgs executes the given command with the specified command +// line args and environmental variables set. It returns string fields +// representing output written to stdout and stderr, additionally any error +// from cmd.Execute() is also returned +func RunCaptureWithArgs(cmd Executable, args []string, env map[string]string) (stdout, stderr string, err error) { + oldout, olderr := os.Stdout, os.Stderr // keep backup of the real stdout + rOut, wOut, _ := os.Pipe() + rErr, wErr, _ := os.Pipe() + os.Stdout, os.Stderr = wOut, wErr defer func() { - os.Stdout = old // restoring the real stdout + os.Stdout, os.Stderr = oldout, olderr // restoring the real stdout }() - outC := make(chan string) // copy the output in a separate goroutine so printing can't block indefinitely - go func() { - var buf bytes.Buffer - // io.Copy will end when we call w.Close() below - io.Copy(&buf, r) - outC <- buf.String() - }() + copyStd := func(reader *os.File) *(chan string) { + stdC := make(chan string) + go func() { + var buf bytes.Buffer + // io.Copy will end when we call reader.Close() below + io.Copy(&buf, reader) + stdC <- buf.String() + }() + return &stdC + } + outC := copyStd(rOut) + errC := copyStd(rErr) // now run the command err = RunWithArgs(cmd, args, env) // and grab the stdout to return - w.Close() - output = <-outC - return output, err + wOut.Close() + wErr.Close() + stdout = <-*outC + stderr = <-*errC + return stdout, stderr, err } diff --git a/cli/setup.go b/cli/setup.go index 35362ed81..78151015b 100644 --- a/cli/setup.go +++ b/cli/setup.go @@ -97,9 +97,9 @@ func (e Executor) Execute() error { err := e.Command.Execute() if err != nil { if viper.GetBool(TraceFlag) { - fmt.Printf("ERROR: %+v\n", err) + fmt.Fprintf(os.Stderr, "ERROR: %+v\n", err) } else { - fmt.Println("ERROR:", err.Error()) + fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) } // return error code 1 by default, can override it with a special error type diff --git a/cli/setup_test.go b/cli/setup_test.go index 36cbbcc90..4e606ac7a 100644 --- a/cli/setup_test.go +++ b/cli/setup_test.go @@ -223,9 +223,11 @@ func TestSetupTrace(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) - out, err := RunCaptureWithArgs(cmd, args, tc.env) + stdout, stderr, err := RunCaptureWithArgs(cmd, args, tc.env) require.NotNil(err, i) - msg := strings.Split(out, "\n") + require.Equal("", stdout, i) + require.NotEqual("", stderr, i) + msg := strings.Split(stderr, "\n") desired := fmt.Sprintf("ERROR: %s", tc.expected) assert.Equal(desired, msg[0], i) if tc.long && assert.True(len(msg) > 2, i) {