Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // fancy-ish log of a task step
- func logstep(text string) {
- fmt.Println(
- color.MagentaString(">"),
- color.New(color.Bold).Sprint(text),
- )
- }
- // command runner holds the metadata for a specific command
- type runner struct {
- cmd *exec.Cmd
- program string
- args []string
- okmsg string
- errmsg string
- quiet bool
- allowerr bool
- }
- // exec a command returning its error and pretty printing the ok and error messages
- func (r *runner) exec() error {
- if !r.quiet {
- logstep(fmt.Sprint(r.program, " ", strings.Join(r.args, " ")))
- }
- err := r.cmd.Run()
- if !r.allowerr && err != nil {
- if !r.quiet && r.errmsg != "" {
- color.Red(r.errmsg)
- }
- return err
- }
- if !r.quiet && r.okmsg != "" {
- color.Green(r.okmsg)
- }
- return nil
- }
- // build a command runner for a specific program
- func cmd(ctx context.Context, program string, opts ...runneropt) (*runner, error) {
- command := exec.CommandContext(ctx, program)
- command.Stdout = os.Stdout
- command.Stderr = os.Stderr
- r := runner{
- cmd: command,
- program: program,
- }
- for _, opt := range opts {
- err := opt(&r)
- if err != nil {
- return nil, err
- }
- }
- command.Args = append([]string{program}, r.args...)
- return &r, nil
- }
- // helper function to avoid repetition while gracefully handling errors
- func run(ctx context.Context, program string, opts ...runneropt) error {
- rnr, err := cmd(ctx, program, opts...)
- if err != nil {
- return err
- }
- return rnr.exec()
- }
- // options to customize the behaviour of the command runner
- type runneropt func(r *runner) error
- // sets up environment variables for the command
- func withenv(vars ...string) runneropt {
- return func(r *runner) error {
- r.cmd.Env = os.Environ()[:]
- for _, vrb := range vars {
- items := strings.Split(vrb, "=")
- if len(items) != 2 {
- return errors.New("")
- }
- r.cmd.Env = append(r.cmd.Env, vrb)
- }
- return nil
- }
- }
- // command arguments
- func withargs(args ...string) runneropt {
- return func(r *runner) error {
- r.args = args
- return nil
- }
- }
- // sets a message to be printed when the command finishes successfully
- func withokmsg(msg string) runneropt {
- return func(r *runner) error {
- r.okmsg = msg
- return nil
- }
- }
- // sets a message to be printed when the command fails
- func witherrmsg(msg string) runneropt {
- return func(r *runner) error {
- r.errmsg = msg
- return nil
- }
- }
- // sets the directory where the command should be run inside
- func withdir(dir string) runneropt {
- return func(r *runner) error {
- r.cmd.Dir = dir
- return nil
- }
- }
- // silences all output for the command; useful when handling that on the caller side
- func withoutnoise() runneropt {
- return func(r *runner) error {
- r.quiet = true
- r.cmd.Stdout = nil
- r.cmd.Stderr = nil
- return nil
- }
- }
- // set up stdout writer
- func withstdout(w io.Writer) runneropt {
- return func(r *runner) error {
- r.cmd.Stdout = w
- return nil
- }
- }
- // allow errors in the command
- func withallowerr() runneropt {
- return func(r *runner) error {
- r.allowerr = true
- return nil
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement