move delete command to archiver.delete

This commit is contained in:
Thomas Waldmann 2022-07-09 01:08:39 +02:00
parent 06fe8d3e64
commit 350a8fe252
3 changed files with 169 additions and 148 deletions

View File

@ -121,6 +121,7 @@ per_file_ignores =
src/borg/archiver/config.py:F405,E722 src/borg/archiver/config.py:F405,E722
src/borg/archiver/common.py:E501,F405 src/borg/archiver/common.py:E501,F405
src/borg/archiver/debug.py:F405 src/borg/archiver/debug.py:F405
src/borg/archiver/delete.py:F405
src/borg/archiver/diff.py:F405 src/borg/archiver/diff.py:F405
src/borg/archiver/help.py:E501,F405 src/borg/archiver/help.py:E501,F405
src/borg/archiver/keys.py:F405 src/borg/archiver/keys.py:F405

View File

@ -28,7 +28,7 @@ try:
from .common import with_repository, with_archive, Highlander from .common import with_repository, with_archive, Highlander
from .. import __version__ from .. import __version__
from .. import helpers from .. import helpers
from ..archive import Archive, ArchiveRecreater, Statistics, is_special from ..archive import Archive, ArchiveRecreater, is_special
from ..archive import BackupError, BackupOSError, backup_io, OsOpen, stat_update_check from ..archive import BackupError, BackupOSError, backup_io, OsOpen, stat_update_check
from ..archive import FilesystemObjectProcessors, MetadataCollector, ChunksProcessor from ..archive import FilesystemObjectProcessors, MetadataCollector, ChunksProcessor
from ..cache import Cache from ..cache import Cache
@ -39,7 +39,7 @@ try:
from ..helpers import location_validator, archivename_validator, ChunkerParams, Location from ..helpers import location_validator, archivename_validator, ChunkerParams, Location
from ..helpers import NameSpec, CommentSpec, FilesCacheMode from ..helpers import NameSpec, CommentSpec, FilesCacheMode
from ..helpers import BaseFormatter, ItemFormatter, ArchiveFormatter from ..helpers import BaseFormatter, ItemFormatter, ArchiveFormatter
from ..helpers import format_timedelta, format_file_size, format_archive from ..helpers import format_timedelta, format_file_size
from ..helpers import remove_surrogates, bin_to_hex, eval_escapes from ..helpers import remove_surrogates, bin_to_hex, eval_escapes
from ..helpers import timestamp from ..helpers import timestamp
from ..helpers import get_cache_dir, os_stat from ..helpers import get_cache_dir, os_stat
@ -93,6 +93,7 @@ from .check import CheckMixIn
from .compact import CompactMixIn from .compact import CompactMixIn
from .config import ConfigMixIn from .config import ConfigMixIn
from .debug import DebugMixIn from .debug import DebugMixIn
from .delete import DeleteMixIn
from .diff import DiffMixIn from .diff import DiffMixIn
from .help import HelpMixIn from .help import HelpMixIn
from .keys import KeysMixIn from .keys import KeysMixIn
@ -112,6 +113,7 @@ class Archiver(
ConfigMixIn, ConfigMixIn,
CompactMixIn, CompactMixIn,
DebugMixIn, DebugMixIn,
DeleteMixIn,
DiffMixIn, DiffMixIn,
TarMixIn, TarMixIn,
BenchmarkMixIn, BenchmarkMixIn,
@ -697,83 +699,6 @@ class Archiver(
pi.finish() pi.finish()
return self.exit_code return self.exit_code
@with_repository(exclusive=True, manifest=False)
def do_delete(self, args, repository):
"""Delete archives"""
self.output_list = args.output_list
dry_run = args.dry_run
manifest, key = Manifest.load(repository, (Manifest.Operation.DELETE,))
archive_names = tuple(x.name for x in manifest.archives.list_considering(args))
if not archive_names:
return self.exit_code
if args.glob_archives is None and args.first == 0 and args.last == 0:
self.print_error(
"Aborting: if you really want to delete all archives, please use -a '*' "
"or just delete the whole repository (might be much faster)."
)
return EXIT_ERROR
if args.forced == 2:
deleted = False
logger_list = logging.getLogger("borg.output.list")
for i, archive_name in enumerate(archive_names, 1):
try:
current_archive = manifest.archives.pop(archive_name)
except KeyError:
self.exit_code = EXIT_WARNING
logger.warning(f"Archive {archive_name} not found ({i}/{len(archive_names)}).")
else:
deleted = True
if self.output_list:
msg = "Would delete: {} ({}/{})" if dry_run else "Deleted archive: {} ({}/{})"
logger_list.info(msg.format(format_archive(current_archive), i, len(archive_names)))
if dry_run:
logger.info("Finished dry-run.")
elif deleted:
manifest.write()
# note: might crash in compact() after committing the repo
repository.commit(compact=False)
logger.warning('Done. Run "borg check --repair" to clean up the mess.')
else:
logger.warning("Aborted.")
return self.exit_code
stats = Statistics(iec=args.iec)
with Cache(repository, key, manifest, progress=args.progress, lock_wait=self.lock_wait, iec=args.iec) as cache:
msg_delete = "Would delete archive: {} ({}/{})" if dry_run else "Deleting archive: {} ({}/{})"
msg_not_found = "Archive {} not found ({}/{})."
logger_list = logging.getLogger("borg.output.list")
delete_count = 0
for i, archive_name in enumerate(archive_names, 1):
try:
archive_info = manifest.archives[archive_name]
except KeyError:
logger.warning(msg_not_found.format(archive_name, i, len(archive_names)))
else:
if self.output_list:
logger_list.info(msg_delete.format(format_archive(archive_info), i, len(archive_names)))
if not dry_run:
archive = Archive(
repository,
key,
manifest,
archive_name,
cache=cache,
consider_part_files=args.consider_part_files,
)
archive.delete(stats, progress=args.progress, forced=args.forced)
delete_count += 1
if delete_count > 0:
# only write/commit if we actually changed something, see #6060.
manifest.write()
repository.commit(compact=False, save_space=args.save_space)
cache.commit()
if args.stats:
log_multi(str(stats), logger=logging.getLogger("borg.output.stats"))
return self.exit_code
@with_repository(compatibility=(Manifest.Operation.READ,)) @with_repository(compatibility=(Manifest.Operation.READ,))
def do_list(self, args, repository, manifest, key): def do_list(self, args, repository, manifest, key):
"""List archive contents""" """List archive contents"""
@ -1672,78 +1597,10 @@ class Archiver(
self.build_parser_config(subparsers, common_parser, mid_common_parser) self.build_parser_config(subparsers, common_parser, mid_common_parser)
self.build_parser_debug(subparsers, common_parser, mid_common_parser) self.build_parser_debug(subparsers, common_parser, mid_common_parser)
self.build_parser_delete(subparsers, common_parser, mid_common_parser)
self.build_parser_help(subparsers, common_parser, mid_common_parser, parser) self.build_parser_help(subparsers, common_parser, mid_common_parser, parser)
self.build_parser_rdelete(subparsers, common_parser, mid_common_parser, parser) self.build_parser_rdelete(subparsers, common_parser, mid_common_parser, parser)
# borg delete
delete_epilog = process_epilog(
"""
This command deletes archives from the repository.
Important: When deleting archives, repository disk space is **not** freed until
you run ``borg compact``.
When in doubt, use ``--dry-run --list`` to see what would be deleted.
When using ``--stats``, you will get some statistics about how much data was
deleted - the "Deleted data" deduplicated size there is most interesting as
that is how much your repository will shrink.
Please note that the "All archives" stats refer to the state after deletion.
You can delete multiple archives by specifying a matching shell pattern,
using the ``--glob-archives GLOB`` option (for more info on these patterns,
see :ref:`borg_patterns`).
Always first use ``--dry-run --list`` to see what would be deleted.
"""
)
subparser = subparsers.add_parser(
"delete",
parents=[common_parser],
add_help=False,
description=self.do_delete.__doc__,
epilog=delete_epilog,
formatter_class=argparse.RawDescriptionHelpFormatter,
help="delete archive",
)
subparser.set_defaults(func=self.do_delete)
subparser.add_argument("-n", "--dry-run", dest="dry_run", action="store_true", help="do not change repository")
subparser.add_argument(
"--list", dest="output_list", action="store_true", help="output verbose list of archives"
)
subparser.add_argument(
"--consider-checkpoints",
action="store_true",
dest="consider_checkpoints",
help="consider checkpoint archives for deletion (default: not considered).",
)
subparser.add_argument(
"-s", "--stats", dest="stats", action="store_true", help="print statistics for the deleted archive"
)
subparser.add_argument(
"--cache-only",
dest="cache_only",
action="store_true",
help="delete only the local cache for the given repository",
)
subparser.add_argument(
"--force",
dest="forced",
action="count",
default=0,
help="force deletion of corrupted archives, " "use ``--force --force`` in case ``--force`` does not work.",
)
subparser.add_argument(
"--keep-security-info",
dest="keep_security_info",
action="store_true",
help="keep the local security info when deleting a repository",
)
subparser.add_argument(
"--save-space", dest="save_space", action="store_true", help="work slower, but using less space"
)
define_archive_filters_group(subparser)
# borg extract # borg extract
extract_epilog = process_epilog( extract_epilog = process_epilog(
""" """

163
src/borg/archiver/delete.py Normal file
View File

@ -0,0 +1,163 @@
import argparse
import logging
from .common import with_repository
from ..archive import Archive, Statistics
from ..cache import Cache
from ..constants import * # NOQA
from ..helpers import Manifest
from ..helpers import log_multi, format_archive
from ..logger import create_logger
logger = create_logger()
class DeleteMixIn:
@with_repository(exclusive=True, manifest=False)
def do_delete(self, args, repository):
"""Delete archives"""
self.output_list = args.output_list
dry_run = args.dry_run
manifest, key = Manifest.load(repository, (Manifest.Operation.DELETE,))
archive_names = tuple(x.name for x in manifest.archives.list_considering(args))
if not archive_names:
return self.exit_code
if args.glob_archives is None and args.first == 0 and args.last == 0:
self.print_error(
"Aborting: if you really want to delete all archives, please use -a '*' "
"or just delete the whole repository (might be much faster)."
)
return EXIT_ERROR
if args.forced == 2:
deleted = False
logger_list = logging.getLogger("borg.output.list")
for i, archive_name in enumerate(archive_names, 1):
try:
current_archive = manifest.archives.pop(archive_name)
except KeyError:
self.exit_code = EXIT_WARNING
logger.warning(f"Archive {archive_name} not found ({i}/{len(archive_names)}).")
else:
deleted = True
if self.output_list:
msg = "Would delete: {} ({}/{})" if dry_run else "Deleted archive: {} ({}/{})"
logger_list.info(msg.format(format_archive(current_archive), i, len(archive_names)))
if dry_run:
logger.info("Finished dry-run.")
elif deleted:
manifest.write()
# note: might crash in compact() after committing the repo
repository.commit(compact=False)
logger.warning('Done. Run "borg check --repair" to clean up the mess.')
else:
logger.warning("Aborted.")
return self.exit_code
stats = Statistics(iec=args.iec)
with Cache(repository, key, manifest, progress=args.progress, lock_wait=self.lock_wait, iec=args.iec) as cache:
msg_delete = "Would delete archive: {} ({}/{})" if dry_run else "Deleting archive: {} ({}/{})"
msg_not_found = "Archive {} not found ({}/{})."
logger_list = logging.getLogger("borg.output.list")
delete_count = 0
for i, archive_name in enumerate(archive_names, 1):
try:
archive_info = manifest.archives[archive_name]
except KeyError:
logger.warning(msg_not_found.format(archive_name, i, len(archive_names)))
else:
if self.output_list:
logger_list.info(msg_delete.format(format_archive(archive_info), i, len(archive_names)))
if not dry_run:
archive = Archive(
repository,
key,
manifest,
archive_name,
cache=cache,
consider_part_files=args.consider_part_files,
)
archive.delete(stats, progress=args.progress, forced=args.forced)
delete_count += 1
if delete_count > 0:
# only write/commit if we actually changed something, see #6060.
manifest.write()
repository.commit(compact=False, save_space=args.save_space)
cache.commit()
if args.stats:
log_multi(str(stats), logger=logging.getLogger("borg.output.stats"))
return self.exit_code
def build_parser_delete(self, subparsers, common_parser, mid_common_parser):
from .common import process_epilog, define_archive_filters_group
delete_epilog = process_epilog(
"""
This command deletes archives from the repository.
Important: When deleting archives, repository disk space is **not** freed until
you run ``borg compact``.
When in doubt, use ``--dry-run --list`` to see what would be deleted.
When using ``--stats``, you will get some statistics about how much data was
deleted - the "Deleted data" deduplicated size there is most interesting as
that is how much your repository will shrink.
Please note that the "All archives" stats refer to the state after deletion.
You can delete multiple archives by specifying a matching shell pattern,
using the ``--glob-archives GLOB`` option (for more info on these patterns,
see :ref:`borg_patterns`).
Always first use ``--dry-run --list`` to see what would be deleted.
"""
)
subparser = subparsers.add_parser(
"delete",
parents=[common_parser],
add_help=False,
description=self.do_delete.__doc__,
epilog=delete_epilog,
formatter_class=argparse.RawDescriptionHelpFormatter,
help="delete archive",
)
subparser.set_defaults(func=self.do_delete)
subparser.add_argument("-n", "--dry-run", dest="dry_run", action="store_true", help="do not change repository")
subparser.add_argument(
"--list", dest="output_list", action="store_true", help="output verbose list of archives"
)
subparser.add_argument(
"--consider-checkpoints",
action="store_true",
dest="consider_checkpoints",
help="consider checkpoint archives for deletion (default: not considered).",
)
subparser.add_argument(
"-s", "--stats", dest="stats", action="store_true", help="print statistics for the deleted archive"
)
subparser.add_argument(
"--cache-only",
dest="cache_only",
action="store_true",
help="delete only the local cache for the given repository",
)
subparser.add_argument(
"--force",
dest="forced",
action="count",
default=0,
help="force deletion of corrupted archives, " "use ``--force --force`` in case ``--force`` does not work.",
)
subparser.add_argument(
"--keep-security-info",
dest="keep_security_info",
action="store_true",
help="keep the local security info when deleting a repository",
)
subparser.add_argument(
"--save-space", dest="save_space", action="store_true", help="work slower, but using less space"
)
define_archive_filters_group(subparser)