func pipePty(cmd *exec.Cmd, handler *interactive.ShellHandler) error { // Start the shell as TTY f, err := pty.Start(cmd) if err == nil { // Connect pipes (close stderr as tty only has two streams) go ioext.CopyAndClose(f, handler.StdinPipe()) go ioext.CopyAndClose(handler.StdoutPipe(), f) go handler.StderrPipe().Close() // Start communication handler.Communicate(func(cols, rows uint16) error { return setTTYSize(f, cols, rows) }, func() error { if cmd.Process != nil { return cmd.Process.Kill() } return nil }) } // If pty wasn't supported for some reason we fall back to normal execution if err == pty.ErrUnsupported { return pipeCommand(cmd, handler) } if err != nil { handler.Communicate(nil, func() error { // If cmd.Start() failed, then we don't have a process, but we start // the communication flow anyways. if cmd.Process != nil { return cmd.Process.Kill() } return nil }) } return err }
func pipeCommand(cmd *exec.Cmd, handler *interactive.ShellHandler) error { // Set pipes cmd.Stdin = handler.StdinPipe() cmd.Stdout = handler.StdoutPipe() cmd.Stderr = handler.StderrPipe() // Start the shell, this must finished before we can call Kill() err := cmd.Start() // Start communication handler.Communicate(nil, func() error { // If cmd.Start() failed, then we don't have a process, but we start // the communication flow anyways. if cmd.Process != nil { return cmd.Process.Kill() } return nil }) return err }