diff --git a/src/borg/archive.py b/src/borg/archive.py index bfc583612..e831be225 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -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!') diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 40024261e..bc0f5ae57 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -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 diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index a2c44280d..ecaa6be6d 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -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')