Merge pull request #5554 from MichaelEischer/termstatus-flush

termstatus: flush before reading password from terminal
This commit is contained in:
Michael Eischer
2025-10-12 17:59:03 +02:00
committed by GitHub
3 changed files with 37 additions and 3 deletions

View File

@@ -0,0 +1,7 @@
Bugfix: Password prompt was sometimes not shown
The password prompt for a repository was sometimes not shown when running
the `backup -v` command. This has been fixed.
https://github.com/restic/restic/issues/5477
https://github.com/restic/restic/pull/5554

View File

@@ -42,8 +42,9 @@ type Terminal struct {
}
type message struct {
line string
err bool
line string
err bool
barrier chan struct{}
}
type status struct {
@@ -79,6 +80,7 @@ func Setup(stdin io.ReadCloser, stdout, stderr io.Writer, quiet bool) (*Terminal
if term.outputWriter != nil {
_ = term.outputWriter.Close()
}
term.Flush()
// shutdown termstatus
cancel()
wg.Wait()
@@ -141,6 +143,7 @@ func (t *Terminal) InputRaw() io.ReadCloser {
func (t *Terminal) ReadPassword(ctx context.Context, prompt string) (string, error) {
if t.InputIsTerminal() {
t.Flush()
return terminal.ReadPassword(ctx, int(t.inFd), t.errWriter, prompt)
}
if t.OutputIsTerminal() {
@@ -177,6 +180,7 @@ func (t *Terminal) OutputWriter() io.Writer {
// other option. Must not be used in combination with Print, Error, SetStatus
// or any other method that writes to the terminal.
func (t *Terminal) OutputRaw() io.Writer {
t.Flush()
return t.wr
}
@@ -210,6 +214,10 @@ func (t *Terminal) run(ctx context.Context) {
return
case msg := <-t.msg:
if msg.barrier != nil {
msg.barrier <- struct{}{}
continue
}
if terminal.IsProcessBackground(t.fd) {
// ignore all messages, do nothing, we are in the background process group
continue
@@ -284,6 +292,10 @@ func (t *Terminal) runWithoutStatus(ctx context.Context) {
case <-ctx.Done():
return
case msg := <-t.msg:
if msg.barrier != nil {
msg.barrier <- struct{}{}
continue
}
var dst io.Writer
if msg.err {
@@ -307,6 +319,20 @@ func (t *Terminal) runWithoutStatus(ctx context.Context) {
}
}
// Flush waits for all pending messages to be printed.
func (t *Terminal) Flush() {
ch := make(chan struct{})
defer close(ch)
select {
case t.msg <- message{barrier: ch}:
case <-t.closed:
}
select {
case <-ch:
case <-t.closed:
}
}
func (t *Terminal) print(line string, isErr bool) {
// make sure the line ends with a line break
if len(line) == 0 || line[len(line)-1] != '\n' {

View File

@@ -124,7 +124,8 @@ func TestReadPasswordTerminal(t *testing.T) {
func TestRawInputOutput(t *testing.T) {
input := io.NopCloser(strings.NewReader("password"))
var output bytes.Buffer
term := New(input, &output, io.Discard, false)
term, cancel := Setup(input, &output, io.Discard, false)
defer cancel()
rtest.Equals(t, input, term.InputRaw())
rtest.Equals(t, false, term.InputIsTerminal())
rtest.Equals(t, &output, term.OutputRaw())