Deprecate "borgmatic list --successful" flag, as listing only non-checkpoint (successful) archives is now the default in newer versions of Borg.

This commit is contained in:
Dan Helfman 2022-06-02 20:35:39 -07:00
parent cd834311eb
commit 80ec3e7d97
8 changed files with 25 additions and 85 deletions

4
NEWS
View file

@ -1,3 +1,7 @@
1.6.3.dev0
* Deprecate "borgmatic list --successful" flag, as listing only non-checkpoint (successful)
archives is now the default in newer versions of Borg.
1.6.2 1.6.2
* #523: Reduce the default consistency check frequency and support configuring the frequency * #523: Reduce the default consistency check frequency and support configuring the frequency
independently for each check. Also add "borgmatic check --force" flag to ignore configured independently for each check. Also add "borgmatic check --force" flag to ignore configured

View file

@ -6,17 +6,11 @@ from borgmatic.execute import execute_command
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# A hack to convince Borg to exclude archives ending in ".checkpoint". This assumes that a
# non-checkpoint archive name ends in a digit (e.g. from a timestamp).
BORG_EXCLUDE_CHECKPOINTS_GLOB = '*[0123456789]'
def resolve_archive_name(repository, archive, storage_config, local_path='borg', remote_path=None): def resolve_archive_name(repository, archive, storage_config, local_path='borg', remote_path=None):
''' '''
Given a local or remote repository path, an archive name, a storage config dict, a local Borg Given a local or remote repository path, an archive name, a storage config dict, a local Borg
path, and a remote Borg path, simply return the archive name. But if the archive name is path, and a remote Borg path, simply return the archive name. But if the archive name is
"latest", then instead introspect the repository for the latest successful (non-checkpoint) "latest", then instead introspect the repository for the latest archive and return its name.
archive, and return its name.
Raise ValueError if "latest" is given but there are no archives in the repository. Raise ValueError if "latest" is given but there are no archives in the repository.
''' '''
@ -31,7 +25,6 @@ def resolve_archive_name(repository, archive, storage_config, local_path='borg',
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ()) + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
+ make_flags('remote-path', remote_path) + make_flags('remote-path', remote_path)
+ make_flags('lock-wait', lock_wait) + make_flags('lock-wait', lock_wait)
+ make_flags('glob-archives', BORG_EXCLUDE_CHECKPOINTS_GLOB)
+ make_flags('last', 1) + make_flags('last', 1)
+ ('--short', repository) + ('--short', repository)
) )
@ -54,8 +47,6 @@ def list_archives(repository, storage_config, list_arguments, local_path='borg',
if an archive name is given, listing the files in that archive. if an archive name is given, listing the files in that archive.
''' '''
lock_wait = storage_config.get('lock_wait', None) lock_wait = storage_config.get('lock_wait', None)
if list_arguments.successful:
list_arguments.glob_archives = BORG_EXCLUDE_CHECKPOINTS_GLOB
full_command = ( full_command = (
(local_path, 'list') (local_path, 'list')
@ -71,9 +62,7 @@ def list_archives(repository, storage_config, list_arguments, local_path='borg',
) )
+ make_flags('remote-path', remote_path) + make_flags('remote-path', remote_path)
+ make_flags('lock-wait', lock_wait) + make_flags('lock-wait', lock_wait)
+ make_flags_from_arguments( + make_flags_from_arguments(list_arguments, excludes=('repository', 'archive', 'paths'))
list_arguments, excludes=('repository', 'archive', 'paths', 'successful')
)
+ ( + (
'::'.join((repository, list_arguments.archive)) '::'.join((repository, list_arguments.archive))
if list_arguments.archive if list_arguments.archive

View file

@ -573,7 +573,7 @@ def make_parsers():
'--successful', '--successful',
default=False, default=False,
action='store_true', action='store_true',
help='Only list archive names of successful (non-checkpoint) backups', help='Deprecated in favor of listing successful (non-checkpoint) backups by default in newer versions of Borg',
) )
list_group.add_argument( list_group.add_argument(
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys' '--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
@ -681,9 +681,6 @@ def parse_arguments(*unparsed_arguments):
if 'init' in arguments and arguments['global'].dry_run: if 'init' in arguments and arguments['global'].dry_run:
raise ValueError('The init action cannot be used with the --dry-run option') raise ValueError('The init action cannot be used with the --dry-run option')
if 'list' in arguments and arguments['list'].glob_archives and arguments['list'].successful:
raise ValueError('The --glob-archives and --successful options cannot be used together')
if ( if (
'list' in arguments 'list' in arguments
and 'info' in arguments and 'info' in arguments

View file

@ -116,7 +116,7 @@ Omit the `--archive` flag to mount all archives (lazy-loaded):
borgmatic mount --mount-point /mnt borgmatic mount --mount-point /mnt
``` ```
Or use the "latest" value for the archive to mount the latest successful archive: Or use the "latest" value for the archive to mount the latest archive:
```bash ```bash
borgmatic mount --archive latest --mount-point /mnt borgmatic mount --archive latest --mount-point /mnt

View file

@ -286,35 +286,12 @@ output only shows up at the console, and not in syslog.
* [Borgmacator GNOME AppIndicator](https://github.com/N-Coder/borgmacator/) * [Borgmacator GNOME AppIndicator](https://github.com/N-Coder/borgmacator/)
### Successful backups
`borgmatic list` includes support for a `--successful` flag that only lists
successful (non-checkpoint) backups. This flag works via a basic heuristic: It
assumes that non-checkpoint archive names end with a digit (e.g. from a
timestamp), while checkpoint archive names do not. This means that if you're
using custom archive names that do not end in a digit, the `--successful` flag
will not work as expected.
Combined with a built-in Borg flag like `--last`, you can list the last
successful backup for use in your monitoring scripts. Here's an example
combined with `--json`:
```bash
borgmatic list --successful --last 1 --json
```
Note that this particular combination will only work if you've got a single
backup "series" in your repository. If you're instead backing up, say, from
multiple different hosts into a single repository, then you'll need to get
fancier with your archive listing. See `borg list --help` for more flags.
### Latest backups ### Latest backups
All borgmatic actions that accept an "--archive" flag allow you to specify an All borgmatic actions that accept an "--archive" flag allow you to specify an
archive name of "latest". This lets you get the latest successful archive archive name of "latest". This lets you get the latest archive without having
without having to first run "borgmatic list" manually, which can be handy in to first run "borgmatic list" manually, which can be handy in automated
automated scripts. Here's an example: scripts. Here's an example:
```bash ```bash
borgmatic info --archive latest borgmatic info --archive latest

View file

@ -1,6 +1,6 @@
from setuptools import find_packages, setup from setuptools import find_packages, setup
VERSION = '1.6.2' VERSION = '1.6.3.dev0'
setup( setup(

View file

@ -296,15 +296,6 @@ def test_parse_arguments_disallows_init_and_dry_run():
) )
def test_parse_arguments_disallows_glob_archives_with_successful():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
with pytest.raises(ValueError):
module.parse_arguments(
'--config', 'myconfig', 'list', '--glob-archives', '*glob*', '--successful'
)
def test_parse_arguments_disallows_repository_unless_action_consumes_it(): def test_parse_arguments_disallows_repository_unless_action_consumes_it():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default']) flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

View file

@ -8,8 +8,6 @@ from borgmatic.borg import list as module
from ..test_verbosity import insert_logging_mock from ..test_verbosity import insert_logging_mock
BORG_LIST_LATEST_ARGUMENTS = ( BORG_LIST_LATEST_ARGUMENTS = (
'--glob-archives',
module.BORG_EXCLUDE_CHECKPOINTS_GLOB,
'--last', '--last',
'1', '1',
'--short', '--short',
@ -116,7 +114,7 @@ def test_list_archives_calls_borg_with_parameters():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=False, successful=False), list_arguments=flexmock(archive=None, paths=None, json=False),
) )
@ -129,7 +127,7 @@ def test_list_archives_with_log_info_calls_borg_with_info_parameter():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=False, successful=False), list_arguments=flexmock(archive=None, paths=None, json=False),
) )
@ -142,7 +140,7 @@ def test_list_archives_with_log_info_and_json_suppresses_most_borg_output():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=True, successful=False), list_arguments=flexmock(archive=None, paths=None, json=True),
) )
@ -157,7 +155,7 @@ def test_list_archives_with_log_debug_calls_borg_with_debug_parameter():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=False, successful=False), list_arguments=flexmock(archive=None, paths=None, json=False),
) )
@ -170,7 +168,7 @@ def test_list_archives_with_log_debug_and_json_suppresses_most_borg_output():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=True, successful=False), list_arguments=flexmock(archive=None, paths=None, json=True),
) )
@ -185,7 +183,7 @@ def test_list_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config=storage_config, storage_config=storage_config,
list_arguments=flexmock(archive=None, paths=None, json=False, successful=False), list_arguments=flexmock(archive=None, paths=None, json=False),
) )
@ -198,7 +196,7 @@ def test_list_archives_with_archive_calls_borg_with_archive_parameter():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config=storage_config, storage_config=storage_config,
list_arguments=flexmock(archive='archive', paths=None, json=False, successful=False), list_arguments=flexmock(archive='archive', paths=None, json=False),
) )
@ -213,7 +211,7 @@ def test_list_archives_with_path_calls_borg_with_path_parameter():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config=storage_config, storage_config=storage_config,
list_arguments=flexmock(archive='archive', paths=['var/lib'], json=False, successful=False), list_arguments=flexmock(archive='archive', paths=['var/lib'], json=False),
) )
@ -225,7 +223,7 @@ def test_list_archives_with_local_path_calls_borg_via_local_path():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=False, successful=False), list_arguments=flexmock(archive=None, paths=None, json=False),
local_path='borg1', local_path='borg1',
) )
@ -240,7 +238,7 @@ def test_list_archives_with_remote_path_calls_borg_with_remote_path_parameters()
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=False, successful=False), list_arguments=flexmock(archive=None, paths=None, json=False),
remote_path='borg1', remote_path='borg1',
) )
@ -255,7 +253,7 @@ def test_list_archives_with_short_calls_borg_with_short_parameter():
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=False, successful=False, short=True), list_arguments=flexmock(archive=None, paths=None, json=False, short=True),
) )
@ -283,23 +281,7 @@ def test_list_archives_passes_through_arguments_to_borg(argument_name):
module.list_archives( module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock( list_arguments=flexmock(archive=None, paths=None, json=False, **{argument_name: 'value'}),
archive=None, paths=None, json=False, successful=False, **{argument_name: 'value'}
),
)
def test_list_archives_with_successful_calls_borg_to_exclude_checkpoints():
flexmock(module).should_receive('execute_command').with_args(
('borg', 'list', '--glob-archives', module.BORG_EXCLUDE_CHECKPOINTS_GLOB, 'repo'),
output_log_level=logging.WARNING,
borg_local_path='borg',
).and_return('[]')
module.list_archives(
repository='repo',
storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=False, successful=True),
) )
@ -311,7 +293,7 @@ def test_list_archives_with_json_calls_borg_with_json_parameter():
json_output = module.list_archives( json_output = module.list_archives(
repository='repo', repository='repo',
storage_config={}, storage_config={},
list_arguments=flexmock(archive=None, paths=None, json=True, successful=False), list_arguments=flexmock(archive=None, paths=None, json=True),
) )
assert json_output == '[]' assert json_output == '[]'