package runner import ( "bytes" "context" "fmt" "os/exec" ) type Runner interface { Run(context.Context, string, ...any) ([]byte, error) } type ZRunner struct { Prog string Args []string } func (runner *ZRunner) Run(ctx context.Context, command string, formatArgs ...any) ([]byte, error) { var subArgs string if len(formatArgs) > 0 { subArgs = fmt.Sprintf(command, formatArgs...) } else { subArgs = command } args := append(runner.Args, subArgs) cmd := exec.Command(runner.Prog, args...) return cmd.CombinedOutput() } func Pipeline(cmds ...*exec.Cmd) ([]byte, error) { for i := 0; i < len(cmds)-1; i++ { stdout, err := cmds[i].StdoutPipe() if err != nil { return nil, err } cmds[i+1].Stdin = stdout } out := bytes.Buffer{} cmds[len(cmds)-1].Stdout = &out for _, cmd := range cmds { err := cmd.Start() if err != nil { return out.Bytes(), err } } for _, cmd := range cmds { err := cmd.Wait() if err != nil { return out.Bytes(), err } } return out.Bytes(), nil }