From 6888d5dcb2293aceaa9494b76ae4771ded4bf2ca Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Sat, 2 Jul 2022 20:52:41 +0200 Subject: [PATCH] remove -P (aka --prefix) option, fixes #6806 -a (aka --glob-archives) can be used for same purpose and is more powerful. --- docs/faq.rst | 5 ++--- docs/quickstart.rst | 4 ++-- docs/usage/delete.rst | 2 +- docs/usage/prune.rst | 6 +++--- src/borg/archiver.py | 25 ++++++++----------------- src/borg/helpers/manifest.py | 4 +--- src/borg/testsuite/archiver.py | 18 +++++++++--------- 7 files changed, 26 insertions(+), 38 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 9566fdec7..abf8fed23 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -402,11 +402,10 @@ different prefixes. For example, you could have a script that does:: Then you would have two different prune calls with different policies:: - borg prune --verbose --list -d 30 --prefix main- - borg prune --verbose --list -d 7 --prefix logs- + borg prune --verbose --list -d 30 -a 'main-*' + borg prune --verbose --list -d 7 -a 'logs-*' This will keep 7 days of logs and 30 days of everything else. -Borg also supports the ``--glob-archives`` parameter. How do I remove files from an existing backup? ---------------------------------------------- diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 5c33d3857..af14815d9 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -195,13 +195,13 @@ backed up and that the ``prune`` command is keeping and deleting the correct bac info "Pruning repository" # Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly - # archives of THIS machine. The '{hostname}-' prefix is very important to + # archives of THIS machine. The '{hostname}-*' globbing is very important to # limit prune's operation to this machine's archives and not apply to # other machines' archives also: borg prune \ --list \ - --prefix '{hostname}-' \ + --glob-archives '{hostname}-*' \ --show-rc \ --keep-daily 7 \ --keep-weekly 4 \ diff --git a/docs/usage/delete.rst b/docs/usage/delete.rst index d3f44a066..56fc6e4e8 100644 --- a/docs/usage/delete.rst +++ b/docs/usage/delete.rst @@ -10,7 +10,7 @@ Examples $ borg compact # delete all archives whose names begin with the machine's hostname followed by "-" - $ borg delete --prefix '{hostname}-' + $ borg delete -a '{hostname}-*' # delete all archives whose names contain "-2012-" $ borg delete -a '*-2012-*' diff --git a/docs/usage/prune.rst b/docs/usage/prune.rst index 44880adb8..602385de5 100644 --- a/docs/usage/prune.rst +++ b/docs/usage/prune.rst @@ -7,8 +7,8 @@ Be careful, prune is a potentially dangerous command, it will remove backup archives. The default of prune is to apply to **all archives in the repository** unless -you restrict its operation to a subset of the archives using ``--prefix``. -When using ``--prefix``, be careful to choose a good prefix - e.g. do not use a +you restrict its operation to a subset of the archives using ``-a`` / ``--glob-archives``. +When using ``-a``, be careful to choose a good pattern - e.g. do not use a prefix "foo" if you do not also want to match "foobar". It is strongly recommended to always run ``prune -v --list --dry-run ...`` @@ -22,7 +22,7 @@ first so you will see what it would do without it actually doing anything. # Same as above but only apply to archive names starting with the hostname # of the machine followed by a "-" character: - $ borg prune -v --list --keep-daily=7 --keep-weekly=4 --prefix='{hostname}-' + $ borg prune -v --list --keep-daily=7 --keep-weekly=4 -a '{hostname}-*' # actually free disk space: $ borg compact diff --git a/src/borg/archiver.py b/src/borg/archiver.py index d61ead194..2777303c1 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -459,8 +459,8 @@ class Archiver: env_var_override='BORG_CHECK_I_KNOW_WHAT_I_AM_DOING'): return EXIT_ERROR if args.repo_only and any( - (args.verify_data, args.first, args.last, args.prefix is not None, args.glob_archives)): - self.print_error("--repository-only contradicts --first, --last, --prefix, --glob-archives " + (args.verify_data, args.first, args.last, args.glob_archives)): + self.print_error("--repository-only contradicts --first, --last, -a / --glob-archives " " and --verify-data arguments.") return EXIT_ERROR if args.repair and args.max_duration: @@ -476,8 +476,6 @@ class Archiver: if not args.archives_only: if not repository.check(repair=args.repair, save_space=args.save_space, max_duration=args.max_duration): return EXIT_WARNING - if args.prefix is not None: - args.glob_archives = args.prefix + '*' if not args.repo_only and not ArchiveChecker().check(repository, repair=args.repair, first=args.first, last=args.last, sort_by=args.sort_by or 'ts', glob=args.glob_archives, verify_data=args.verify_data, save_space=args.save_space): @@ -1757,8 +1755,6 @@ class Archiver: '"keep-secondly", "keep-minutely", "keep-hourly", "keep-daily", ' '"keep-weekly", "keep-monthly" or "keep-yearly" settings must be specified.') return self.exit_code - if args.prefix is not None: - args.glob_archives = args.prefix + '*' checkpoint_re = r'\.checkpoint(\.\d+)?' archives_checkpoints = manifest.archives.list(glob=args.glob_archives, consider_checkpoints=True, @@ -2652,7 +2648,7 @@ class Archiver: This allows you to share the same patterns between multiple repositories without needing to specify them on the command line.\n\n''') helptext['placeholders'] = textwrap.dedent(''' - Repository URLs, ``--name``, ``--prefix``, ``--glob-archives``, ``--comment`` + Repository URLs, ``--name``, ``-a`` / ``--glob-archives``, ``--comment`` and ``--remote-path`` values support these placeholders: {hostname} @@ -2698,7 +2694,7 @@ class Archiver: borg create /path/to/repo::{hostname}-{user}-{utcnow} ... borg create /path/to/repo::{hostname}-{now:%Y-%m-%d_%H:%M:%S} ... - borg prune --prefix '{hostname}-' ... + borg prune -a '{hostname}-*' ... .. note:: systemd uses a difficult, non-standard syntax for command lines in unit files (refer to @@ -3091,13 +3087,10 @@ class Archiver: filters_group = subparser.add_argument_group('Archive filters', 'Archive filters can be applied to repository targets.') group = filters_group.add_mutually_exclusive_group() - group.add_argument('-P', '--prefix', metavar='PREFIX', dest='prefix', type=PrefixSpec, action=Highlander, - help='only consider archive names starting with this prefix.') group.add_argument('-a', '--glob-archives', metavar='GLOB', dest='glob_archives', type=GlobSpec, action=Highlander, help='only consider archive names matching the glob. ' - 'sh: rules apply, see "borg help patterns". ' - '``--prefix`` and ``--glob-archives`` are mutually exclusive.') + 'sh: rules apply, see "borg help patterns".') if sort_by: sort_by_default = 'timestamp' @@ -3971,11 +3964,9 @@ class Archiver: 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 their common prefix, if they - have one, using the ``--prefix PREFIX`` option. You can also specify a shell - pattern to match multiple archives using the ``--glob-archives GLOB`` option - (for more info on these patterns, see :ref:`borg_patterns`). Note that these - two options are mutually exclusive. + 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. """) diff --git a/src/borg/helpers/manifest.py b/src/borg/helpers/manifest.py index 786eb27bb..f2eeaad68 100644 --- a/src/borg/helpers/manifest.py +++ b/src/borg/helpers/manifest.py @@ -106,9 +106,7 @@ class Archives(abc.MutableMapping): name = getattr(args, 'name', None) consider_checkpoints = getattr(args, 'consider_checkpoints', None) if name is not None: - raise Error('Giving a specific name is incompatible with options --first, --last, --prefix, and --glob-archives, and --consider-checkpoints.') - if args.prefix is not None: - args.glob_archives = args.prefix + '*' + raise Error('Giving a specific name is incompatible with options --first, --last, -a / --glob-archives, and --consider-checkpoints.') return self.list(sort_by=args.sort_by.split(','), consider_checkpoints=consider_checkpoints, glob=args.glob_archives, first=args.first, last=args.last) def set_raw_dict(self, d): diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 6fda62be7..d568d2a9c 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -1600,7 +1600,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'another_test.2', 'input') self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') - self.cmd(f'--repo={self.repository_location}', 'delete', '--prefix', 'another_') + self.cmd(f'--repo={self.repository_location}', 'delete', '--glob-archives', 'another_*') self.cmd(f'--repo={self.repository_location}', 'delete', '--last', '1') self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test') self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') @@ -2259,7 +2259,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'foo-2015-08-12-20:00', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'bar-2015-08-12-10:00', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'bar-2015-08-12-20:00', src_dir) - output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--prefix=foo-') + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--glob-archives=foo-*') assert re.search(r'Keeping archive \(rule: daily #1\):\s+foo-2015-08-12-20:00', output) assert re.search(r'Would prune:\s+foo-2015-08-12-10:00', output) output = self.cmd(f'--repo={self.repository_location}', 'rlist') @@ -2267,7 +2267,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in('foo-2015-08-12-20:00', output) self.assert_in('bar-2015-08-12-10:00', output) self.assert_in('bar-2015-08-12-20:00', output) - self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1', '--prefix=foo-') + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1', '--glob-archives=foo-*') output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_not_in('foo-2015-08-12-10:00', output) self.assert_in('foo-2015-08-12-20:00', output) @@ -2300,7 +2300,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'something-else-than-test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'test-2', src_dir) - output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--prefix=test-') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--glob-archives=test-*') self.assert_in('test-1', output) self.assert_in('test-2', output) self.assert_not_in('something-else', output) @@ -2664,13 +2664,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert sorted(os.listdir(os.path.join(mountpoint))) == ['arch11', 'arch12'] with self.fuse_mount(self.repository_location, mountpoint, '--last=2', '--sort=name'): assert sorted(os.listdir(os.path.join(mountpoint))) == ['arch21', 'arch22'] - with self.fuse_mount(self.repository_location, mountpoint, '--prefix=arch1'): + with self.fuse_mount(self.repository_location, mountpoint, '--glob-archives=arch1*'): assert sorted(os.listdir(os.path.join(mountpoint))) == ['arch11', 'arch12'] - with self.fuse_mount(self.repository_location, mountpoint, '--prefix=arch2'): + with self.fuse_mount(self.repository_location, mountpoint, '--glob-archives=arch2*'): assert sorted(os.listdir(os.path.join(mountpoint))) == ['arch21', 'arch22'] - with self.fuse_mount(self.repository_location, mountpoint, '--prefix=arch'): + with self.fuse_mount(self.repository_location, mountpoint, '--glob-archives=arch*'): assert sorted(os.listdir(os.path.join(mountpoint))) == ['arch11', 'arch12', 'arch21', 'arch22'] - with self.fuse_mount(self.repository_location, mountpoint, '--prefix=nope'): + with self.fuse_mount(self.repository_location, mountpoint, '--glob-archives=nope'): assert sorted(os.listdir(os.path.join(mountpoint))) == [] @unittest.skipUnless(llfuse, 'llfuse not installed') @@ -3559,7 +3559,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', exit_code=0) self.assert_not_in('Starting repository check', output) self.assert_in('Starting archive consistency check', output) - output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', '--prefix=archive2', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', '--glob-archives=archive2', exit_code=0) self.assert_not_in('archive1', output) output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', '--first=1', exit_code=0) self.assert_in('archive1', output)