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:
parent
cd834311eb
commit
80ec3e7d97
8 changed files with 25 additions and 85 deletions
4
NEWS
4
NEWS
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -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(
|
||||||
|
|
|
@ -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'])
|
||||||
|
|
||||||
|
|
|
@ -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 == '[]'
|
||||||
|
|
Loading…
Reference in a new issue