diff --git a/pkg/commands/oscommands/cmd_obj.go b/pkg/commands/oscommands/cmd_obj.go index 57bc295ed..1fbe84087 100644 --- a/pkg/commands/oscommands/cmd_obj.go +++ b/pkg/commands/oscommands/cmd_obj.go @@ -157,7 +157,7 @@ func (self *CmdObj) ShouldStreamOutput() bool { } // when you call this, then call Run(), we'll use a PTY to run the command. Only -// has an effect if StreamOutput() was also called. Ignored on Windows. +// has an effect if StreamOutput() was also called. func (self *CmdObj) UsePty() *CmdObj { self.usePty = true diff --git a/pkg/commands/oscommands/cmd_obj_runner.go b/pkg/commands/oscommands/cmd_obj_runner.go index 978682618..b70668431 100644 --- a/pkg/commands/oscommands/cmd_obj_runner.go +++ b/pkg/commands/oscommands/cmd_obj_runner.go @@ -219,6 +219,10 @@ type cmdHandler struct { stdoutPipe io.Reader stdinPipe io.Writer close func() error + // wait blocks until the child process exits. Needed as a separate + // field because the pty path on Windows spawns via CreateProcess and + // never runs *exec.Cmd.Start — so cmd.Wait wouldn't work there. + wait func() error } func (self *cmdObjRunner) runAndStream(cmdObj *CmdObj) error { @@ -274,7 +278,7 @@ func (self *cmdObjRunner) runAndStreamAux( onRun(handler, cmdWriter) - err = cmd.Wait() + err = handler.wait() self.log.Infof("%s (%s)", cmdObj.ToString(), time.Since(t)) @@ -376,9 +380,7 @@ func (self *cmdObjRunner) processOutput( responseChan := promptUserForCredential(askFor) if responseChan == nil { // Returning a nil channel means we should terminate the process. - // We achieve this by closing the pty that it's running in. Note that this won't - // work for the case where we're not running in a pty (i.e. on Windows), but - // in that case we'll never be prompted for credentials, so it's not a concern. + // We achieve this by closing the pty that it's running in. if err := closeFunc(); err != nil { self.log.Error(err) } @@ -481,5 +483,21 @@ func (self *cmdObjRunner) getCmdHandlerNonPty(cmd *exec.Cmd) (*cmdHandler, error stdoutPipe: stdoutReader, stdinPipe: buf, close: func() error { return nil }, + wait: cmd.Wait, + }, nil +} + +func (self *cmdObjRunner) getCmdHandlerPty(cmd *exec.Cmd) (*cmdHandler, error) { + // Size will be adjusted by the caller if it cares; this just avoids a + // zero-size pty. + sp, err := StartPty(cmd, 80, 24) + if err != nil { + return nil, err + } + return &cmdHandler{ + stdoutPipe: sp.Pty, + stdinPipe: sp.Pty, + close: sp.Pty.Close, + wait: sp.Wait, }, nil } diff --git a/pkg/commands/oscommands/cmd_obj_runner_default.go b/pkg/commands/oscommands/cmd_obj_runner_default.go deleted file mode 100644 index 72cbc26c6..000000000 --- a/pkg/commands/oscommands/cmd_obj_runner_default.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build !windows - -package oscommands - -import ( - "os/exec" - - "github.com/creack/pty" -) - -// we define this separately for windows and non-windows given that windows does -// not have great PTY support and we need a PTY to handle a credential request -func (self *cmdObjRunner) getCmdHandlerPty(cmd *exec.Cmd) (*cmdHandler, error) { - ptmx, err := pty.Start(cmd) - if err != nil { - return nil, err - } - - return &cmdHandler{ - stdoutPipe: ptmx, - stdinPipe: ptmx, - close: ptmx.Close, - }, nil -} diff --git a/pkg/commands/oscommands/cmd_obj_runner_windows.go b/pkg/commands/oscommands/cmd_obj_runner_windows.go deleted file mode 100644 index f92e36c69..000000000 --- a/pkg/commands/oscommands/cmd_obj_runner_windows.go +++ /dev/null @@ -1,10 +0,0 @@ -package oscommands - -import ( - "os/exec" -) - -func (self *cmdObjRunner) getCmdHandlerPty(cmd *exec.Cmd) (*cmdHandler, error) { - // We don't have PTY support on Windows yet, so we just return a non-PTY handler. - return self.getCmdHandlerNonPty(cmd) -}