package main import ( "context" "errors" "os/exec" "strings" "time" ) func runCommand(timeout time.Duration, command string, args []string) (*cmdResponse, error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() cmd := exec.CommandContext(ctx, command, args...) var stdout, stderr strings.Builder cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() // if the command exits with a non-zero exit code, // we still want to return a valid cmdResponse var exitError *exec.ExitError if err != nil && !errors.As(err, &exitError) { return nil, err } if errors.Is(ctx.Err(), context.DeadlineExceeded) { return nil, ctx.Err() } response := cmdResponse{ ExitCode: cmd.ProcessState.ExitCode(), Stdout: stdout.String(), Stderr: stderr.String(), } return &response, nil }