feat: add WithContext functions for all subprocess-related code
Also deprecate the existing subprocess calls.
This commit is contained in:
@@ -3,8 +3,10 @@ package common
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"context"
|
||||
@@ -13,21 +15,76 @@ import (
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
// ExecCommandInput is the input for the ExecCommand function
|
||||
type ExecCommandInput struct {
|
||||
Command string
|
||||
Args []string
|
||||
// Command is the command to execute
|
||||
Command string
|
||||
|
||||
// Args are the arguments to pass to the command
|
||||
Args []string
|
||||
|
||||
// CaptureOutput determines whether to capture the output of the command
|
||||
CaptureOutput bool
|
||||
Env map[string]string
|
||||
StreamStdio bool
|
||||
|
||||
// Env is the environment variables to pass to the command
|
||||
Env map[string]string
|
||||
|
||||
// Stdin is the stdin of the command
|
||||
Stdin io.Reader
|
||||
|
||||
// StreamStdio prints stdout and stderr directly to os.Stdout/err as
|
||||
// the command runs
|
||||
StreamStdio bool
|
||||
|
||||
// StreamStdout prints stdout directly to os.Stdout as the command runs.
|
||||
StreamStdout bool
|
||||
|
||||
// StreamStderr prints stderr directly to os.Stderr as the command runs.
|
||||
StreamStderr bool
|
||||
|
||||
// Sudo runs the command with sudo -n -u root
|
||||
Sudo bool
|
||||
}
|
||||
|
||||
func CallExecCommand(input ExecCommandInput) (execute.ExecResult, error) {
|
||||
// ExecCommandResponse is the response for the ExecCommand function
|
||||
type ExecCommandResponse struct {
|
||||
// Stdout is the stdout of the command
|
||||
Stdout string
|
||||
|
||||
// Stderr is the stderr of the command
|
||||
Stderr string
|
||||
|
||||
// ExitCode is the exit code of the command
|
||||
ExitCode int
|
||||
|
||||
// Cancelled is whether the command was cancelled
|
||||
Cancelled bool
|
||||
}
|
||||
|
||||
// StdoutContents returns the trimmed stdout of the command
|
||||
func (ecr ExecCommandResponse) StdoutContents() string {
|
||||
return strings.TrimSpace(ecr.Stdout)
|
||||
}
|
||||
|
||||
// StderrContents returns the trimmed stderr of the command
|
||||
func (ecr ExecCommandResponse) StderrContents() string {
|
||||
return strings.TrimSpace(ecr.Stderr)
|
||||
}
|
||||
|
||||
// CallExecCommand executes a command on the local host
|
||||
func CallExecCommand(input ExecCommandInput) (ExecCommandResponse, error) {
|
||||
ctx := context.Background()
|
||||
return CallExecCommandWithContext(ctx, input)
|
||||
}
|
||||
|
||||
// CallExecCommandWithContext executes a command on the local host with the given context
|
||||
func CallExecCommandWithContext(ctx context.Context, input ExecCommandInput) (ExecCommandResponse, error) {
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, os.Interrupt, syscall.SIGHUP,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGQUIT,
|
||||
syscall.SIGTERM)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
go func() {
|
||||
<-signals
|
||||
cancel()
|
||||
@@ -47,9 +104,16 @@ func CallExecCommand(input ExecCommandInput) (execute.ExecResult, error) {
|
||||
}
|
||||
}
|
||||
|
||||
command := input.Command
|
||||
commandArgs := input.Args
|
||||
if input.Sudo {
|
||||
commandArgs = append([]string{"-n", "-u", "root", command}, commandArgs...)
|
||||
command = "sudo"
|
||||
}
|
||||
|
||||
cmd := execute.ExecTask{
|
||||
Command: input.Command,
|
||||
Args: input.Args,
|
||||
Command: command,
|
||||
Args: commandArgs,
|
||||
Env: env,
|
||||
DisableStdioBuffer: !input.CaptureOutput,
|
||||
}
|
||||
@@ -58,22 +122,45 @@ func CallExecCommand(input ExecCommandInput) (execute.ExecResult, error) {
|
||||
cmd.PrintCommand = true
|
||||
}
|
||||
|
||||
if isatty {
|
||||
if input.Stdin != nil {
|
||||
cmd.Stdin = input.Stdin
|
||||
} else if isatty {
|
||||
cmd.Stdin = os.Stdin
|
||||
}
|
||||
|
||||
if input.StreamStdio {
|
||||
cmd.StreamStdio = true
|
||||
}
|
||||
if input.StreamStdout {
|
||||
cmd.StdOutWriter = os.Stdout
|
||||
}
|
||||
if input.StreamStderr {
|
||||
cmd.StdErrWriter = os.Stderr
|
||||
}
|
||||
|
||||
res, err := cmd.Execute(ctx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
return ExecCommandResponse{
|
||||
Stdout: res.Stdout,
|
||||
Stderr: res.Stderr,
|
||||
ExitCode: res.ExitCode,
|
||||
Cancelled: res.Cancelled,
|
||||
}, err
|
||||
}
|
||||
|
||||
if res.ExitCode != 0 {
|
||||
return res, errors.New(res.Stderr)
|
||||
return ExecCommandResponse{
|
||||
Stdout: res.Stdout,
|
||||
Stderr: res.Stderr,
|
||||
ExitCode: res.ExitCode,
|
||||
Cancelled: res.Cancelled,
|
||||
}, errors.New(res.Stderr)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return ExecCommandResponse{
|
||||
Stdout: res.Stdout,
|
||||
Stderr: res.Stderr,
|
||||
ExitCode: res.ExitCode,
|
||||
Cancelled: res.Cancelled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user