diff --git a/.gitignore b/.gitignore index 381931381..f37225baa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.swp *.swo +vendor diff --git a/cli/helper.go b/cli/helper.go new file mode 100644 index 000000000..b0662c78d --- /dev/null +++ b/cli/helper.go @@ -0,0 +1,64 @@ +package cli + +import ( + "bytes" + "io" + "os" +) + +// RunWithArgs executes the given command with the specified command line args +// and environmental variables set. It returns any error returned from cmd.Execute() +func RunWithArgs(cmd Executable, args []string, env map[string]string) error { + oargs := os.Args + oenv := map[string]string{} + // defer returns the environment back to normal + defer func() { + os.Args = oargs + for k, v := range oenv { + os.Setenv(k, v) + } + }() + + // set the args and env how we want them + os.Args = args + for k, v := range env { + // backup old value if there, to restore at end + oenv[k] = os.Getenv(k) + err := os.Setenv(k, v) + if err != nil { + return err + } + } + + // and finally run the command + 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 + defer func() { + os.Stdout = old // 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() + }() + + // now run the command + err = RunWithArgs(cmd, args, env) + + // and grab the stdout to return + w.Close() + output = <-outC + return output, err +} diff --git a/cli/setup_test.go b/cli/setup_test.go index 169b14004..34877209d 100644 --- a/cli/setup_test.go +++ b/cli/setup_test.go @@ -1,11 +1,8 @@ package cli import ( - "bytes" "fmt" - "io" "io/ioutil" - "os" "path/filepath" "strconv" "strings" @@ -54,7 +51,7 @@ func TestSetupEnv(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) - err := runWithArgs(cmd, args, tc.env) + err := RunWithArgs(cmd, args, tc.env) require.Nil(err, i) assert.Equal(tc.expected, foo, i) } @@ -120,7 +117,7 @@ func TestSetupConfig(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) - err := runWithArgs(cmd, args, tc.env) + err := RunWithArgs(cmd, args, tc.env) require.Nil(err, i) assert.Equal(tc.expected, foo, i) } @@ -197,7 +194,7 @@ func TestSetupUnmarshal(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) - err := runWithArgs(cmd, args, tc.env) + err := RunWithArgs(cmd, args, tc.env) require.Nil(err, i) assert.Equal(tc.expected, cfg, i) } @@ -231,7 +228,7 @@ func TestSetupDebug(t *testing.T) { viper.Reset() args := append([]string{cmd.Use}, tc.args...) - out, err := runCaptureWithArgs(cmd, args, tc.env) + out, err := RunCaptureWithArgs(cmd, args, tc.env) require.NotNil(err, i) msg := strings.Split(out, "\n") desired := fmt.Sprintf("ERROR: %s", tc.expected) @@ -243,60 +240,3 @@ func TestSetupDebug(t *testing.T) { } } } - -// runWithArgs executes the given command with the specified command line args -// and environmental variables set. It returns any error returned from cmd.Execute() -func runWithArgs(cmd Executable, args []string, env map[string]string) error { - oargs := os.Args - oenv := map[string]string{} - // defer returns the environment back to normal - defer func() { - os.Args = oargs - for k, v := range oenv { - os.Setenv(k, v) - } - }() - - // set the args and env how we want them - os.Args = args - for k, v := range env { - // backup old value if there, to restore at end - oenv[k] = os.Getenv(k) - err := os.Setenv(k, v) - if err != nil { - return err - } - } - - // and finally run the command - 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 - defer func() { - os.Stdout = old // 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() - }() - - // now run the command - err = runWithArgs(cmd, args, env) - - // and grab the stdout to return - w.Close() - output = <-outC - return output, err -}