Keep only rsync's summary lines when not verbose

Every output line was kept in memory although only the last two were logged, and fewer than two lines (e.g. with --rsync-options q) raised an IndexError.
This commit is contained in:
Fuxino
2026-10-21 22:40:17 +02:00
parent b54f7e1817
commit 408beefc66
2 changed files with 20 additions and 4 deletions
+6 -3
View File
@@ -24,6 +24,7 @@ import re
import shlex import shlex
import sys import sys
import warnings import warnings
from collections import deque
from collections.abc import Callable, Iterator from collections.abc import Callable, Iterator
from datetime import datetime from datetime import datetime
from functools import wraps from functools import wraps
@@ -774,7 +775,8 @@ class Backup:
assert p.stdin is not None and isinstance(p.stdout, io.BufferedIOBase) assert p.stdin is not None and isinstance(p.stdout, io.BufferedIOBase)
p.stdin.close() p.stdin.close()
output = [] # Without -v, only the summary (the last two lines) is logged
output: list[str] | deque[str] = [] if self._verbose else deque(maxlen=2)
try: try:
for r in _read_records(p.stdout): for r in _read_records(p.stdout):
@@ -790,8 +792,9 @@ class Backup:
if self._verbose: if self._verbose:
logger.info('rsync: %s', output) logger.info('rsync: %s', output)
else: else:
logger.info('rsync: %s', output[-2]) # May be fewer than two lines, e.g. with --rsync-options q
logger.info('rsync: %s', output[-1]) for r in output:
logger.info('rsync: %s', r)
else: else:
self._returncode_log(returncode) self._returncode_log(returncode)
+14 -1
View File
@@ -298,12 +298,13 @@ class FakePopen:
returncode = 0 returncode = 0
calls: list[list[str]] = [] calls: list[list[str]] = []
output = b'sending incremental file list\nsent 1 bytes received 2 bytes\ntotal size is 3\n'
def __init__(self, args: list[str], **kwargs: Any) -> None: def __init__(self, args: list[str], **kwargs: Any) -> None:
FakePopen.calls.append(args) FakePopen.calls.append(args)
os.makedirs(args[args.index('/') + 1]) os.makedirs(args[args.index('/') + 1])
self.stdin = io.BytesIO() self.stdin = io.BytesIO()
self.stdout = io.BytesIO(b'sending incremental file list\nsent 1 bytes received 2 bytes\ntotal size is 3\n') self.stdout = io.BytesIO(FakePopen.output)
def __enter__(self) -> 'FakePopen': def __enter__(self) -> 'FakePopen':
return self return self
@@ -343,6 +344,18 @@ class TestReturnCodes:
assert f'--link-dest={out}/simple_backup/{old_backups[-1]}' in args assert f'--link-dest={out}/simple_backup/{old_backups[-1]}' in args
assert args[args.index('/') + 1] == f'{out}/simple_backup/2026-10-14_10-00-00' assert args[args.index('/') + 1] == f'{out}/simple_backup/2026-10-14_10-00-00'
@pytest.mark.parametrize('lines, logged', [
([f'file{n}' for n in range(5)] + ['sent 1 bytes', 'total size is 3'], ['sent 1 bytes', 'total size is 3']),
([], []),
(['total size is 3'], ['total size is 3']),
])
def test_summary_logged(self, src: Path, out: Path, fake_popen: type[FakePopen], monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture, lines: list[str], logged: list[str]) -> None:
monkeypatch.setattr(fake_popen, 'output', ''.join(f'{line}\n' for line in lines).encode())
assert run_backup(out, [str(src)]) == 0
assert [m[7:] for m in caplog.messages if m.startswith('rsync: ')] == logged
def test_rsync_missing(self, src: Path, out: Path, tmp_path: Path, fake_popen: type[FakePopen], def test_rsync_missing(self, src: Path, out: Path, tmp_path: Path, fake_popen: type[FakePopen],
old_backups: list[str], monkeypatch: pytest.MonkeyPatch, old_backups: list[str], monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture) -> None: caplog: pytest.LogCaptureFixture) -> None: