blob: b1e5cdff6f9fcecc71af73ae3f6c3c780aa1dc26 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package execution
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"strings"
)
// Executor supports chaining subcommand execution and error handling.
type Executor struct {
stdout io.Writer
stderr io.Writer
dir string
}
// NewExecutor returns a new Executor that writes to stdout and stderr.
func NewExecutor(stdout, stderr io.Writer, dir string) *Executor {
return &Executor{stdout: stdout, stderr: stderr, dir: dir}
}
// Exec runs the command at path with args.
func (e Executor) Exec(ctx context.Context, path string, args ...string) error {
cmd := exec.CommandContext(ctx, path, args...)
cmd.Env = os.Environ()
cmd.Stdout = e.stdout
cmd.Stderr = e.stderr
cmd.Dir = e.dir
return cmd.Run()
}
// ExecAll runs all given commands. Upon encountering an error after execution
// stops and the error is returned. Returns an error if an element in cmds is
// empty.
func (e Executor) ExecAll(ctx context.Context, cmds [][]string) error {
for i, cmd := range cmds {
if len(cmd) == 0 {
return fmt.Errorf("forbidden empty list in cmds at position %d", i)
}
if err := e.Exec(ctx, cmd[0], cmd[1:]...); err != nil {
return fmt.Errorf("failed to exec cmd: %s; %v", strings.Join(cmd, " "), err)
}
}
return nil
}