diff --git a/acceptance/bundle/exec/cmd-not-found/output.txt b/acceptance/bundle/exec/cmd-not-found/output.txt index 36db64667..8344948b4 100644 --- a/acceptance/bundle/exec/cmd-not-found/output.txt +++ b/acceptance/bundle/exec/cmd-not-found/output.txt @@ -1,5 +1,5 @@ >>> [CLI] bundle exec -- doesnotexist arg1 arg2 --flag1 --flag2 -Error: Running "doesnotexist arg1 arg2 --flag1 --flag2" failed: exec: "doesnotexist": executable file not found in $PATH +Error: starting "doesnotexist arg1 arg2 --flag1 --flag2" failed: exec: "doesnotexist": executable file not found in $PATH Exit code: 1 diff --git a/acceptance/bundle/exec/databricks-cli/profile-is-passed/output.txt b/acceptance/bundle/exec/databricks-cli/profile-is-passed/output.txt index 06cdd1c44..1c1b74058 100644 --- a/acceptance/bundle/exec/databricks-cli/profile-is-passed/output.txt +++ b/acceptance/bundle/exec/databricks-cli/profile-is-passed/output.txt @@ -1,12 +1,12 @@ >>> [CLI] bundle exec -- [CLI] current-user me { - "id":"[USERID]", - "userName":"[USERNAME]" +"id":"[USERID]", +"userName":"[USERNAME]" } >>> [CLI] bundle exec --profile myprofile -- [CLI] current-user me { - "id":"[USERID]", - "userName":"[USERNAME]" +"id":"[USERID]", +"userName":"[USERNAME]" } diff --git a/acceptance/bundle/exec/databricks-cli/target-is-passed/output.txt b/acceptance/bundle/exec/databricks-cli/target-is-passed/output.txt index 84a9653e9..0fce7c1a7 100644 --- a/acceptance/bundle/exec/databricks-cli/target-is-passed/output.txt +++ b/acceptance/bundle/exec/databricks-cli/target-is-passed/output.txt @@ -1,14 +1,14 @@ >>> [CLI] bundle exec -- [CLI] current-user me { - "id":"[USERID]", - "userName":"[USERNAME]" +"id":"[USERID]", +"userName":"[USERNAME]" } >>> [CLI] bundle exec -t pat -- [CLI] current-user me { - "id":"[USERID]", - "userName":"[USERNAME]" +"id":"[USERID]", +"userName":"[USERNAME]" } >>> errcode [CLI] bundle exec -t pat -- [CLI] current-user me -t oauth @@ -19,6 +19,6 @@ Exit code: 1 >>> [CLI] bundle exec -t oauth -- [CLI] current-user me { - "id":"[USERID]", - "userName":"[USERNAME]" +"id":"[USERID]", +"userName":"[USERNAME]" } diff --git a/cmd/bundle/exec.go b/cmd/bundle/exec.go index dbd7d1156..e914f8844 100644 --- a/cmd/bundle/exec.go +++ b/cmd/bundle/exec.go @@ -1,9 +1,11 @@ package bundle import ( + "bufio" "fmt" "os/exec" "strings" + "sync" "github.com/databricks/cli/bundle/config/mutator" "github.com/databricks/cli/cmd/root" @@ -89,12 +91,71 @@ Example usage: // adding support for the scripts section. childCmd.Dir = b.BundleRootPath - // Stream the stdout and stderr of the child process directly. - childCmd.Stdout = cmd.OutOrStdout() - childCmd.Stderr = cmd.ErrOrStderr() + stdout, err := childCmd.StdoutPipe() + if err != nil { + return fmt.Errorf("creating stdout pipe failed: %w", err) + } - // Run the command. - err := childCmd.Run() + stderr, err := childCmd.StderrPipe() + if err != nil { + return fmt.Errorf("creating stderr pipe failed: %w", err) + } + + // Start the child command. + err = childCmd.Start() + if err != nil { + return fmt.Errorf("starting %q failed: %w", strings.Join(args, " "), err) + } + + var wg sync.WaitGroup + wg.Add(2) + + var stdoutErr error + go func() { + reader := bufio.NewReader(stdout) + line, err := reader.ReadString('\n') + for err == nil { + _, err = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", strings.TrimSpace(line)) + if err != nil { + stdoutErr = err + break + } + line, err = reader.ReadString('\n') + } + + wg.Done() + }() + + var stderrErr error + go func() { + reader := bufio.NewReader(stderr) + // TODO CONTINUE: The formatting is messed u[] because of the new line business + // here. + // Fix that. + line, err := reader.ReadString('\n') + for err == nil { + _, err = fmt.Fprintf(cmd.ErrOrStderr(), "%s\n", strings.TrimSpace(line)) + if err != nil { + stderrErr = err + break + } + line, err = reader.ReadString('\n') + } + + wg.Done() + }() + + wg.Wait() + + if stdoutErr != nil { + return fmt.Errorf("writing stdout failed: %w", stdoutErr) + } + + if stderrErr != nil { + return fmt.Errorf("writing stderr failed: %w", stderrErr) + } + + err = childCmd.Wait() if exitErr, ok := err.(*exec.ExitError); ok { // We don't make the parent CLI process exit with the same exit code // as the child process because the exit codes for the CLI have not @@ -108,10 +169,7 @@ Example usage: } } if err != nil { - return &runErr{ - err: err, - args: args, - } + return fmt.Errorf("running %q failed: %w", strings.Join(args, " "), err) } return nil