Merge pull request #4318 from MichaelEischer/status-output-truncation
Fix status output truncation
This commit is contained in:
commit
db046c0acc
3 changed files with 86 additions and 10 deletions
8
changelog/unreleased/pull-4318
Normal file
8
changelog/unreleased/pull-4318
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Bugfix: Correctly clean up status bar output of the `backup` command
|
||||||
|
|
||||||
|
Due to a regression in restic 0.15.2, the status bar of the `backup` command
|
||||||
|
could leave some output behind. This happened if filenames were printed that
|
||||||
|
are wider than the current terminal width. This has been fixed.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/issues/4319
|
||||||
|
https://github.com/restic/restic/pull/4318
|
|
@ -334,6 +334,21 @@ func wideRune(s string) (wide bool, utfsize uint) {
|
||||||
return wide, uint(size)
|
return wide, uint(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sanitizeLines(lines []string, width int) []string {
|
||||||
|
// Sanitize lines and truncate them if they're too long.
|
||||||
|
for i, line := range lines {
|
||||||
|
line = Quote(line)
|
||||||
|
if width > 0 {
|
||||||
|
line = Truncate(line, width-2)
|
||||||
|
}
|
||||||
|
if i < len(lines)-1 { // Last line gets no line break.
|
||||||
|
line += "\n"
|
||||||
|
}
|
||||||
|
lines[i] = line
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
// SetStatus updates the status lines.
|
// SetStatus updates the status lines.
|
||||||
// The lines should not contain newlines; this method adds them.
|
// The lines should not contain newlines; this method adds them.
|
||||||
func (t *Terminal) SetStatus(lines []string) {
|
func (t *Terminal) SetStatus(lines []string) {
|
||||||
|
@ -352,16 +367,7 @@ func (t *Terminal) SetStatus(lines []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize lines and truncate them if they're too long.
|
sanitizeLines(lines, width)
|
||||||
for i, line := range lines {
|
|
||||||
line = Quote(line)
|
|
||||||
if width > 0 {
|
|
||||||
line = Truncate(line, width-2)
|
|
||||||
}
|
|
||||||
if i < len(lines)-1 { // Last line gets no line break.
|
|
||||||
lines[i] = line + "\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case t.status <- status{lines: lines}:
|
case t.status <- status{lines: lines}:
|
||||||
|
|
|
@ -1,12 +1,54 @@
|
||||||
package termstatus
|
package termstatus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestSetStatus(t *testing.T) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
term := New(&buf, io.Discard, false)
|
||||||
|
|
||||||
|
term.canUpdateStatus = true
|
||||||
|
term.fd = ^uintptr(0)
|
||||||
|
term.clearCurrentLine = posixClearCurrentLine
|
||||||
|
term.moveCursorUp = posixMoveCursorUp
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
go term.Run(ctx)
|
||||||
|
|
||||||
|
const (
|
||||||
|
clear = posixControlClearLine
|
||||||
|
home = posixControlMoveCursorHome
|
||||||
|
up = posixControlMoveCursorUp
|
||||||
|
)
|
||||||
|
|
||||||
|
term.SetStatus([]string{"first"})
|
||||||
|
exp := home + clear + "first" + home
|
||||||
|
|
||||||
|
term.SetStatus([]string{"foo", "bar", "baz"})
|
||||||
|
exp += home + clear + "foo\n" + home + clear + "bar\n" +
|
||||||
|
home + clear + "baz" + home + up + up
|
||||||
|
|
||||||
|
term.SetStatus([]string{"quux", "needs\nquote"})
|
||||||
|
exp += home + clear + "quux\n" +
|
||||||
|
home + clear + "\"needs\\nquote\"\n" +
|
||||||
|
home + clear + home + up + up // Third line implicit.
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
exp += home + clear + "\n" + home + clear + "\n" +
|
||||||
|
home + up + up // Status cleared.
|
||||||
|
|
||||||
|
<-term.closed
|
||||||
|
rtest.Equals(t, exp, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
func TestQuote(t *testing.T) {
|
func TestQuote(t *testing.T) {
|
||||||
for _, c := range []struct {
|
for _, c := range []struct {
|
||||||
in string
|
in string
|
||||||
|
@ -91,3 +133,23 @@ func BenchmarkTruncateUnicode(b *testing.B) {
|
||||||
|
|
||||||
benchmarkTruncate(b, s, w-1)
|
benchmarkTruncate(b, s, w-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSanitizeLines(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
input []string
|
||||||
|
width int
|
||||||
|
output []string
|
||||||
|
}{
|
||||||
|
{[]string{""}, 80, []string{""}},
|
||||||
|
{[]string{"too long test line"}, 10, []string{"too long"}},
|
||||||
|
{[]string{"too long test line", "text"}, 10, []string{"too long\n", "text"}},
|
||||||
|
{[]string{"too long test line", "second long test line"}, 10, []string{"too long\n", "second l"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(fmt.Sprintf("%s %d", test.input, test.width), func(t *testing.T) {
|
||||||
|
out := sanitizeLines(test.input, test.width)
|
||||||
|
rtest.Equals(t, test.output, out)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue