diff --git a/pkg/commands/oscommands/cmd_obj_runner.go b/pkg/commands/oscommands/cmd_obj_runner.go index 6acd8d0fb..2d0b7034e 100644 --- a/pkg/commands/oscommands/cmd_obj_runner.go +++ b/pkg/commands/oscommands/cmd_obj_runner.go @@ -10,7 +10,6 @@ import ( "time" "github.com/go-errors/errors" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sasha-s/go-deadlock" "github.com/sirupsen/logrus" @@ -295,14 +294,10 @@ const ( Token ) -// Whenever we're asked for a password we just enter a newline, which will -// eventually cause the command to fail. +// Whenever we're asked for a password we return a nil channel to tell the +// caller to kill the process. var failPromptFn = func(CredentialType) <-chan string { - ch := make(chan string) - go func() { - ch <- "\n" - }() - return ch + return nil } func (self *cmdObjRunner) runWithCredentialHandling(cmdObj *CmdObj) error { @@ -340,7 +335,7 @@ func (self *cmdObjRunner) runAndDetectCredentialRequest( tr := io.TeeReader(handler.stdoutPipe, cmdWriter) go utils.Safe(func() { - self.processOutput(tr, handler.stdinPipe, promptUserForCredential, cmdObj.GetTask()) + self.processOutput(tr, handler.stdinPipe, promptUserForCredential, cmdObj) }) }) } @@ -349,9 +344,10 @@ func (self *cmdObjRunner) processOutput( reader io.Reader, writer io.Writer, promptUserForCredential func(CredentialType) <-chan string, - task gocui.Task, + cmdObj *CmdObj, ) { checkForCredentialRequest := self.getCheckForCredentialRequestFunc() + task := cmdObj.GetTask() scanner := bufio.NewScanner(reader) scanner.Split(bufio.ScanBytes) @@ -360,16 +356,26 @@ func (self *cmdObjRunner) processOutput( askFor, ok := checkForCredentialRequest(newBytes) if ok { responseChan := promptUserForCredential(askFor) - if task != nil { - task.Pause() - } - toInput := <-responseChan - if task != nil { - task.Continue() - } - // If the return data is empty we don't write anything to stdin - if toInput != "" { - _, _ = writer.Write([]byte(toInput)) + if responseChan == nil { + // Returning a nil channel means we should kill the process. + // Note that we don't break the loop after this, because we + // still need to drain the output, otherwise the Wait() call + // later might block. + if err := Kill(cmdObj.GetCmd()); err != nil { + self.log.Error(err) + } + } else { + if task != nil { + task.Pause() + } + toInput := <-responseChan + if task != nil { + task.Continue() + } + // If the return data is empty we don't write anything to stdin + if toInput != "" { + _, _ = writer.Write([]byte(toInput)) + } } } } diff --git a/pkg/commands/oscommands/cmd_obj_runner_test.go b/pkg/commands/oscommands/cmd_obj_runner_test.go index c906cea3f..280ba213b 100644 --- a/pkg/commands/oscommands/cmd_obj_runner_test.go +++ b/pkg/commands/oscommands/cmd_obj_runner_test.go @@ -120,8 +120,8 @@ func TestProcessOutput(t *testing.T) { reader := strings.NewReader(scenario.output) writer := &strings.Builder{} - task := gocui.NewFakeTask() - runner.processOutput(reader, writer, toChanFn(scenario.promptUserForCredential), task) + cmdObj := &CmdObj{task: gocui.NewFakeTask()} + runner.processOutput(reader, writer, toChanFn(scenario.promptUserForCredential), cmdObj) if writer.String() != scenario.expectedToWrite { t.Errorf("expected to write '%s' but got '%s'", scenario.expectedToWrite, writer.String())