func compile(w *World) *bytes.Buffer { ioutil.WriteFile(TEMPPATH+".go", []byte(w.source()), 0644) err := new(bytes.Buffer) re, e, _ := os.Pipe() attr := &os.ProcAttr{Env: os.Environ(), Files: []*os.File{nil, e, nil}} args := []string{bin + "/" + arch + "g", "-o", TEMPPATH + ".6", TEMPPATH + ".go"} os.StartProcess(bin+"/"+arch+"g", args, attr) e.Close() io.Copy(err, re) if err.Len() > 0 { return err } re, e, _ = os.Pipe() attr = &os.ProcAttr{Env: os.Environ(), Files: []*os.File{nil, e, nil}} args = []string{bin + "/" + arch + "l", "-o", TEMPPATH + "", TEMPPATH + ".6"} os.StartProcess(bin+"/"+arch+"l", args, attr) e.Close() io.Copy(err, re) return err }
func captureOutput(f func(), t *testing.T) (string, string) { // Capture STDOUT with a pipe stdout := os.Stdout stderr := os.Stderr so, op, _ := os.Pipe() //outpipe oe, ep, _ := os.Pipe() //errpipe defer func(stdout, stderr *os.File) { os.Stdout = stdout os.Stderr = stderr }(stdout, stderr) os.Stdout = op os.Stderr = ep f() os.Stdout = stdout os.Stderr = stderr op.Close() ep.Close() errOutput, err := ioutil.ReadAll(oe) if err != nil { t.Error("Could not get output from stderr") } stdOutput, err := ioutil.ReadAll(so) if err != nil { t.Error("Could not get output from stdout") } return string(stdOutput), string(errOutput) }
func (s *server) Dial(config *ssh.ClientConfig) *ssh.ClientConn { s.cmd = exec.Command("sshd", "-f", s.configfile, "-i") r1, w1, err := os.Pipe() if err != nil { s.t.Fatal(err) } s.cmd.Stdout = w1 r2, w2, err := os.Pipe() if err != nil { s.t.Fatal(err) } s.cmd.Stdin = r2 s.cmd.Stderr = os.Stderr if err := s.cmd.Start(); err != nil { s.t.Fail() s.Shutdown() s.t.Fatalf("s.cmd.Start: %v", err) } conn, err := ssh.Client(&client{wc: w2, r: r1}, config) if err != nil { s.t.Fail() s.Shutdown() s.t.Fatalf("ssh.Client: %v", err) } return conn }
func startChild(filename string) (*childInfo, error) { cmdPath, err := exec.LookPath(cmdName) if err != nil { return nil, err } pr1, pw1, err := os.Pipe() if err != nil { return nil, err } pr2, pw2, err := os.Pipe() if err != nil { return nil, err } pr3, pw3, err := os.Pipe() if err != nil { return nil, err } args := []string{cmdPath, filename} fds := []*os.File{pr1, pw2, pw3} p, err := os.StartProcess(cmdPath, args, &os.ProcAttr{Dir: "/", Files: fds}) if err != nil { return nil, err } return &childInfo{ r: bufio.NewReader(pr2), w: pw1, proc: p, er: bufio.NewReader(pr3), }, nil }
// CaptureStdOutAndErr captures all std out/err until the returned func is // called. That func returns any captured output as a string. This is useful // for capturing remote output (e.g. on a server) and writing it to a file or // piping it to a log etc. func CaptureStdOutAndErr() func() string { old := os.Stdout // keep backup of the real stdout oldErr := os.Stderr r, w, _ := os.Pipe() os.Stdout = w rErr, wErr, _ := os.Pipe() os.Stderr = wErr outC := make(chan string) // copy the output in a separate goroutine so printing can't block indefinitely go func() { var buf bytes.Buffer io.Copy(&buf, r) outC <- buf.String() }() outErrC := make(chan string) go func() { var buf bytes.Buffer io.Copy(&buf, rErr) outErrC <- buf.String() }() return func() string { w.Close() wErr.Close() os.Stdout = old // restoring the real stdout os.Stderr = oldErr // restoring the real stdout return <-outC + <-outErrC } }
func startProc(path, args interface{}) interface{} { p, ok := path.(string) if !ok { TypeError("string", path) } argv := make([]string, ListLen(args)) for cur, i := args, 0; cur != EMPTY_LIST; cur, i = Cdr(cur), i+1 { x := Car(cur) s, ok := x.(string) if !ok { TypeError("string", x) } argv[i] = s } inr, inw, err := os.Pipe() if err != nil { SystemError(err) } outr, outw, err := os.Pipe() if err != nil { SystemError(err) } _, err = os.ForkExec(p, argv, os.Envs, "", []*os.File{inr, outw, os.Stderr}) if err != nil { SystemError(err) } return Cons(NewOutput(inw), NewInput(outr)) }
func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.ClientConn, error) { sshd, err := exec.LookPath("sshd") if err != nil { s.t.Skipf("skipping test: %v", err) } s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e") r1, w1, err := os.Pipe() if err != nil { s.t.Fatal(err) } s.cmd.Stdout = w1 r2, w2, err := os.Pipe() if err != nil { s.t.Fatal(err) } s.cmd.Stdin = r2 s.cmd.Stderr = os.Stderr if err := s.cmd.Start(); err != nil { s.t.Fail() s.Shutdown() s.t.Fatalf("s.cmd.Start: %v", err) } return ssh.Client(&client{wc: w2, r: r1}, config) }
func TestTurnOn(t *testing.T) { // use pipes to capture stdout and stderr oldStdout := os.Stdout oldStderr := os.Stderr r, w, _ := os.Pipe() re, we, _ := os.Pipe() os.Stdout = w os.Stderr = we turnOnLogging(LevelWarning, nil) Info("info %d", 123) Warning("warning %d", 123) Error(nil, "error %d", 123) we.Close() w.Close() out, _ := ioutil.ReadAll(r) errOut, _ := ioutil.ReadAll(re) os.Stdout = oldStdout os.Stderr = oldStderr outStr := string(out[:]) errStr := string(errOut[:]) assert.True(t, strings.Contains(outStr, "warning 123"), "Should have warning printed") assert.True(t, strings.Contains(errStr, "error 123"), "Should have error") assert.False(t, strings.Contains(outStr, "info"), "Should not have info printed") }
func Keyspace(servers string) (*KeyspaceProxy, os.Error) { serverList := strings.Split(servers, " ", -1) argv := make([]string, len(serverList)+1) argv[0] = scriptPath for idx, server := range serverList { argv[idx+1] = server } stdinRead, stdinWrite, err := os.Pipe() if err != nil { return nil, err } stdoutRead, stdoutWrite, err := os.Pipe() if err != nil { return nil, err } stderrRead, stderrWrite, err := os.Pipe() if err != nil { return nil, err } fd := []*os.File{stdinRead, stdoutWrite, stderrWrite} pid, err := os.ForkExec(scriptPath, argv, os.Environ(), "", fd) if err != nil { return nil, err } return &KeyspaceProxy{ Servers: servers, pid: pid, stdin: stdinWrite, stdout: stdoutRead, stderr: stderrRead, lock: &sync.Mutex{}, }, nil }
// Tests both incremental and verifies actual file changes func (s *internal) TestSendComplex() { name := "/" + s.pool + "/a/2/markerfile" NoError := s.Require().NoError NoError(touch(name)) NoError(snap(s.pool + "/a/2@pre")) NoError(command("sudo", "rm", name).Run()) NoError(snap(s.pool + "/a/2@post")) reader, writer, err := os.Pipe() NoError(err) NoError(send(s.pool+"/a/2@pre", writer.Fd(), "", true, true)) writer.Close() // must be before receiver, otherwise can block s.NoError(receive(reader, s.pool+"/c")) reader.Close() name = strings.Replace(name, "/a/", "/c/", 1) _, err = os.Stat(name) s.NoError(err) reader, writer, err = os.Pipe() NoError(err) s.NoError(send(s.pool+"/a/2@post", writer.Fd(), s.pool+"/a/2@pre", false, false)) writer.Close() // must be before receiver, otherwise can block s.NoError(receive(reader, s.pool+"/c")) reader.Close() _, err = os.Stat(name) s.IsType(&os.PathError{}, err) }
// setup standard pipes so that the TTY of the calling runc process // is not inherited by the container. func createStdioPipes(p *libcontainer.Process, rootuid int) (*tty, error) { var ( t = &tty{} fds []int ) r, w, err := os.Pipe() if err != nil { return nil, err } fds = append(fds, int(r.Fd()), int(w.Fd())) go io.Copy(w, os.Stdin) t.closers = append(t.closers, w) p.Stdin = r if r, w, err = os.Pipe(); err != nil { return nil, err } fds = append(fds, int(r.Fd()), int(w.Fd())) go io.Copy(os.Stdout, r) p.Stdout = w t.closers = append(t.closers, r) if r, w, err = os.Pipe(); err != nil { return nil, err } fds = append(fds, int(r.Fd()), int(w.Fd())) go io.Copy(os.Stderr, r) p.Stderr = w t.closers = append(t.closers, r) // change the ownership of the pipe fds incase we are in a user namespace. for _, fd := range fds { if err := syscall.Fchown(fd, rootuid, rootuid); err != nil { return nil, err } } return t, nil }
func (s *internal) TestSendSimple() { s.EqualError(send("should-not-exist", 0, "", true, true), enoent) s.EqualError(send(s.pool+"/a/2@snap1", 42, "", true, true), ebadf) s.EqualError(send(s.pool+"/"+longName, 42, "", true, true), einval) // WANTE(ENAMETOOLONG) // expect epipe reader, writer, err := os.Pipe() s.Require().NoError(err) reader.Close() s.EqualError(send(s.pool+"/a/2@snap1", writer.Fd(), "", true, true), epipe) writer.Close() // expect ebadf reader, writer, err = os.Pipe() s.Require().NoError(err) writer.Close() s.EqualError(send(s.pool+"/a/2@snap1", writer.Fd(), "", true, true), ebadf) reader.Close() // ok reader, writer, err = os.Pipe() s.Require().NoError(err) s.NoError(send(s.pool+"/a/4", writer.Fd(), "", true, true)) s.NoError(receive(reader, s.pool+"/c")) reader.Close() writer.Close() }
func testClientGoSvr(t testing.TB, readonly bool, delay time.Duration) (*Client, *exec.Cmd) { txPipeRd, txPipeWr, err := os.Pipe() if err != nil { t.Fatal(err) } rxPipeRd, rxPipeWr, err := os.Pipe() if err != nil { t.Fatal(err) } server, err := NewServer(txPipeRd, rxPipeWr, os.Stderr, 0, readonly, ".") if err != nil { t.Fatal(err) } go server.Serve() var ctx io.WriteCloser = txPipeWr if delay > NO_DELAY { ctx = newDelayedWriter(ctx, delay) } client, err := NewClientPipe(rxPipeRd, ctx) if err != nil { t.Fatal(err) } // dummy command... return client, exec.Command("true") }
func ExecuteCommand(command string, input string) { stdoutRead, stdoutWrite, _ := os.Pipe() stdinRead, stdinWrite, _ := os.Pipe() attr := &os.ProcAttr{".", nil, []*os.File{stdinRead, stdoutWrite, stdoutWrite}, nil} proc, err := os.StartProcess(command, []string{command}, attr) stdoutWrite.Close() stdinRead.Close() if err == nil { // create two go-routines. One for reading, one for writing inputBytes := []byte(input) go func() { _, _ = stdinWrite.Write(inputBytes) stdinWrite.Close() log.Println("Completed writing to child proccs") }() go func() { for { // allocate a new buffer buffer := make([]byte, 1000) // read into that buffer count, err := stdoutRead.Read(buffer) if count > 0 { fmt.Printf("output from command: %s\n", buffer[:count]) } // if we reached the end, bail from this loop if err == io.EOF { break } } stdoutRead.Close() log.Println("Waiting to reap child process") // reap child process _, _ = proc.Wait() // if error != nil { // fmt.Printf("error=%v\n", error) // } log.Println("Go routine terminating") }() } else { log.Println("Error: " + err.Error()) stdoutRead.Close() stdinWrite.Close() log.Println("Cleaned up handles after error") } // return err }
func init() { // Redirect the standard output and error to logcat oldStdout, oldStderr := os.Stdout, os.Stderr outRead, outWrite, _ := os.Pipe() errRead, errWrite, _ := os.Pipe() os.Stdout = outWrite os.Stderr = errWrite go func() { scanner := bufio.NewScanner(outRead) for scanner.Scan() { line := scanner.Text() C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stdout"), C.CString(line)) oldStdout.WriteString(line + "\n") } }() go func() { scanner := bufio.NewScanner(errRead) for scanner.Scan() { line := scanner.Text() C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stderr"), C.CString(line)) oldStderr.WriteString(line + "\n") } }() }
func TestPassExtraFiles(t *testing.T) { if testing.Short() { return } rootfs, err := newRootfs() if err != nil { t.Fatal(err) } defer remove(rootfs) config := newTemplateConfig(rootfs) container, err := factory.Create("test", config) if err != nil { t.Fatal(err) } defer container.Destroy() var stdout bytes.Buffer pipeout1, pipein1, err := os.Pipe() pipeout2, pipein2, err := os.Pipe() process := libcontainer.Process{ Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"}, Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}, ExtraFiles: []*os.File{pipein1, pipein2}, Stdin: nil, Stdout: &stdout, } err = container.Start(&process) if err != nil { t.Fatal(err) } waitProcess(&process, t) out := string(stdout.Bytes()) // fd 5 is the directory handle for /proc/$$/fd if out != "0 1 2 3 4 5" { t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to init, got '%s'", out) } var buf = []byte{0} _, err = pipeout1.Read(buf) if err != nil { t.Fatal(err) } out1 := string(buf) if out1 != "1" { t.Fatalf("expected first pipe to receive '1', got '%s'", out1) } _, err = pipeout2.Read(buf) if err != nil { t.Fatal(err) } out2 := string(buf) if out2 != "2" { t.Fatalf("expected second pipe to receive '2', got '%s'", out2) } }
func TestWriteHistory(t *testing.T) { oldout := os.Stdout defer func() { os.Stdout = oldout }() oldin := os.Stdout defer func() { os.Stdin = oldin }() newinr, newinw, err := os.Pipe() if err != nil { t.Fatal(err) } os.Stdin = newinr newoutr, newoutw, err := os.Pipe() if err != nil { t.Fatal(err) } defer newoutr.Close() os.Stdout = newoutw var wait sync.WaitGroup wait.Add(1) s := NewLiner() go func() { s.AppendHistory("foo") s.AppendHistory("bar") s.Prompt("") wait.Done() }() s.WriteHistory(ioutil.Discard) newinw.Close() wait.Wait() }
func (ss *SubService) startProcess() (proc *os.Process, err error) { cmd := exec.Command(ss.binPath, ss.argv...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr dRead, ssWrite, err := os.Pipe() ssRead, dWrite, err := os.Pipe() // Store Fd's for us to read/write to SubService ss.pipe = daemon.NewPipe(dRead, dWrite) // Pass SubService their side of the connection cmd.ExtraFiles = append(cmd.ExtraFiles, ssRead, ssWrite) err = cmd.Start() proc = cmd.Process startupTimer := time.NewTimer(RerunWait) if proc != nil { go ss.watchSignals() go ss.watchProcess(proc, startupTimer) } return }
func run() (*bytes.Buffer, *bytes.Buffer) { out := new(bytes.Buffer) err := new(bytes.Buffer) re, e, _ := os.Pipe() ro, o, _ := os.Pipe() os.ForkExec( TEMPPATH, []string{TEMPPATH}, os.Environ(), "", []*os.File{nil, o, e}) e.Close() io.Copy(err, re) if err.Len() > 0 { return nil, err } o.Close() io.Copy(out, ro) return out, err }
func compile(w *World) *bytes.Buffer { ioutil.WriteFile(TEMPPATH+".go", []byte(w.source()), 0644) err := new(bytes.Buffer) re, e, _ := os.Pipe() os.ForkExec( bin+"/"+arch+"g", []string{bin + "/" + arch + "g", "-o", TEMPPATH + ".6", TEMPPATH + ".go"}, os.Environ(), "", []*os.File{nil, e, nil}) e.Close() io.Copy(err, re) if err.Len() > 0 { return err } re, e, _ = os.Pipe() os.ForkExec( bin+"/"+arch+"l", []string{bin + "/" + arch + "l", "-o", TEMPPATH + "", TEMPPATH + ".6"}, os.Environ(), "", []*os.File{nil, e, nil}) e.Close() io.Copy(err, re) return err }
func testNewLinuxHostTaoServer(t *testing.T) (Tao, error) { lh, err := testNewRootLinuxHost() if err != nil { return nil, fmt.Errorf("Can't make root linux host: %s", err) } hostRead, childWrite, err := os.Pipe() if err != nil { return nil, fmt.Errorf("Can't make pipe: %s", err) } childRead, hostWrite, err := os.Pipe() if err != nil { childWrite.Close() hostRead.Close() return nil, fmt.Errorf("Can't make pipe: %s", err) } hostChannel := util.NewPairReadWriteCloser(hostRead, hostWrite) childChannel := util.NewPairReadWriteCloser(childRead, childWrite) child := &LinuxHostChild{ channel: hostChannel, ChildSubprin: []auth.PrinExt{auth.PrinExt{Name: "TestChild"}}, Cmd: nil, // The Cmd field is not used in this test. } go NewLinuxHostTaoServer(lh, child).Serve(hostChannel) return &RPC{protorpc.NewClient(childChannel), "Tao"}, nil }
func captureReader(block func()) (*os.File, *os.File, error) { rOut, wOut, err := os.Pipe() if err != nil { return nil, nil, err } rErr, wErr, err := os.Pipe() if err != nil { return nil, nil, err } defer wOut.Close() defer wErr.Close() var stdout, stderr *os.File os.Stdout, stdout = wOut, os.Stdout os.Stderr, stderr = wErr, os.Stderr defer func() { os.Stdout = stdout os.Stderr = stderr }() block() wOut.Close() wErr.Close() return rOut, rErr, nil }
// ExecTee runs a command and arguments and returns both STDERR and STDOUT in a // two `[]btye`'s. Errors are turned as `error`. Additionally, it pipes STDOUT // and STDERR to the respective `io.WriteCloser`'s. func ExecTee2(ostream, estream io.WriteCloser, command string, args ...string) (oout, eout []byte, err error) { cmd := exec.Command(command, args...) oread, owrite, _ := os.Pipe() eread, ewrite, _ := os.Pipe() defer func() { oread.Close() eread.Close() }() cmd.Stdout = io.MultiWriter(owrite, ostream) cmd.Stderr = io.MultiWriter(ewrite, estream) err = cmd.Run() owrite.Close() ewrite.Close() oout, oreadErr := ioutil.ReadAll(oread) eout, ereadErr := ioutil.ReadAll(eread) if oreadErr != nil { return oout, eout, oreadErr } if ereadErr != nil { return oout, eout, ereadErr } return }
func captureOutputs(f func()) (stdout, stderr []byte) { oldStdout := os.Stdout oldStderr := os.Stderr rOut, wOut, _ := os.Pipe() rErr, wErr, _ := os.Pipe() os.Stdout = wOut os.Stderr = wErr resetLoggers() f() outC := make(chan []byte) errC := make(chan []byte) go func() { bytes, _ := ioutil.ReadAll(rOut) outC <- bytes bytes, _ = ioutil.ReadAll(rErr) errC <- bytes }() wOut.Close() wErr.Close() stdout = <-outC stderr = <-errC os.Stdout = oldStdout os.Stderr = oldStderr return }
func (self *ProcessGroup) StartProcess() (process *os.Process, err error) { self.wg.Add(1) stdoutReader, stdoutWriter, err := os.Pipe() if err != nil { return nil, err } stderrReader, stderrWriter, err := os.Pipe() if err != nil { return nil, err } env := append(os.Environ(), "EINHORN_FDS=3") procattr := &os.ProcAttr{ Env: env, Files: []*os.File{os.Stdin, stdoutWriter, stderrWriter, self.sockfile}, } process, err = os.StartProcess(self.commandPath, []string{}, procattr) if err != nil { return } // Add to set self.set[process] = true // Helps waiting for process, stdout and stderr var wg sync.WaitGroup // Prefix stdout and stderr lines with the [pid] go PrefixOutput(stdoutReader, os.Stdout, process.Pid, wg) go PrefixOutput(stderrReader, os.Stderr, process.Pid, wg) // Handle the process death go func() { wg.Add(1) state, err := process.Wait() log.Println(process.Pid, state, err) // Remove from set delete(self.set, process) // Process is gone stdoutReader.Close() stderrReader.Close() wg.Done() }() // Wait for process, stdout and stderr before declaring the process done go func() { wg.Wait() self.wg.Done() }() return }
func captureStd() (*os.File, *os.File, *os.File, *os.File) { oldStdout := os.Stdout oldStderr := os.Stderr _, writerStdout, _ := os.Pipe() _, writerStderr, _ := os.Pipe() os.Stdout = writerStdout os.Stderr = writerStderr return writerStdout, writerStderr, oldStdout, oldStderr }
// todo: make this private. func compileJs(filename string, externs []string, includes []string, w io.Writer, level Optimization) error { // output pipe orp, owp, err := os.Pipe() if err != nil { return err } defer orp.Close() defer owp.Close() var cp, jp *os.Process switch level { case None: cp, err = cpp(filename, includes, owp) if err != nil { return err } owp.Close() case Basic, Advanced: irp, iwp, err := os.Pipe() if err != nil { return err } defer irp.Close() defer iwp.Close() cp, err = cpp(filename, includes, iwp) if err != nil { return err } iwp.Close() jp, err = jsc(irp, owp, externs, pathToJsc(), level) if err != nil { return err } irp.Close() owp.Close() } _, err = io.Copy(w, orp) if err != nil { return err } err = waitFor(cp, jp) if err != nil { return err } return nil }
func StartSignalWatcher(t *testing.T, cgroupdir string) (*exec.Cmd, *os.File) { // cmd := exec.Command(os.Args[0], EXECUTION_TOKEN) output, stdout, err := os.Pipe() if err != nil { t.Fatalf("Error making pipe: %s", err) } defer stdout.Close() check, stderr, err := os.Pipe() if err != nil { t.Fatalf("Error making pipe: %s", err) } defer stderr.Close() cmd.Stdin = nil cmd.Stdout = stdout cmd.Stderr = stderr if err := cmd.Start(); err != nil { t.Fatalf("Error starting signal process: %s", err) } // Add this task to the given cgroup. if cgroupdir != "" { // Add the task to the cgroup tasksfile := path.Join(cgroupdir, "tasks") pidstr := []byte(fmt.Sprintf("%d\n", cmd.Process.Pid)) if err := ioutil.WriteFile(tasksfile, pidstr, 0644); err != nil { t.Fatalf("Error adding process to cgroup: %s", err) } } rchan := make(chan string) go func() { line, err := bufio.NewReader(check).ReadString('\n') if err != nil { rchan <- fmt.Sprintf("Error waiting for process start: %s", err) } else if line != "READY\n" { rchan <- fmt.Sprintf("Wrong string read: %s", line) } else { rchan <- "" } }() select { case msg := <-rchan: if msg != "" { t.Fatalf(msg) } case <-time.NewTimer(time.Second).C: t.Fatalf("timeout starting command") } return cmd, output }
//init opes the pipes and start the python process. func (py *pygoImpl) init() error { stderrReader, stderrWriter, err := os.Pipe() if err != nil { return err } pyIn, goOut, err := os.Pipe() if err != nil { return err } goIn, pyOut, err := os.Pipe() if err != nil { return err } var env []string = nil if py.opts.PythonPath != "" { env = []string{fmt.Sprintf("PYTHONPATH=%s", py.opts.PythonPath)} } env = append(env, py.opts.Env...) attr := &os.ProcAttr{ Files: []*os.File{nil, nil, stderrWriter, pyIn, pyOut}, Env: env, } ps, err := os.StartProcess(py.binPath, []string{ py.binPath, "-c", fmt.Sprintf(code, py.module)}, attr) defer func() { stderrWriter.Close() pyIn.Close() pyOut.Close() }() if err != nil { return err } py.ps = ps py.stream = NewStream(goOut, goIn) py.chanerr = stderrReader return nil }
func StartWrapped(cmd *exec.Cmd, outWrapper OutputWrapper, errWrapper OutputWrapper) (*Session, error) { stdinOut, stdinIn, err := os.Pipe() if err != nil { return nil, err } stdoutOut, stdoutIn, err := os.Pipe() if err != nil { return nil, err } stderrOut, stderrIn, err := os.Pipe() if err != nil { return nil, err } cmd.Stdin = stdinOut cmd.Stdout = outWrapper(stdoutIn) cmd.Stderr = errWrapper(stderrIn) outExpector := NewExpector(stdoutOut, 0) errExpector := NewExpector(stderrOut, 0) err = cmd.Start() if err != nil { return nil, err } exited := make(chan int, 1) go func() { cmd.Wait() exited <- cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() close(exited) stdoutIn.Close() stderrIn.Close() }() return &Session{ Cmd: cmd, Stdin: stdinIn, stdout: outExpector, stderr: errExpector, exited: exited, }, nil }