mirror of
https://github.com/borgbackup/borg.git
synced 2024-12-26 01:37:20 +00:00
Merge pull request #1739 from ThomasWaldmann/borg-check-refactor
borg check --first / --last / --sort / --prefix, fixes #1663
This commit is contained in:
commit
1a272ddd48
3 changed files with 25 additions and 25 deletions
|
@ -978,19 +978,19 @@ def __init__(self):
|
|||
self.error_found = False
|
||||
self.possibly_superseded = set()
|
||||
|
||||
def check(self, repository, repair=False, archive=None, last=None, prefix=None, verify_data=False,
|
||||
save_space=False):
|
||||
def check(self, repository, repair=False, archive=None, first=0, last=0, sort_by='', prefix='',
|
||||
verify_data=False, save_space=False):
|
||||
"""Perform a set of checks on 'repository'
|
||||
|
||||
:param repair: enable repair mode, write updated or corrected data into repository
|
||||
:param archive: only check this archive
|
||||
:param last: only check this number of recent archives
|
||||
:param first/last/sort_by: only check this number of first/last archives ordered by sort_by
|
||||
:param prefix: only check archives with this prefix
|
||||
:param verify_data: integrity verification of data referenced by archives
|
||||
:param save_space: Repository.commit(save_space)
|
||||
"""
|
||||
logger.info('Starting archive consistency check...')
|
||||
self.check_all = archive is None and last is None and prefix is None
|
||||
self.check_all = archive is None and not any((first, last, prefix))
|
||||
self.repair = repair
|
||||
self.repository = repository
|
||||
self.init_chunks()
|
||||
|
@ -1003,7 +1003,7 @@ def check(self, repository, repair=False, archive=None, last=None, prefix=None,
|
|||
self.manifest = self.rebuild_manifest()
|
||||
else:
|
||||
self.manifest, _ = Manifest.load(repository, key=self.key)
|
||||
self.rebuild_refcounts(archive=archive, last=last, prefix=prefix)
|
||||
self.rebuild_refcounts(archive=archive, first=first, last=last, sort_by=sort_by, prefix=prefix)
|
||||
self.orphan_chunks_check()
|
||||
self.finish(save_space=save_space)
|
||||
if self.error_found:
|
||||
|
@ -1160,7 +1160,7 @@ def valid_archive(obj):
|
|||
logger.info('Manifest rebuild complete.')
|
||||
return manifest
|
||||
|
||||
def rebuild_refcounts(self, archive=None, last=None, prefix=None):
|
||||
def rebuild_refcounts(self, archive=None, first=0, last=0, sort_by='', prefix=''):
|
||||
"""Rebuild object reference counts by walking the metadata
|
||||
|
||||
Missing and/or incorrect data is repaired when detected
|
||||
|
@ -1294,12 +1294,11 @@ def valid_item(obj):
|
|||
i += 1
|
||||
|
||||
if archive is None:
|
||||
# we need last N or all archives
|
||||
archive_infos = self.manifest.archives.list(sort_by=['ts'], reverse=True)
|
||||
if prefix is not None:
|
||||
archive_infos = [info for info in archive_infos if info.name.startswith(prefix)]
|
||||
num_archives = len(archive_infos)
|
||||
end = None if last is None else min(num_archives, last)
|
||||
sort_by = sort_by.split(',')
|
||||
if any((first, last, prefix)):
|
||||
archive_infos = self.manifest.archives.list(sort_by=sort_by, prefix=prefix, first=first, last=last)
|
||||
else:
|
||||
archive_infos = self.manifest.archives.list(sort_by=sort_by)
|
||||
else:
|
||||
# we only want one specific archive
|
||||
info = self.manifest.archives.get(archive)
|
||||
|
@ -1308,12 +1307,11 @@ def valid_item(obj):
|
|||
archive_infos = []
|
||||
else:
|
||||
archive_infos = [info]
|
||||
num_archives = 1
|
||||
end = 1
|
||||
num_archives = len(archive_infos)
|
||||
|
||||
with cache_if_remote(self.repository) as repository:
|
||||
for i, info in enumerate(archive_infos[:end]):
|
||||
logger.info('Analyzing archive {} ({}/{})'.format(info.name, num_archives - i, num_archives))
|
||||
for i, info in enumerate(archive_infos):
|
||||
logger.info('Analyzing archive {} ({}/{})'.format(info.name, i + 1, num_archives))
|
||||
archive_id = info.id
|
||||
if archive_id not in self.chunks:
|
||||
logger.error('Archive metadata block is missing!')
|
||||
|
|
|
@ -206,16 +206,16 @@ def do_check(self, args, repository):
|
|||
truish=('YES', ), retry=False,
|
||||
env_var_override='BORG_CHECK_I_KNOW_WHAT_I_AM_DOING'):
|
||||
return EXIT_ERROR
|
||||
if args.repo_only and args.verify_data:
|
||||
self.print_error("--repository-only and --verify-data contradict each other. Please select one.")
|
||||
if args.repo_only and any((args.verify_data, args.first, args.last, args.prefix)):
|
||||
self.print_error("--repository-only contradicts --first, --last, --prefix and --verify-data arguments.")
|
||||
return EXIT_ERROR
|
||||
if not args.archives_only:
|
||||
if not repository.check(repair=args.repair, save_space=args.save_space):
|
||||
return EXIT_WARNING
|
||||
if not args.repo_only and not ArchiveChecker().check(
|
||||
repository, repair=args.repair, archive=args.location.archive,
|
||||
last=args.last, prefix=args.prefix, verify_data=args.verify_data,
|
||||
save_space=args.save_space):
|
||||
first=args.first, last=args.last, sort_by=args.sort_by or 'ts', prefix=args.prefix,
|
||||
verify_data=args.verify_data, save_space=args.save_space):
|
||||
return EXIT_WARNING
|
||||
return EXIT_SUCCESS
|
||||
|
||||
|
@ -1660,14 +1660,10 @@ def build_parser(self, prog=None):
|
|||
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
||||
default=False,
|
||||
help='work slower, but using less space')
|
||||
subparser.add_argument('--last', dest='last',
|
||||
type=int, default=None, metavar='N',
|
||||
help='only check last N archives (Default: all)')
|
||||
subparser.add_argument('-P', '--prefix', dest='prefix', type=PrefixSpec,
|
||||
help='only consider archive names starting with this prefix')
|
||||
subparser.add_argument('-p', '--progress', dest='progress',
|
||||
action='store_true', default=False,
|
||||
help="""show progress display while checking""")
|
||||
self.add_archives_filters_args(subparser)
|
||||
|
||||
change_passphrase_epilog = textwrap.dedent("""
|
||||
The key files used for repository encryption are optionally passphrase
|
||||
|
|
|
@ -2014,6 +2014,12 @@ def test_check_usage(self):
|
|||
self.assert_in('Starting archive consistency check', output)
|
||||
output = self.cmd('check', '-v', '--archives-only', '--prefix=archive2', self.repository_location, exit_code=0)
|
||||
self.assert_not_in('archive1', output)
|
||||
output = self.cmd('check', '-v', '--archives-only', '--first=1', self.repository_location, exit_code=0)
|
||||
self.assert_in('archive1', output)
|
||||
self.assert_not_in('archive2', output)
|
||||
output = self.cmd('check', '-v', '--archives-only', '--last=1', self.repository_location, exit_code=0)
|
||||
self.assert_not_in('archive1', output)
|
||||
self.assert_in('archive2', output)
|
||||
|
||||
def test_missing_file_chunk(self):
|
||||
archive, repository = self.open_archive('archive1')
|
||||
|
|
Loading…
Reference in a new issue