import argparse from ._common import with_repository from ..cache import Cache, SecurityManager from ..constants import * # NOQA from ..helpers import EXIT_ERROR from ..helpers import format_archive from ..helpers import bin_to_hex from ..helpers import yes from ..manifest import Manifest, NoManifestError from ..logger import create_logger logger = create_logger() class RDeleteMixIn: @with_repository(exclusive=True, manifest=False) def do_rdelete(self, args, repository): """Delete a repository""" self.output_list = args.output_list dry_run = args.dry_run keep_security_info = args.keep_security_info if not args.cache_only: if args.forced == 0: # without --force, we let the user see the archives list and confirm. id = bin_to_hex(repository.id) location = repository._location.canonical_path() msg = [] try: manifest = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) n_archives = len(manifest.archives) msg.append( f"You requested to completely DELETE the following repository " f"*including* {n_archives} archives it contains:" ) except NoManifestError: n_archives = None msg.append( "You requested to completely DELETE the following repository " "*including* all archives it may contain:" ) msg.append(DASHES) msg.append(f"Repository ID: {id}") msg.append(f"Location: {location}") if self.output_list: msg.append("") msg.append("Archives:") if n_archives is not None: if n_archives > 0: for archive_info in manifest.archives.list(sort_by=["ts"]): msg.append(format_archive(archive_info)) else: msg.append("This repository seems not to have any archives.") else: msg.append( "This repository seems to have no manifest, so we can't " "tell anything about its contents." ) msg.append(DASHES) msg.append("Type 'YES' if you understand this and want to continue: ") msg = "\n".join(msg) if not yes( msg, false_msg="Aborting.", invalid_msg="Invalid answer, aborting.", truish=("YES",), retry=False, env_var_override="BORG_DELETE_I_KNOW_WHAT_I_AM_DOING", ): self.exit_code = EXIT_ERROR return self.exit_code if not dry_run: repository.destroy() logger.info("Repository deleted.") if not keep_security_info: SecurityManager.destroy(repository) else: logger.info("Would delete repository.") logger.info("Would %s security info." % ("keep" if keep_security_info else "delete")) if not dry_run: Cache.destroy(repository) logger.info("Cache deleted.") else: logger.info("Would delete cache.") return self.exit_code def build_parser_rdelete(self, subparsers, common_parser, mid_common_parser): from ._common import process_epilog rdelete_epilog = process_epilog( """ This command deletes the complete repository. When you delete a complete repository, the security info and local cache for it (if any) are also deleted. Alternatively, you can delete just the local cache with the ``--cache-only`` option, or keep the security info with the ``--keep-security-info`` option. Always first use ``--dry-run --list`` to see what would be deleted. """ ) subparser = subparsers.add_parser( "rdelete", parents=[common_parser], add_help=False, description=self.do_rdelete.__doc__, epilog=rdelete_epilog, formatter_class=argparse.RawDescriptionHelpFormatter, help="delete repository", ) subparser.set_defaults(func=self.do_rdelete) 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( "--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( "--cache-only", dest="cache_only", action="store_true", help="delete only the local cache for the given repository", ) subparser.add_argument( "--keep-security-info", dest="keep_security_info", action="store_true", help="keep the local security info when deleting a repository", )