Skip to content

Commit 676b5c2

Browse files
authored
Kill background fetch when it requests a passphrase (#4588)
Previously we would enter a newline at the password prompt, which would cause the fetch to fail. The problem with this was that if you have many remotes, the fetch would sometimes hang for some reason; I don't totally understand how that happened, but I guess the many ssh processes requesting passwords would somehow interfere with each other. Avoid this by simply killing the git fetch process the moment it requests the first password.
2 parents c4bfdae + d5bd304 commit 676b5c2

File tree

2 files changed

+28
-22
lines changed

2 files changed

+28
-22
lines changed

pkg/commands/oscommands/cmd_obj_runner.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"time"
1111

1212
"github.com/go-errors/errors"
13-
"github.com/jesseduffield/gocui"
1413
"github.com/jesseduffield/lazygit/pkg/utils"
1514
"github.com/sasha-s/go-deadlock"
1615
"github.com/sirupsen/logrus"
@@ -295,14 +294,10 @@ const (
295294
Token
296295
)
297296

298-
// Whenever we're asked for a password we just enter a newline, which will
299-
// eventually cause the command to fail.
297+
// Whenever we're asked for a password we return a nil channel to tell the
298+
// caller to kill the process.
300299
var failPromptFn = func(CredentialType) <-chan string {
301-
ch := make(chan string)
302-
go func() {
303-
ch <- "\n"
304-
}()
305-
return ch
300+
return nil
306301
}
307302

308303
func (self *cmdObjRunner) runWithCredentialHandling(cmdObj *CmdObj) error {
@@ -340,7 +335,7 @@ func (self *cmdObjRunner) runAndDetectCredentialRequest(
340335
tr := io.TeeReader(handler.stdoutPipe, cmdWriter)
341336

342337
go utils.Safe(func() {
343-
self.processOutput(tr, handler.stdinPipe, promptUserForCredential, cmdObj.GetTask())
338+
self.processOutput(tr, handler.stdinPipe, promptUserForCredential, cmdObj)
344339
})
345340
})
346341
}
@@ -349,9 +344,10 @@ func (self *cmdObjRunner) processOutput(
349344
reader io.Reader,
350345
writer io.Writer,
351346
promptUserForCredential func(CredentialType) <-chan string,
352-
task gocui.Task,
347+
cmdObj *CmdObj,
353348
) {
354349
checkForCredentialRequest := self.getCheckForCredentialRequestFunc()
350+
task := cmdObj.GetTask()
355351

356352
scanner := bufio.NewScanner(reader)
357353
scanner.Split(bufio.ScanBytes)
@@ -360,16 +356,26 @@ func (self *cmdObjRunner) processOutput(
360356
askFor, ok := checkForCredentialRequest(newBytes)
361357
if ok {
362358
responseChan := promptUserForCredential(askFor)
363-
if task != nil {
364-
task.Pause()
365-
}
366-
toInput := <-responseChan
367-
if task != nil {
368-
task.Continue()
369-
}
370-
// If the return data is empty we don't write anything to stdin
371-
if toInput != "" {
372-
_, _ = writer.Write([]byte(toInput))
359+
if responseChan == nil {
360+
// Returning a nil channel means we should kill the process.
361+
// Note that we don't break the loop after this, because we
362+
// still need to drain the output, otherwise the Wait() call
363+
// later might block.
364+
if err := Kill(cmdObj.GetCmd()); err != nil {
365+
self.log.Error(err)
366+
}
367+
} else {
368+
if task != nil {
369+
task.Pause()
370+
}
371+
toInput := <-responseChan
372+
if task != nil {
373+
task.Continue()
374+
}
375+
// If the return data is empty we don't write anything to stdin
376+
if toInput != "" {
377+
_, _ = writer.Write([]byte(toInput))
378+
}
373379
}
374380
}
375381
}

pkg/commands/oscommands/cmd_obj_runner_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ func TestProcessOutput(t *testing.T) {
120120
reader := strings.NewReader(scenario.output)
121121
writer := &strings.Builder{}
122122

123-
task := gocui.NewFakeTask()
124-
runner.processOutput(reader, writer, toChanFn(scenario.promptUserForCredential), task)
123+
cmdObj := &CmdObj{task: gocui.NewFakeTask()}
124+
runner.processOutput(reader, writer, toChanFn(scenario.promptUserForCredential), cmdObj)
125125

126126
if writer.String() != scenario.expectedToWrite {
127127
t.Errorf("expected to write '%s' but got '%s'", scenario.expectedToWrite, writer.String())

0 commit comments

Comments
 (0)