Cofnij ostatnią operację
undo przywraca pliki z dziennika — i odmawia usunięcia tego, co pojawiło się w pierwotnym miejscu.
Komenda undo znajduje ostatni manifest, odczytuje lista
wykonanych przeniesień i zwraca pliki tam, skąd zostały wzięte. Tutaj obowiązuje
ta sama zasada co w całym programie: nic nie nadpisywać milcząco.
def undo(manifest: OperationManifest) -> UndoResult:
restored, conflicts = [], []
for move in manifest.moves:
if not move.completed:
continue
source, destination = move.source, move.destination
if source.exists() or source.is_symlink():
conflicts.append(UndoConflict(source, destination,
"a file already exists at the original location"))
continue
shutil.move(str(destination), str(source))
restored.append(CompletedMove(destination, source, completed=True))
return UndoResult(restored=tuple(restored), conflicts=tuple(conflicts))
if not move.completed: continue – Ruchy, które zawiodły podczas apply, nigdy nie dotykały dysku i nie ma czego cofnąć.Najpierw standardowe skuteczne cofnięcie się:
Konflikt anulowania – rzeczywisty scenariusz
Co się stanie, jeśli uruchomimy undo ponownie, gdy
już na swoich pierwotnych miejscach? Samo cofanie się wymaże to, co już tam jest. Zamiast
ten SafeSort sprawdza oryginalną lokalizację wcześniej odzyskiwaniu każdego pliku i,
Jeśli coś już tam jest, odmawia przywrócenia tego konkretnego pliku:
Odmowa — a nie ciche nadpisanie. Każdy konflikt jest przetwarzany niezależnie: pliki bez konfliktu zostałyby przywrócone, nawet jeśli część listy odmówiła.
Punkt kontrolny testowy: Operacja odwrotna
def test_undo_restores_original_location(tmp_path):
source = tmp_path / "report.pdf"
source.write_bytes(b"report")
plan = build_plan(scan(tmp_path, Config()), tmp_path, Config())
moves = apply_plan(plan)
manifest, _ = write_manifest(tmp_path, moves)
result = undo(manifest)
assert len(result.restored) == 1
assert source.read_bytes() == b"report"