mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-15 12:58:04 +00:00
Skip vanished backup list entries (#2006)
This commit is contained in:
+23
-9
@@ -133,18 +133,32 @@ def cmd_list(args):
|
|||||||
emit([], args)
|
emit([], args)
|
||||||
return
|
return
|
||||||
entries = []
|
entries = []
|
||||||
for p in sorted(_BACKUP_DIR.iterdir(), key=lambda x: x.stat().st_mtime, reverse=True):
|
for p in _BACKUP_DIR.iterdir():
|
||||||
if not p.is_file():
|
entry = _backup_entry(p)
|
||||||
continue
|
if entry is not None:
|
||||||
entries.append({
|
entries.append(entry)
|
||||||
"path": str(p),
|
entries.sort(key=lambda entry: entry["_mtime"], reverse=True)
|
||||||
"name": p.name,
|
for entry in entries:
|
||||||
"bytes": p.stat().st_size,
|
entry.pop("_mtime", None)
|
||||||
"modified": datetime.fromtimestamp(p.stat().st_mtime).isoformat(),
|
|
||||||
})
|
|
||||||
emit(entries, args)
|
emit(entries, args)
|
||||||
|
|
||||||
|
|
||||||
|
def _backup_entry(p):
|
||||||
|
try:
|
||||||
|
if not p.is_file():
|
||||||
|
return None
|
||||||
|
st = p.stat()
|
||||||
|
except OSError:
|
||||||
|
return None
|
||||||
|
return {
|
||||||
|
"path": str(p),
|
||||||
|
"name": p.name,
|
||||||
|
"bytes": st.st_size,
|
||||||
|
"modified": datetime.fromtimestamp(st.st_mtime).isoformat(),
|
||||||
|
"_mtime": st.st_mtime,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def cmd_verify(args):
|
def cmd_verify(args):
|
||||||
"""Open the tarball read-only and walk its members — confirms
|
"""Open the tarball read-only and walk its members — confirms
|
||||||
integrity without extracting anything."""
|
integrity without extracting anything."""
|
||||||
|
|||||||
@@ -25,6 +25,46 @@ def _verify_args(path: Path):
|
|||||||
return SimpleNamespace(path=str(path), pretty=False)
|
return SimpleNamespace(path=str(path), pretty=False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_backup_entry_skips_files_that_disappear():
|
||||||
|
backup = _load_backup_cli()
|
||||||
|
|
||||||
|
class Vanished:
|
||||||
|
name = "gone.tar.gz"
|
||||||
|
|
||||||
|
def is_file(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def stat(self):
|
||||||
|
raise FileNotFoundError("gone")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "backups/gone.tar.gz"
|
||||||
|
|
||||||
|
assert backup._backup_entry(Vanished()) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_backup_list_sorts_by_captured_mtime(monkeypatch):
|
||||||
|
backup = _load_backup_cli()
|
||||||
|
first = SimpleNamespace(name="older.tar.gz")
|
||||||
|
second = SimpleNamespace(name="newer.tar.gz")
|
||||||
|
monkeypatch.setattr(backup, "_BACKUP_DIR", SimpleNamespace(
|
||||||
|
is_dir=lambda: True,
|
||||||
|
iterdir=lambda: [first, second],
|
||||||
|
))
|
||||||
|
monkeypatch.setattr(backup, "_backup_entry", lambda p: {
|
||||||
|
"name": p.name,
|
||||||
|
"modified": "2026-10-25T01:45:00" if p is first else "2026-10-25T01:15:00",
|
||||||
|
"_mtime": 100 if p is first else 200,
|
||||||
|
})
|
||||||
|
seen = []
|
||||||
|
monkeypatch.setattr(backup, "emit", lambda payload, args: seen.append(payload))
|
||||||
|
|
||||||
|
backup.cmd_list(SimpleNamespace(pretty=False))
|
||||||
|
|
||||||
|
assert [entry["name"] for entry in seen[0]] == ["newer.tar.gz", "older.tar.gz"]
|
||||||
|
assert all("_mtime" not in entry for entry in seen[0])
|
||||||
|
|
||||||
|
|
||||||
def test_snapshot_rejects_output_inside_data_dir(tmp_path, monkeypatch):
|
def test_snapshot_rejects_output_inside_data_dir(tmp_path, monkeypatch):
|
||||||
backup = _load_backup_cli()
|
backup = _load_backup_cli()
|
||||||
repo = tmp_path / "repo"
|
repo = tmp_path / "repo"
|
||||||
|
|||||||
Reference in New Issue
Block a user