1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2025-01-01 12:45:34 +00:00

Allows delete to be used with archive filters

This commit is contained in:
Frank Sachsenheim 2016-07-24 00:40:15 +02:00
parent 17f2363935
commit f2d4d36cea
2 changed files with 74 additions and 31 deletions

View file

@ -770,11 +770,31 @@ def do_rename(self, args, repository, manifest, key, cache, archive):
@with_repository(exclusive=True, manifest=False)
def do_delete(self, args, repository):
"""Delete an existing repository or archive"""
"""Delete an existing repository or archives"""
if any((args.location.archive, args.first, args.last, args.prefix)):
return self._delete_archives(args, repository)
else:
return self._delete_repository(args, repository)
def _delete_archives(self, args, repository):
"""Delete archives"""
manifest, key = Manifest.load(repository)
if args.location.archive:
manifest, key = Manifest.load(repository)
with Cache(repository, key, manifest, lock_wait=self.lock_wait) as cache:
archive = Archive(repository, key, manifest, args.location.archive, cache=cache)
archive_names = (args.location.archive,)
else:
archive_names = tuple(x.name for x in self._get_filtered_archives(args, manifest))
if not archive_names:
return self.exit_code
stats_logger = logging.getLogger('borg.output.stats')
if args.stats:
log_multi(DASHES, STATS_HEADER, logger=stats_logger)
with Cache(repository, key, manifest, lock_wait=self.lock_wait) as cache:
for i, archive_name in enumerate(archive_names, 1):
logger.info('Deleting {} ({}/{}):'.format(archive_name, i, len(archive_names)))
archive = Archive(repository, key, manifest, archive_name, cache=cache)
stats = Statistics()
archive.delete(stats, progress=args.progress, forced=args.forced)
manifest.write()
@ -782,33 +802,41 @@ def do_delete(self, args, repository):
cache.commit()
logger.info("Archive deleted.")
if args.stats:
log_multi(DASHES,
STATS_HEADER,
stats.summary.format(label='Deleted data:', stats=stats),
str(cache),
DASHES, logger=logging.getLogger('borg.output.stats'))
else:
if not args.cache_only:
msg = []
try:
manifest, key = Manifest.load(repository)
except NoManifestError:
msg.append("You requested to completely DELETE the repository *including* all archives it may contain.")
msg.append("This repository seems to have no manifest, so we can't tell anything about its contents.")
else:
msg.append("You requested to completely DELETE the repository *including* all archives it contains:")
for archive_info in manifest.archives.list(sort_by='ts'):
msg.append(format_archive(archive_info))
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
repository.destroy()
logger.info("Repository deleted.")
Cache.destroy(repository)
logger.info("Cache deleted.")
log_multi(stats.summary.format(label='Deleted data:', stats=stats),
DASHES, logger=stats_logger)
if not args.forced and self.exit_code:
break
if args.stats:
stats_logger.info(str(cache))
return self.exit_code
def _delete_repository(self, args, repository):
"""Delete a repository"""
if not args.cache_only:
msg = []
try:
manifest, key = Manifest.load(repository)
except NoManifestError:
msg.append("You requested to completely DELETE the repository *including* all archives it may "
"contain.")
msg.append("This repository seems to have no manifest, so we can't tell anything about its "
"contents.")
else:
msg.append("You requested to completely DELETE the repository *including* all archives it "
"contains:")
for archive_info in manifest.archives.list(sort_by='ts'):
msg.append(format_archive(archive_info))
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
repository.destroy()
logger.info("Repository deleted.")
Cache.destroy(repository)
logger.info("Cache deleted.")
return self.exit_code
@with_repository()
@ -1969,6 +1997,7 @@ def build_parser(self, prog=None):
subparser.add_argument('location', metavar='TARGET', nargs='?', default='',
type=location_validator(),
help='archive or repository to delete')
self.add_archives_filters_args(subparser)
list_epilog = textwrap.dedent("""
This command lists the contents of a repository or an archive.

View file

@ -59,6 +59,9 @@ def exec_cmd(*args, archiver=None, fork=False, exe=None, **kw):
except subprocess.CalledProcessError as e:
output = e.output
ret = e.returncode
except SystemExit as e: # possibly raised by argparse
output = ''
ret = e.code
return ret, os.fsdecode(output)
else:
stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
@ -987,8 +990,13 @@ def test_delete(self):
self.cmd('init', self.repository_location)
self.cmd('create', self.repository_location + '::test', 'input')
self.cmd('create', self.repository_location + '::test.2', 'input')
self.cmd('create', self.repository_location + '::test.3', 'input')
self.cmd('create', self.repository_location + '::another_test.1', 'input')
self.cmd('create', self.repository_location + '::another_test.2', 'input')
self.cmd('extract', '--dry-run', self.repository_location + '::test')
self.cmd('extract', '--dry-run', self.repository_location + '::test.2')
self.cmd('delete', '--prefix', 'another_', self.repository_location)
self.cmd('delete', '--last', '1', self.repository_location)
self.cmd('delete', self.repository_location + '::test')
self.cmd('extract', '--dry-run', self.repository_location + '::test.2')
output = self.cmd('delete', '--stats', self.repository_location + '::test.2')
@ -1811,6 +1819,12 @@ def test_recreate_list_output(self):
self.assert_not_in("input/file1", output)
self.assert_not_in("x input/file5", output)
def test_bad_filters(self):
self.cmd('init', self.repository_location)
self.cmd('create', self.repository_location + '::test', 'input')
self.cmd('delete', '--first', '1', '--last', '1', self.repository_location, fork=True, exit_code=2)
def test_key_export_keyfile(self):
export_file = self.output_path + '/exported'
self.cmd('init', self.repository_location, '--encryption', 'keyfile')