diff --git a/src/borg/archive.py b/src/borg/archive.py index ad17dc9be..4e334d164 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -141,9 +141,12 @@ class Statistics: def csize_fmt(self): return format_file_size(self.csize, iec=self.iec) + PROGRESS_FMT = '{0.osize_fmt} O {0.csize_fmt} C {0.usize_fmt} D {0.nfiles} N ' + def show_progress(self, item=None, final=False, stream=None, dt=None): now = time.monotonic() if dt is None or now - self.last_progress > dt: + stream = stream or sys.stderr self.last_progress = now if self.output_json: if not final: @@ -158,10 +161,18 @@ class Statistics: }) msg = json.dumps(data) end = '\n' + elif not stream.isatty(): + # if we don't output to a terminal, use normal linefeeds and assume line length is unlimited + if not final: + msg = self.PROGRESS_FMT.format(self) + msg += remove_surrogates(item.path) if item else '' + else: + msg = '' + end = '\n' else: columns, lines = get_terminal_size() if not final: - msg = '{0.osize_fmt} O {0.csize_fmt} C {0.usize_fmt} D {0.nfiles} N '.format(self) + msg = self.PROGRESS_FMT.format(self) path = remove_surrogates(item.path) if item else '' space = columns - swidth(msg) if space < 12: @@ -172,7 +183,7 @@ class Statistics: else: msg = ' ' * columns end = '\r' - print(msg, end=end, file=stream or sys.stderr, flush=True) + print(msg, end=end, file=stream, flush=True) def is_special(mode): diff --git a/src/borg/testsuite/archive.py b/src/borg/testsuite/archive.py index 08aef74aa..7358a0454 100644 --- a/src/borg/testsuite/archive.py +++ b/src/borg/testsuite/archive.py @@ -32,27 +32,50 @@ def test_stats_basic(stats): assert stats.usize == 10 -def tests_stats_progress(stats, monkeypatch, columns=80): +def tests_stats_progress_tty(stats, monkeypatch, columns=80): + class TTYStringIO(StringIO): + def isatty(self): + return True + monkeypatch.setenv('COLUMNS', str(columns)) - out = StringIO() + out = TTYStringIO() stats.show_progress(stream=out) s = '20 B O 10 B C 10 B D 0 N ' buf = ' ' * (columns - len(s)) assert out.getvalue() == s + buf + "\r" - out = StringIO() + out = TTYStringIO() stats.update(10**3, 0, unique=False) stats.show_progress(item=Item(path='foo'), final=False, stream=out) s = '1.02 kB O 10 B C 10 B D 0 N foo' buf = ' ' * (columns - len(s)) assert out.getvalue() == s + buf + "\r" - out = StringIO() + out = TTYStringIO() stats.show_progress(item=Item(path='foo'*40), final=False, stream=out) s = '1.02 kB O 10 B C 10 B D 0 N foofoofoofoofoofoofoofo...oofoofoofoofoofoofoofoofoo' buf = ' ' * (columns - len(s)) assert out.getvalue() == s + buf + "\r" +def tests_stats_progress_file(stats, monkeypatch): + out = StringIO() + stats.show_progress(stream=out) + s = '20 B O 10 B C 10 B D 0 N ' + assert out.getvalue() == s + "\n" + + out = StringIO() + stats.update(10**3, 0, unique=False) + path = 'foo' + stats.show_progress(item=Item(path=path), final=False, stream=out) + s = f'1.02 kB O 10 B C 10 B D 0 N {path}' + assert out.getvalue() == s + "\n" + out = StringIO() + path = 'foo' * 40 + stats.show_progress(item=Item(path=path), final=False, stream=out) + s = f'1.02 kB O 10 B C 10 B D 0 N {path}' + assert out.getvalue() == s + "\n" + + def test_stats_format(stats): assert str(stats) == """\ This archive: 20 B 10 B 10 B"""