in internal/util/util.go [22:74]
func ExecuteCommand(ctx context.Context, c []string, runAsUser string, envVars []string, stdin io.ReadCloser) (output CommandOutput, err error) {
// Separate name and args, plus catch a few error cases
var name string
var args []string
// Check the empty struct case ([]string{}) for the command
if len(c) == 0 {
return CommandOutput{}, fmt.Errorf("must provide a command")
}
// Set the name of the command and check if args are also provided
name = c[0]
if len(c) > 1 {
args = c[1:]
}
// Set command and create output buffers
cmd := exec.CommandContext(ctx, name, args...)
var stdoutb, stderrb bytes.Buffer
cmd.Stdout = &stdoutb
cmd.Stderr = &stderrb
// Set command stdin if the stdin parameter is provided
if stdin != nil {
cmd.Stdin = stdin
}
// Set runAsUser, if defined, otherwise will run as root
if runAsUser != "" {
uid, gid, err := getUIDandGID(runAsUser)
if err != nil {
return CommandOutput{Stdout: stdoutb.String(), Stderr: stderrb.String()}, fmt.Errorf("error looking up user: %w", err)
}
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
}
// Append environment variables
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, envVars...)
// Start the command's execution
if err = cmd.Start(); err != nil {
return CommandOutput{Stdout: stdoutb.String(), Stderr: stderrb.String()}, fmt.Errorf("error starting specified command: %w", err)
}
// Wait for the command to exit
if err = cmd.Wait(); err != nil {
return CommandOutput{Stdout: stdoutb.String(), Stderr: stderrb.String()}, fmt.Errorf("error waiting for specified command to exit: %w", err)
}
return CommandOutput{Stdout: stdoutb.String(), Stderr: stderrb.String()}, err
}