2023-09-27 09:04:44 +00:00
|
|
|
package process
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/databricks/cli/libs/env"
|
|
|
|
"github.com/databricks/cli/libs/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ProcessError struct {
|
|
|
|
Command string
|
|
|
|
Err error
|
|
|
|
Stdout string
|
|
|
|
Stderr string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (perr *ProcessError) Unwrap() error {
|
|
|
|
return perr.Err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (perr *ProcessError) Error() string {
|
|
|
|
return fmt.Sprintf("%s: %s", perr.Command, perr.Err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Background(ctx context.Context, args []string, opts ...execOption) (string, error) {
|
|
|
|
commandStr := strings.Join(args, " ")
|
|
|
|
log.Debugf(ctx, "running: %s", commandStr)
|
|
|
|
cmd := exec.CommandContext(ctx, args[0], args[1:]...)
|
|
|
|
stdout := bytes.Buffer{}
|
|
|
|
stderr := bytes.Buffer{}
|
|
|
|
// For background processes, there's no standard input
|
|
|
|
cmd.Stdin = nil
|
|
|
|
cmd.Stdout = &stdout
|
|
|
|
cmd.Stderr = &stderr
|
|
|
|
// we pull the env through lib/env such that we can run
|
|
|
|
// parallel tests with anything using libs/process.
|
|
|
|
for k, v := range env.All(ctx) {
|
|
|
|
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v))
|
|
|
|
}
|
|
|
|
for _, o := range opts {
|
|
|
|
err := o(ctx, cmd)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
Added process stubbing for easier testing of launched subprocesses (#963)
## Changes
This PR makes unit testing with subprocesses fast.
```
ctx := context.Background()
ctx, stub := process.WithStub(ctx)
stub.WithDefaultOutput("meeee")
ctx = env.Set(ctx, "FOO", "bar")
out, err := process.Background(ctx, []string{"/usr/local/bin/meeecho", "1", "--foo", "bar"})
require.NoError(t, err)
require.Equal(t, "meeee", out)
require.Equal(t, 1, stub.Len())
require.Equal(t, []string{"meeecho 1 --foo bar"}, stub.Commands())
allEnv := stub.CombinedEnvironment()
require.Equal(t, "bar", allEnv["FOO"])
require.Equal(t, "bar", stub.LookupEnv("FOO"))
```
This should make further iterations of
https://github.com/databricks/cli/pull/914 easier
## Tests
`make test`
2023-11-09 14:24:05 +00:00
|
|
|
if err := runCmd(ctx, cmd); err != nil {
|
2023-09-27 09:04:44 +00:00
|
|
|
return stdout.String(), &ProcessError{
|
|
|
|
Err: err,
|
|
|
|
Command: commandStr,
|
|
|
|
Stdout: stdout.String(),
|
|
|
|
Stderr: stderr.String(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return stdout.String(), nil
|
|
|
|
}
|