mirror of https://github.com/databricks/cli.git
102 lines
2.0 KiB
Go
102 lines
2.0 KiB
Go
|
package exec
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"io"
|
||
|
"os"
|
||
|
osexec "os/exec"
|
||
|
)
|
||
|
|
||
|
type Command interface {
|
||
|
// Wait for command to terminate. It must have been previously started.
|
||
|
Wait() error
|
||
|
|
||
|
// StdinPipe returns a pipe that will be connected to the command's standard input when the command starts.
|
||
|
Stdout() io.ReadCloser
|
||
|
|
||
|
// StderrPipe returns a pipe that will be connected to the command's standard error when the command starts.
|
||
|
Stderr() io.ReadCloser
|
||
|
}
|
||
|
|
||
|
type command struct {
|
||
|
cmd *osexec.Cmd
|
||
|
execContext *execContext
|
||
|
stdout io.ReadCloser
|
||
|
stderr io.ReadCloser
|
||
|
}
|
||
|
|
||
|
func (c *command) Wait() error {
|
||
|
// After the command has finished (cmd.Wait call), remove the temporary script file
|
||
|
defer os.Remove(c.execContext.scriptFile)
|
||
|
|
||
|
err := c.cmd.Wait()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *command) Stdout() io.ReadCloser {
|
||
|
return c.stdout
|
||
|
}
|
||
|
|
||
|
func (c *command) Stderr() io.ReadCloser {
|
||
|
return c.stderr
|
||
|
}
|
||
|
|
||
|
type Executor struct {
|
||
|
interpreter interpreter
|
||
|
dir string
|
||
|
}
|
||
|
|
||
|
func NewCommandExecutor(dir string) (*Executor, error) {
|
||
|
interpreter, err := findInterpreter()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &Executor{
|
||
|
interpreter: interpreter,
|
||
|
dir: dir,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (e *Executor) StartCommand(ctx context.Context, command string) (Command, error) {
|
||
|
ec, err := e.interpreter.prepare(command)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return e.start(ctx, ec)
|
||
|
}
|
||
|
|
||
|
func (e *Executor) start(ctx context.Context, ec *execContext) (Command, error) {
|
||
|
cmd := osexec.CommandContext(ctx, ec.executable, ec.args...)
|
||
|
cmd.Dir = e.dir
|
||
|
|
||
|
stdout, err := cmd.StdoutPipe()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
stderr, err := cmd.StderrPipe()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &command{cmd, ec, stdout, stderr}, cmd.Start()
|
||
|
}
|
||
|
|
||
|
func (e *Executor) Exec(ctx context.Context, command string) ([]byte, error) {
|
||
|
cmd, err := e.StartCommand(ctx, command)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
res, err := io.ReadAll(io.MultiReader(cmd.Stdout(), cmd.Stderr()))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return res, cmd.Wait()
|
||
|
}
|