mirror of
https://github.com/borgbackup/borg.git
synced 2026-06-09 08:51:54 -04:00
Merge pull request #9422 from ThomasWaldmann/deletion-fixes
Some checks are pending
Lint / lint (push) Waiting to run
CI / lint (push) Waiting to run
CI / security (push) Waiting to run
CI / asan_ubsan (push) Blocked by required conditions
CI / native_tests (push) Blocked by required conditions
CI / vm_tests (Haiku, false, haiku, r1beta5) (push) Blocked by required conditions
CI / vm_tests (NetBSD, false, netbsd, 10.1) (push) Blocked by required conditions
CI / vm_tests (OmniOS, false, omnios, r151056) (push) Blocked by required conditions
CI / vm_tests (OpenBSD, false, openbsd, 7.7) (push) Blocked by required conditions
CI / vm_tests (borg-freebsd-14-x86_64-gh, FreeBSD, true, freebsd, 14.3) (push) Blocked by required conditions
CI / windows_tests (push) Blocked by required conditions
CodeQL / Analyze (push) Waiting to run
Some checks are pending
Lint / lint (push) Waiting to run
CI / lint (push) Waiting to run
CI / security (push) Waiting to run
CI / asan_ubsan (push) Blocked by required conditions
CI / native_tests (push) Blocked by required conditions
CI / vm_tests (Haiku, false, haiku, r1beta5) (push) Blocked by required conditions
CI / vm_tests (NetBSD, false, netbsd, 10.1) (push) Blocked by required conditions
CI / vm_tests (OmniOS, false, omnios, r151056) (push) Blocked by required conditions
CI / vm_tests (OpenBSD, false, openbsd, 7.7) (push) Blocked by required conditions
CI / vm_tests (borg-freebsd-14-x86_64-gh, FreeBSD, true, freebsd, 14.3) (push) Blocked by required conditions
CI / windows_tests (push) Blocked by required conditions
CodeQL / Analyze (push) Waiting to run
prune/delete fixes
This commit is contained in:
commit
b38107c506
3 changed files with 29 additions and 8 deletions
|
|
@ -36,6 +36,8 @@ class DeleteMixIn:
|
|||
logger_list = logging.getLogger("borg.output.list")
|
||||
for i, archive_info in enumerate(archive_infos, 1):
|
||||
name, id, hex_id = archive_info.name, archive_info.id, bin_to_hex(archive_info.id)
|
||||
# format early before deletion of the archive
|
||||
archive_formatted = format_archive(archive_info)
|
||||
try:
|
||||
# this does NOT use Archive.delete, so this code hopefully even works in cases a corrupt archive
|
||||
# would make the code in class Archive crash, so the user can at least get rid of such archives.
|
||||
|
|
@ -47,7 +49,7 @@ class DeleteMixIn:
|
|||
deleted = True
|
||||
if self.output_list:
|
||||
msg = "Would delete: {} ({}/{})" if dry_run else "Deleted archive: {} ({}/{})"
|
||||
logger_list.info(msg.format(format_archive(archive_info), i, count))
|
||||
logger_list.info(msg.format(archive_formatted, i, count))
|
||||
if dry_run:
|
||||
logger.info("Finished dry-run.")
|
||||
elif deleted:
|
||||
|
|
|
|||
|
|
@ -179,29 +179,32 @@ class PruneMixIn:
|
|||
archives_deleted = 0
|
||||
uncommitted_deletes = 0
|
||||
pi = ProgressIndicatorPercent(total=len(to_delete), msg="Pruning archives %3.0f%%", msgid="prune")
|
||||
for archive in archives:
|
||||
for archive_info in archives:
|
||||
if sig_int and sig_int.action_done():
|
||||
break
|
||||
if archive in to_delete:
|
||||
# format_item may internally load the archive from the repository,
|
||||
# so we must call it before deleting the archive.
|
||||
archive_formatted = formatter.format_item(archive_info, jsonline=False)
|
||||
if archive_info in to_delete:
|
||||
pi.show()
|
||||
if args.dry_run:
|
||||
log_message = "Would prune:"
|
||||
else:
|
||||
archives_deleted += 1
|
||||
log_message = "Pruning archive (%d/%d):" % (archives_deleted, to_delete_len)
|
||||
archive = Archive(manifest, archive.id, cache=cache)
|
||||
archive = Archive(manifest, archive_info.id, cache=cache)
|
||||
archive.delete()
|
||||
uncommitted_deletes += 1
|
||||
else:
|
||||
log_message = "Keeping archive (rule: {rule} #{num}):".format(
|
||||
rule=kept_because[archive.id][0], num=kept_because[archive.id][1]
|
||||
rule=kept_because[archive_info.id][0], num=kept_because[archive_info.id][1]
|
||||
)
|
||||
if (
|
||||
args.output_list
|
||||
or (args.list_pruned and archive in to_delete)
|
||||
or (args.list_kept and archive not in to_delete)
|
||||
or (args.list_pruned and archive_info in to_delete)
|
||||
or (args.list_kept and archive_info not in to_delete)
|
||||
):
|
||||
list_logger.info(f"{log_message:<44} {formatter.format_item(archive, jsonline=False)}")
|
||||
list_logger.info(f"{log_message:<44} {archive_formatted}")
|
||||
pi.finish()
|
||||
if sig_int:
|
||||
raise Error("Got Ctrl-C / SIGINT.")
|
||||
|
|
|
|||
|
|
@ -400,3 +400,19 @@ def test_prune_split_no_archives():
|
|||
|
||||
assert keep == []
|
||||
assert kept_because == {}
|
||||
|
||||
|
||||
def test_prune_list_with_metadata_format(archivers, request):
|
||||
# Regression test for: prune --list with a format string that requires loading
|
||||
# archive metadata (e.g. {hostname}) must not fail when archives are deleted.
|
||||
# The bug was that format_item() was called after archive.delete(), causing
|
||||
# Archive.DoesNotExist when the formatter tried to lazy-load the archive.
|
||||
archiver = request.getfixturevalue(archivers)
|
||||
cmd(archiver, "repo-create", RK_ENCRYPTION)
|
||||
cmd(archiver, "create", "test1", src_dir)
|
||||
cmd(archiver, "create", "test2", src_dir)
|
||||
# {hostname} is a "call key" that triggers lazy loading of the archive from the repo.
|
||||
# With the buggy code this would raise Archive.DoesNotExist for the pruned archive.
|
||||
output = cmd(archiver, "prune", "--list", "--keep-daily=1", "--format={name} {hostname}{NL}")
|
||||
assert "test1" in output
|
||||
assert "test2" in output
|
||||
|
|
|
|||
Loading…
Reference in a new issue