Run any command-line actions in the order specified instead of using a fixed ordering (#304).
This commit is contained in:
parent
d88bcc8be9
commit
9db31bd1e9
6 changed files with 222 additions and 158 deletions
3
NEWS
3
NEWS
|
@ -1,6 +1,7 @@
|
|||
1.7.9.dev0
|
||||
* #295: Add a SQLite database dump/restore hook.
|
||||
* #628: Add Healthchecks "log" state to send borgmatic logs to Healthchecks without signalling
|
||||
* #304: Run any command-line actions in the order specified instead of using a fixed ordering.
|
||||
* #628: Add a Healthchecks "log" state to send borgmatic logs to Healthchecks without signalling
|
||||
success or failure.
|
||||
|
||||
1.7.8
|
||||
|
|
|
@ -46,11 +46,12 @@ def parse_subparser_arguments(unparsed_arguments, subparsers):
|
|||
if 'borg' in unparsed_arguments:
|
||||
subparsers = {'borg': subparsers['borg']}
|
||||
|
||||
for subparser_name, subparser in subparsers.items():
|
||||
if subparser_name not in remaining_arguments:
|
||||
continue
|
||||
for argument in remaining_arguments:
|
||||
canonical_name = alias_to_subparser_name.get(argument, argument)
|
||||
subparser = subparsers.get(canonical_name)
|
||||
|
||||
canonical_name = alias_to_subparser_name.get(subparser_name, subparser_name)
|
||||
if not subparser:
|
||||
continue
|
||||
|
||||
# If a parsed value happens to be the same as the name of a subparser, remove it from the
|
||||
# remaining arguments. This prevents, for instance, "check --only extract" from triggering
|
||||
|
|
|
@ -281,27 +281,28 @@ def run_actions(
|
|||
**hook_context,
|
||||
)
|
||||
|
||||
if 'rcreate' in arguments:
|
||||
for (action_name, action_arguments) in arguments.items():
|
||||
if action_name == 'rcreate':
|
||||
borgmatic.actions.rcreate.run_rcreate(
|
||||
repository,
|
||||
storage,
|
||||
local_borg_version,
|
||||
arguments['rcreate'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'transfer' in arguments:
|
||||
elif action_name == 'transfer':
|
||||
borgmatic.actions.transfer.run_transfer(
|
||||
repository,
|
||||
storage,
|
||||
local_borg_version,
|
||||
arguments['transfer'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'prune' in arguments:
|
||||
elif action_name == 'prune':
|
||||
borgmatic.actions.prune.run_prune(
|
||||
config_filename,
|
||||
repository,
|
||||
|
@ -310,13 +311,13 @@ def run_actions(
|
|||
hooks,
|
||||
hook_context,
|
||||
local_borg_version,
|
||||
arguments['prune'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
dry_run_label,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'compact' in arguments:
|
||||
elif action_name == 'compact':
|
||||
borgmatic.actions.compact.run_compact(
|
||||
config_filename,
|
||||
repository,
|
||||
|
@ -325,13 +326,13 @@ def run_actions(
|
|||
hooks,
|
||||
hook_context,
|
||||
local_borg_version,
|
||||
arguments['compact'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
dry_run_label,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'create' in arguments:
|
||||
elif action_name == 'create':
|
||||
yield from borgmatic.actions.create.run_create(
|
||||
config_filename,
|
||||
repository,
|
||||
|
@ -340,13 +341,14 @@ def run_actions(
|
|||
hooks,
|
||||
hook_context,
|
||||
local_borg_version,
|
||||
arguments['create'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
dry_run_label,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'check' in arguments and checks.repository_enabled_for_checks(repository, consistency):
|
||||
elif action_name == 'check':
|
||||
if checks.repository_enabled_for_checks(repository, consistency):
|
||||
borgmatic.actions.check.run_check(
|
||||
config_filename,
|
||||
repository,
|
||||
|
@ -356,12 +358,12 @@ def run_actions(
|
|||
hooks,
|
||||
hook_context,
|
||||
local_borg_version,
|
||||
arguments['check'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'extract' in arguments:
|
||||
elif action_name == 'extract':
|
||||
borgmatic.actions.extract.run_extract(
|
||||
config_filename,
|
||||
repository,
|
||||
|
@ -370,54 +372,59 @@ def run_actions(
|
|||
hooks,
|
||||
hook_context,
|
||||
local_borg_version,
|
||||
arguments['extract'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'export-tar' in arguments:
|
||||
elif action_name == 'export-tar':
|
||||
borgmatic.actions.export_tar.run_export_tar(
|
||||
repository,
|
||||
storage,
|
||||
local_borg_version,
|
||||
arguments['export-tar'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'mount' in arguments:
|
||||
elif action_name == 'mount':
|
||||
borgmatic.actions.mount.run_mount(
|
||||
repository, storage, local_borg_version, arguments['mount'], local_path, remote_path,
|
||||
repository,
|
||||
storage,
|
||||
local_borg_version,
|
||||
arguments['mount'],
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'restore' in arguments:
|
||||
elif action_name == 'restore':
|
||||
borgmatic.actions.restore.run_restore(
|
||||
repository,
|
||||
location,
|
||||
storage,
|
||||
hooks,
|
||||
local_borg_version,
|
||||
arguments['restore'],
|
||||
action_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'rlist' in arguments:
|
||||
elif action_name == 'rlist':
|
||||
yield from borgmatic.actions.rlist.run_rlist(
|
||||
repository, storage, local_borg_version, arguments['rlist'], local_path, remote_path,
|
||||
repository, storage, local_borg_version, action_arguments, local_path, remote_path,
|
||||
)
|
||||
if 'list' in arguments:
|
||||
elif action_name == 'list':
|
||||
yield from borgmatic.actions.list.run_list(
|
||||
repository, storage, local_borg_version, arguments['list'], local_path, remote_path,
|
||||
repository, storage, local_borg_version, action_arguments, local_path, remote_path,
|
||||
)
|
||||
if 'rinfo' in arguments:
|
||||
elif action_name == 'rinfo':
|
||||
yield from borgmatic.actions.rinfo.run_rinfo(
|
||||
repository, storage, local_borg_version, arguments['rinfo'], local_path, remote_path,
|
||||
repository, storage, local_borg_version, action_arguments, local_path, remote_path,
|
||||
)
|
||||
if 'info' in arguments:
|
||||
elif action_name == 'info':
|
||||
yield from borgmatic.actions.info.run_info(
|
||||
repository, storage, local_borg_version, arguments['info'], local_path, remote_path,
|
||||
repository, storage, local_borg_version, action_arguments, local_path, remote_path,
|
||||
)
|
||||
if 'break-lock' in arguments:
|
||||
elif action_name == 'break-lock':
|
||||
borgmatic.actions.break_lock.run_break_lock(
|
||||
repository,
|
||||
storage,
|
||||
|
@ -426,9 +433,9 @@ def run_actions(
|
|||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if 'borg' in arguments:
|
||||
elif action_name == 'borg':
|
||||
borgmatic.actions.borg.run_borg(
|
||||
repository, storage, local_borg_version, arguments['borg'], local_path, remote_path,
|
||||
repository, storage, local_borg_version, action_arguments, local_path, remote_path,
|
||||
)
|
||||
|
||||
command.execute_hook(
|
||||
|
|
|
@ -36,10 +36,16 @@ skipping certain actions while running others. For instance, this skips
|
|||
borgmatic create check
|
||||
```
|
||||
|
||||
Or, you can make backups with `create` on a frequent schedule (e.g. with
|
||||
`borgmatic create` called from one cron job), while only running expensive
|
||||
consistency checks with `check` on a much less frequent basis (e.g. with
|
||||
`borgmatic check` called from a separate cron job).
|
||||
<span class="minilink minilink-addedin">New in version 1.7.9</span> borgmatic
|
||||
now respects your specified command-line action order, running actions in the
|
||||
order you specify. In previous versions, borgmatic ran your specified actions
|
||||
in a fixed ordering regardless of the order they appeared on the command-line.
|
||||
|
||||
But instead of running actions together, another option is to run backups with
|
||||
`create` on a frequent schedule (e.g. with `borgmatic create` called from one
|
||||
cron job), while only running expensive consistency checks with `check` on a
|
||||
much less frequent basis (e.g. with `borgmatic check` called from a separate
|
||||
cron job).
|
||||
|
||||
|
||||
### Consistency check configuration
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import collections
|
||||
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.commands import arguments as module
|
||||
|
@ -70,6 +72,26 @@ def test_parse_subparser_arguments_consumes_multiple_subparser_arguments():
|
|||
assert remaining_arguments == []
|
||||
|
||||
|
||||
def test_parse_subparser_arguments_respects_command_line_action_ordering():
|
||||
other_namespace = flexmock()
|
||||
action_namespace = flexmock(foo=True)
|
||||
subparsers = {
|
||||
'action': flexmock(
|
||||
parse_known_args=lambda arguments: (action_namespace, ['action', '--foo', 'true'])
|
||||
),
|
||||
'other': flexmock(parse_known_args=lambda arguments: (other_namespace, ['other'])),
|
||||
}
|
||||
|
||||
arguments, remaining_arguments = module.parse_subparser_arguments(
|
||||
('other', '--foo', 'true', 'action'), subparsers
|
||||
)
|
||||
|
||||
assert arguments == collections.OrderedDict(
|
||||
[('other', other_namespace), ('action', action_namespace)]
|
||||
)
|
||||
assert remaining_arguments == []
|
||||
|
||||
|
||||
def test_parse_subparser_arguments_applies_default_subparsers():
|
||||
prune_namespace = flexmock()
|
||||
compact_namespace = flexmock()
|
||||
|
|
|
@ -778,6 +778,33 @@ def test_run_actions_runs_borg():
|
|||
)
|
||||
|
||||
|
||||
def test_run_actions_runs_multiple_actions_in_argument_order():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module.command).should_receive('execute_hook')
|
||||
flexmock(borgmatic.actions.borg).should_receive('run_borg').once().ordered()
|
||||
flexmock(borgmatic.actions.restore).should_receive('run_restore').once().ordered()
|
||||
|
||||
tuple(
|
||||
module.run_actions(
|
||||
arguments={
|
||||
'global': flexmock(dry_run=False),
|
||||
'borg': flexmock(),
|
||||
'restore': flexmock(),
|
||||
},
|
||||
config_filename=flexmock(),
|
||||
location={'repositories': []},
|
||||
storage=flexmock(),
|
||||
retention=flexmock(),
|
||||
consistency=flexmock(),
|
||||
hooks={},
|
||||
local_path=flexmock(),
|
||||
remote_path=flexmock(),
|
||||
local_borg_version=flexmock(),
|
||||
repository_path='repo',
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_load_configurations_collects_parsed_configurations_and_logs():
|
||||
configuration = flexmock()
|
||||
other_configuration = flexmock()
|
||||
|
|
Loading…
Reference in a new issue