func (w *Worker) ExecBin(binPath string, args []string, maxRunTime int64) (string, error) { var cmd *exec.Cmd var stdout bytes.Buffer var stderr bytes.Buffer var err error if len(args) == 0 { cmd = exec.Command(binPath) } else { cmd = exec.Command(binPath, args...) } cmd.Stdout = &stdout cmd.Stderr = &stderr cmd.Start() // attention! err, _ = w.CmdRunWithTimeout(cmd, time.Duration(maxRunTime)*time.Second, ) if err != nil { return "", err } if len(stderr.String()) != 0 { errMsg := strings.TrimRight(stderr.String(), "\n") return "", errors.NewError(errMsg) } return strings.TrimRight(stdout.String(), "\n"), nil }
func runCmd(cmd *exec.Cmd) error { if buildX { dir := "" if cmd.Dir != "" { dir = "PWD=" + cmd.Dir + " " } env := strings.Join(cmd.Env, " ") if env != "" { env += " " } printcmd("%s%s%s", dir, env, strings.Join(cmd.Args, " ")) } buf := new(bytes.Buffer) buf.WriteByte('\n') if buildV { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr } else { cmd.Stdout = buf cmd.Stderr = buf } if !buildN { cmd.Env = environ(cmd.Env) if err := cmd.Run(); err != nil { return fmt.Errorf("%s failed: %v%s", strings.Join(cmd.Args, " "), err, buf) } } return nil }
func (r *AssetRoot) CloneRepo() error { var cmd *exec.Cmd repoHash := md5.Sum([]byte(r.GitRepo)) if err := os.MkdirAll(".gitrepos", os.ModePerm); err != nil { return err } cloneDir := filepath.Join(".gitrepos", fmt.Sprintf("%x", repoHash)) r.Path = filepath.Join(cloneDir, r.Path) if _, err := os.Stat(cloneDir); err != nil { cmd = exec.Command("git", "clone", r.GitRepo, "--branch", r.GitBranch, cloneDir) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return err } } if r.GitRef == "" { return nil } cmd = exec.Command("bash", "-c", strings.Join([]string{ "cd", cloneDir, "&&", "git", "checkout", r.GitRef, "&&", "cd", "../../", }, " ")) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() }
func finishRunning(stepName string, cmd *exec.Cmd) bool { log.Printf("Running: %v", stepName) stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil) if *verbose { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr } else { cmd.Stdout = stdout cmd.Stderr = stderr } done := make(chan struct{}) defer close(done) go func() { for { select { case <-done: return case s := <-signals: cmd.Process.Signal(s) } } }() if err := cmd.Run(); err != nil { log.Printf("Error running %v: %v", stepName, err) if !*verbose { fmt.Printf("stdout:\n------\n%v\n------\n", string(stdout.Bytes())) fmt.Printf("stderr:\n------\n%v\n------\n", string(stderr.Bytes())) } return false } return true }
func runPlayer(command string, msgPath string) (*exec.Cmd, io.WriteCloser, io.ReadCloser, error) { if argv := strings.Fields(command); len(argv) == 0 { return nil, nil, nil, os.ErrInvalid } else if name, err := exec.LookPath(argv[0]); err != nil { return nil, nil, nil, err } else if dir, err := os.Getwd(); err != nil { return nil, nil, nil, err } else { cmd := exec.Cmd{Path: name, Args: argv, Dir: dir} if stdin, err := cmd.StdinPipe(); err != nil { return nil, nil, nil, err } else if stdout, err := cmd.StdoutPipe(); err != nil { return nil, nil, nil, err } else { if msgPath == "-" { cmd.Stderr = os.Stderr } else if msgPath != "" { if w, err := os.Create(msgPath); err != nil { // Connect to stderr instead fmt.Fprintln(os.Stderr, err) cmd.Stderr = os.Stderr } else { cmd.Stderr = w } } if err := cmd.Start(); err != nil { return nil, nil, nil, err } return &cmd, stdin, stdout, nil } } }
func AppendStderrWriter(cmd *exec.Cmd, writer io.Writer) { if cmd.Stderr == nil { cmd.Stderr = writer } else { cmd.Stderr = io.MultiWriter(cmd.Stderr, writer) } }
func (r *AgRecipe) Build(ctx *types.BuildContext) error { log.Info("Building the_silver_searcher") srcdir := r.UnpackedDir(ctx, r.Info()) var cmd *exec.Cmd // Run autotools cmd = exec.Command("autoreconf", "-i") cmd.Dir = srcdir cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { log.WithField("err", err).Error("Could not run autotools") return err } log.Infof("Running ./configure") cmd = exec.Command( "./configure", "--host="+ctx.CrossPrefix, "--build=i686", "PKG_CONFIG=/bin/true", ) cmd.Dir = srcdir cmd.Env = ctx.Env. Append("CC", ctx.StaticFlags). Set("CFLAGS", "-fPIC "+ctx.StaticFlags). Set("PCRE_LIBS", ctx.DependencyEnv["pcre"]["LDFLAGS"]). Set("PCRE_CFLAGS", ctx.DependencyEnv["pcre"]["CFLAGS"]). Set("LZMA_LIBS", ctx.DependencyEnv["lzma"]["LDFLAGS"]). Set("LZMA_CFLAGS", ctx.DependencyEnv["lzma"]["CFLAGS"]). Set("ZLIB_LIBS", ctx.DependencyEnv["zlib"]["LDFLAGS"]). Set("ZLIB_CFLAGS", ctx.DependencyEnv["zlib"]["CFLAGS"]). AsSlice() cmd.Stdout = os.Stdout cmd.Stderr = os.Stdout if err := cmd.Run(); err != nil { log.WithField("err", err).Error("Could not run configure") return err } cmd = exec.Command("make") cmd.Dir = srcdir cmd.Stdout = os.Stdout cmd.Stderr = os.Stdout if err := cmd.Run(); err != nil { log.WithField("err", err).Error("Could not run make") return err } log.Info("Finished building the_silver_searcher") return nil }
func spawn(cmd *exec.Cmd, ttySpec *garden.TTYSpec, stdout io.Writer, stderr io.Writer) (process, io.WriteCloser, error) { var stdin io.WriteCloser var err error var processPty *os.File if ttySpec != nil { pty, tty, err := pty.Open() if err != nil { return nil, nil, err } // close our end of the tty after the process has spawned defer tty.Close() processPty = pty stdin = pty windowColumns := 80 windowRows := 24 if ttySpec.WindowSize != nil { windowColumns = ttySpec.WindowSize.Columns windowRows = ttySpec.WindowSize.Rows } ptyutil.SetWinSize(pty, windowColumns, windowRows) cmd.Stdin = tty cmd.Stdout = tty cmd.Stderr = tty go io.Copy(stdout, pty) } else { stdin, err = cmd.StdinPipe() if err != nil { return nil, nil, err } cmd.Stdout = stdout cmd.Stderr = stderr } err = cmd.Start() if err != nil { return nil, nil, err } return &groupProcess{ process: cmd.Process, processPty: processPty, }, stdin, nil }
func (r *PvRecipe) Build(ctx *types.BuildContext) error { log.Info("Building pv") srcdir := r.UnpackedDir(ctx, r.Info()) var cmd *exec.Cmd // 1. Configure log.Infof("Running ./configure") cmd = exec.Command( "./configure", "--host="+ctx.CrossPrefix, "--build=i686", ) cmd.Dir = srcdir cmd.Env = ctx.Env. Append("CC", ctx.StaticFlags). Set("CFLAGS", ctx.StaticFlags). AsSlice() cmd.Stdout = os.Stdout cmd.Stderr = os.Stdout if err := cmd.Run(); err != nil { log.WithField("err", err).Error("Could not run configure") return err } // 2. Fix linker in Makefile cmd = exec.Command( "sed", "-i", fmt.Sprintf("/^CC =/a LD = %s", ctx.Env.Get("LD")), filepath.Join(srcdir, "Makefile"), ) if err := cmd.Run(); err != nil { log.WithField("err", err).Error("Could not patch Makefile") return err } // 3. Run build cmd = exec.Command("make") cmd.Dir = srcdir cmd.Stdout = os.Stdout cmd.Stderr = os.Stdout if err := cmd.Run(); err != nil { log.WithField("err", err).Error("Could not run make") return err } log.Info("Finished building pv") return nil }
func cloneRepo(name, location string) error { src := "https://github.com/eris-ltd/" + name var c *exec.Cmd // if the .git directory exists within ~/.eris/services (or w/e) // then pull rather than clone. if _, err := os.Stat(filepath.Join(location, ".git")); !os.IsNotExist(err) { logger.Debugf("The location exists. Attempting to pull instead.\n") if err := pullRepo(location); err != nil { return err } else { return nil } } // if the ~/.eris/services (or w/e) directory exists, but it does // not have a .git directory (caught above), then init the dir // and pull the repo. if _, err := os.Stat(location); !os.IsNotExist(err) { c = exec.Command("git", "init", location) c.Stdout = config.GlobalConfig.Writer c.Stderr = config.GlobalConfig.ErrorWriter if e2 := c.Run(); e2 != nil { return e2 } c = exec.Command("git", "remote", "add", "origin", src) if e3 := c.Run(); e3 != nil { return e3 } if err := pullRepo(location); err != nil { return err } else { return nil } // if no ~/.eris services (or w/e) directory exists, then it will // simply clone in the directory. } else { c = exec.Command("git", "clone", src, location) c.Stdout = config.GlobalConfig.Writer c.Stderr = config.GlobalConfig.ErrorWriter if err := c.Run(); err != nil { return err } } return nil }
func (r *RealCommandRunner) tee(cmd *exec.Cmd) { if cmd.Stderr == nil { cmd.Stderr = os.Stderr } else if cmd.Stderr != nil { cmd.Stderr = io.MultiWriter(cmd.Stderr, os.Stderr) } if cmd.Stdout == nil { cmd.Stdout = os.Stderr } else if cmd.Stdout != nil { cmd.Stdout = io.MultiWriter(cmd.Stdout, os.Stderr) } }
// RunCmd runs c (which is assumed to be something short-lived, like a // camput or camget command), capturing its stdout for return, and // also capturing its stderr, just in the case of errors. // If there's an error, the return error fully describes the command and // all output. func RunCmd(c *exec.Cmd) (output string, err error) { var stdout, stderr bytes.Buffer if testing.Verbose() { c.Stderr = io.MultiWriter(os.Stderr, &stderr) c.Stdout = io.MultiWriter(os.Stdout, &stdout) } else { c.Stderr = &stderr c.Stdout = &stdout } err = c.Run() if err != nil { return "", fmt.Errorf("Error running command %+v: Stdout:\n%s\nStderr:\n%s\n", c, stdout.String(), stderr.String()) } return stdout.String(), nil }
// dividedOutput runs the command and returns its standard output and standard error. func dividedOutput(c *exec.Cmd) (stdout []byte, stderr []byte, err error) { var outb, errb bytes.Buffer c.Stdout = &outb c.Stderr = &errb err = c.Run() return outb.Bytes(), errb.Bytes(), err }
func writeGitRepositoryArchive(w io.Writer, path string, ref GitCommitRef) error { var cmd *exec.Cmd // TODO: Stream as tar with gzip if ref == EmptyGitCommitRef { cmd = exec.Command("/usr/bin/git", "archive", "--format", "zip", "master") } else { cmd = exec.Command("/usr/bin/git", "archive", "--format", "zip", string(ref)) } cmd.Env = []string{} cmd.Dir = path var stderr bytes.Buffer cmd.Stderr = utils.LimitWriter(&stderr, 20*1024) stdout, err := cmd.StdoutPipe() if err != nil { return err } if err := cmd.Start(); err != nil { return err } io.Copy(w, stdout) if err := cmd.Wait(); err != nil { return errors.New(fmt.Sprintf("Failed to archive repository: %s\n", err.Error()) + stderr.String()) } return nil }
func (a *AutoInstOptions) install() { sfx := "" if a.InstallSuffix != "" { sfx = a.InstallSuffix } osArchSfx := osArch + sfx if a.Env == nil { a.Env = map[string]string{} } roots := []string{} if p := a.Env["GOROOT"]; p != "" { roots = append(roots, filepath.Join(p, "pkg", osArchSfx)) } for _, p := range pathList(a.Env["GOPATH"]) { roots = append(roots, filepath.Join(p, "pkg", osArchSfx)) } if len(roots) == 0 { return } archiveOk := func(fn string) bool { for _, root := range roots { _, err := os.Stat(filepath.Join(root, fn)) if err == nil { return true } } return false } el := envSlice(a.Env) installed := []string{} for path, fn := range a.imports() { if !archiveOk(fn) { var cmd *exec.Cmd if sfx == "" { cmd = exec.Command("go", "install", path) } else { cmd = exec.Command("go", "install", "-installsuffix", sfx, path) } cmd.Env = el cmd.Stderr = ioutil.Discard cmd.Stdout = ioutil.Discard cmd.Run() if archiveOk(fn) { installed = append(installed, path) } } } if len(installed) > 0 { postMessage("auto-installed: %v", strings.Join(installed, ", ")) } }
// cmdStream executes a command, and returns its stdout as a stream. // If the command fails to run or doesn't complete successfully, an error // will be returned, including anything written on stderr. func cmdStream(cmd *exec.Cmd, input io.Reader) (io.ReadCloser, <-chan struct{}, error) { chdone := make(chan struct{}) cmd.Stdin = input pipeR, pipeW := io.Pipe() cmd.Stdout = pipeW var errBuf bytes.Buffer cmd.Stderr = &errBuf // Run the command and return the pipe if err := cmd.Start(); err != nil { return nil, nil, err } // Copy stdout to the returned pipe go func() { if err := cmd.Wait(); err != nil { pipeW.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String())) } else { pipeW.Close() } close(chdone) }() return pipeR, chdone, nil }
func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error { command.Stdout = t.SlavePty command.Stderr = t.SlavePty go func() { if wb, ok := pipes.Stdout.(interface { CloseWriters() error }); ok { defer wb.CloseWriters() } io.Copy(pipes.Stdout, t.MasterPty) }() if pipes.Stdin != nil { command.Stdin = t.SlavePty command.SysProcAttr.Setctty = true go func() { io.Copy(t.MasterPty, pipes.Stdin) pipes.Stdin.Close() }() } return nil }
func (h *Host) Run(command string) error { var cmd *exec.Cmd if runtime.GOOS == "windows" { cmd = exec.Command("cmd", "/c", command) } else { cmd = exec.Command("sh", "-c", command) } realWriter := &RealWriter{ NewLine: true, Prefix: "[" + h.Name + "]: ", } outWriter := &writer{ realWriter: realWriter, Type: 1, } errWriter := &writer{ realWriter: realWriter, Type: 2, } cmd.Stdout = outWriter cmd.Stderr = errWriter cmd.Stdin = os.Stdin err := cmd.Run() if err != nil { return err } return nil }
func runCommandWithOutputForDuration(cmd *exec.Cmd, duration time.Duration) (output string, exitCode int, timedOut bool, err error) { var outputBuffer bytes.Buffer if cmd.Stdout != nil { err = errors.New("cmd.Stdout already set") return } cmd.Stdout = &outputBuffer if cmd.Stderr != nil { err = errors.New("cmd.Stderr already set") return } cmd.Stderr = &outputBuffer done := make(chan error) go func() { exitErr := cmd.Run() exitCode = processExitCode(exitErr) done <- exitErr }() select { case <-time.After(duration): killErr := cmd.Process.Kill() if killErr != nil { fmt.Printf("failed to kill (pid=%d): %v\n", cmd.Process.Pid, killErr) } timedOut = true break case err = <-done: break } output = outputBuffer.String() return }
func RedirectIOTo(cmd *exec.Cmd, myin io.Reader, myout, myerr io.Writer) { // redirect IO cmd.Stdout = myout cmd.Stderr = myerr cmd.Stdin = myin //return nil, err }
func runTest(test test) (passed bool, err error) { prog := path.Join(*buildDir, test[0]) args := test[1:] var cmd *exec.Cmd if *useValgrind { cmd = valgrindOf(false, prog, args...) } else { cmd = exec.Command(prog, args...) } var stdoutBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { return false, err } if err := cmd.Wait(); err != nil { return false, err } // Account for Windows line-endings. stdout := bytes.Replace(stdoutBuf.Bytes(), []byte("\r\n"), []byte("\n"), -1) if bytes.HasSuffix(stdout, []byte("PASS\n")) && (len(stdout) == 5 || stdout[len(stdout)-6] == '\n') { return true, nil } return false, nil }
/* Start starts the passed-in *exec.Cmd command. It wraps the command in a *gexec.Session. The session pipes the command's stdout and stderr to two *gbytes.Buffers available as properties on the session: session.Out and session.Err. These buffers can be used with the gbytes.Say matcher to match against unread output: Ω(session.Out).Should(gbytes.Say("foo-out")) Ω(session.Err).Should(gbytes.Say("foo-err")) In addition, Session satisfies the gbytes.BufferProvider interface and provides the stdout *gbytes.Buffer. This allows you to replace the first line, above, with: Ω(session).Should(gbytes.Say("foo-out")) When outWriter and/or errWriter are non-nil, the session will pipe stdout and/or stderr output both into the session *gybtes.Buffers and to the passed-in outWriter/errWriter. This is useful for capturing the process's output or logging it to screen. In particular, when using Ginkgo it can be convenient to direct output to the GinkgoWriter: session, err := Start(command, GinkgoWriter, GinkgoWriter) This will log output when running tests in verbose mode, but - otherwise - will only log output when a test fails. The session wrapper is responsible for waiting on the *exec.Cmd command. You *should not* call command.Wait() yourself. Instead, to assert that the command has exited you can use the gexec.Exit matcher: Ω(session).Should(gexec.Exit()) When the session exits it closes the stdout and stderr gbytes buffers. This will short circuit any Eventuallys waiting fo the buffers to Say something. */ func Start(command *exec.Cmd, outWriter io.Writer, errWriter io.Writer) (*Session, error) { exited := make(chan struct{}) session := &Session{ Command: command, Out: gbytes.NewBuffer(), Err: gbytes.NewBuffer(), Exited: exited, lock: &sync.Mutex{}, exitCode: -1, } var commandOut, commandErr io.Writer commandOut, commandErr = session.Out, session.Err if outWriter != nil && !reflect.ValueOf(outWriter).IsNil() { commandOut = io.MultiWriter(commandOut, outWriter) } if errWriter != nil && !reflect.ValueOf(errWriter).IsNil() { commandErr = io.MultiWriter(commandErr, errWriter) } command.Stdout = commandOut command.Stderr = commandErr err := command.Start() if err == nil { go session.monitorForExit(exited) } return session, err }
func (b *Provider) mountDataset(vol *zfsVolume) error { // mount the dataset, snapshots will be readonly // 'zfs mount' currently can't perform on snapshots; seealso https://github.com/zfsonlinux/zfs/issues/173 alreadyMounted, err := isMount(vol.basemount) if err != nil { return fmt.Errorf("could not mount: %s", err) } if alreadyMounted { return nil } if err = os.MkdirAll(vol.basemount, 0644); err != nil { return fmt.Errorf("could not mount: %s", err) } var buf bytes.Buffer var cmd *exec.Cmd if vol.IsSnapshot() { cmd = exec.Command("mount", "-tzfs", vol.dataset.Name, vol.basemount) } else { cmd = exec.Command("zfs", "mount", vol.dataset.Name) } cmd.Stderr = &buf if err := cmd.Run(); err != nil { return fmt.Errorf("could not mount: %s (%s)", err, strings.TrimSpace(buf.String())) } return nil }
// Graphviz generates a specification for the graphviz program that visualizes the // communication graph of a stitch. func graphviz(outputFormat string, slug string, dot string) { f, err := util.AppFs.Create(slug + ".dot") if err != nil { panic(err) } defer f.Close() f.Write([]byte(dot)) if outputFormat == "graphviz" { return } defer exec.Command("rm", slug+".dot").Run() // Dependencies: // - easy-graph (install Graph::Easy from cpan) // - graphviz (install from your favorite package manager) var writeGraph *exec.Cmd switch outputFormat { case "ascii": writeGraph = exec.Command("graph-easy", "--input="+slug+".dot", "--as_ascii") case "pdf": writeGraph = exec.Command("dot", "-Tpdf", "-o", slug+".pdf", slug+".dot") } writeGraph.Stdout = os.Stdout writeGraph.Stderr = os.Stderr writeGraph.Run() }
func watcherLoop(watcher *fsnotify.Watcher) { var cmd *exec.Cmd for { select { case event := <-watcher.Events: if event.Op&fsnotify.Write == fsnotify.Write { for i := range tasks { p := "./" + tasks[i].Pattern if m, err := path.Match(p, event.Name); m && (err == nil) { if cmd != nil { cmd.Process.Kill() } name := tasks[i].Command[0] args := tasks[i].Command[1:] log.Print("> ", tasks[i].Name) cmd = exec.Command(name, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Start() } } } case err := <-watcher.Errors: log.Println("error:", err) } } }
func run(src string) error { // Create a temp folder. tempDir, err := ioutil.TempDir("", "goexec_") if err != nil { return err } defer func() { err := os.RemoveAll(tempDir) if err != nil { fmt.Fprintln(os.Stderr, "warning: error removing temp dir:", err) } }() // Write the source code file. tempFile := filepath.Join(tempDir, "gen.go") err = ioutil.WriteFile(tempFile, []byte(src), 0600) if err != nil { return err } // Compile and run the program. var cmd *exec.Cmd switch *compilerFlag { case "gc": cmd = exec.Command("go", "run", tempFile) case "gopherjs": cmd = exec.Command("gopherjs", "run", tempFile) } cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() }
func StopPgpool(w rest.ResponseWriter, r *rest.Request) { logit.Info.Println("StopPgpool called") response := StopPgpoolResponse{} req := StopPgpoolRequest{} err := r.DecodeJsonPayload(&req) if err != nil { logit.Error.Println(err.Error()) rest.Error(w, err.Error(), http.StatusInternalServerError) return } var cmd *exec.Cmd cmd = exec.Command("stop-pgpool.sh", req.Path) var out bytes.Buffer var stderr bytes.Buffer cmd.Stdout = &out cmd.Stderr = &stderr err = cmd.Run() if err != nil { logit.Error.Println(err.Error()) rest.Error(w, err.Error(), 400) return } response.Output = out.String() response.Status = "OK" w.WriteJson(&response) }
func (run execCmdRunner) runCmd(cmd *exec.Cmd) (stdout, stderr string, err error) { cmdString := strings.Join(cmd.Args, " ") run.logger.Debug("Cmd Runner", "Running command: %s", cmdString) stdoutWriter := bytes.NewBufferString("") stderrWriter := bytes.NewBufferString("") cmd.Stdout = stdoutWriter cmd.Stderr = stderrWriter err = cmd.Start() if err != nil { err = bosherr.WrapError(err, "Starting command %s", cmdString) return } err = cmd.Wait() stdout = string(stdoutWriter.Bytes()) stderr = string(stderrWriter.Bytes()) run.logger.Debug("Cmd Runner", "Stdout: %s", stdout) run.logger.Debug("Cmd Runner", "Stderr: %s", stderr) run.logger.Debug("Cmd Runner", "Successful: %t", err == nil) if err != nil { err = bosherr.WrapError(err, "Running command: '%s', stdout: '%s', stderr: '%s'", cmdString, stdout, stderr) } return }
func execCommand(cmd *exec.Cmd) error { cmdReader, err := cmd.StdoutPipe() if err != nil { fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err) return err } scanner := bufio.NewScanner(cmdReader) go func() { for scanner.Scan() { fmt.Printf("docker build out | %s\n", scanner.Text()) } }() var stderr bytes.Buffer cmd.Stdout = os.Stdout cmd.Stderr = &stderr err = cmd.Start() if err != nil { fmt.Printf("docker build out | %s\n", stderr.String()) return err } err = cmd.Wait() if err != nil { fmt.Printf("docker build out | %s\n", stderr.String()) return err } return err }
func run(cmd *exec.Cmd) { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { log.Fatal(err) } }