pass all tests with wittens recommendation
This commit is contained in:
parent
6a1d1a2e59
commit
4b024daae0
3 changed files with 62 additions and 30 deletions
|
@ -1,18 +1,20 @@
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import json
|
|
||||||
|
|
||||||
import borgmatic.borg.extract
|
import borgmatic.borg.extract
|
||||||
import borgmatic.borg.rlist
|
import borgmatic.borg.rlist
|
||||||
import borgmatic.config.validate
|
import borgmatic.config.validate
|
||||||
import borgmatic.hooks.command
|
import borgmatic.hooks.command
|
||||||
|
|
||||||
from borgmatic.borg.state import DEFAULT_BORGMATIC_SOURCE_DIRECTORY
|
from borgmatic.borg.state import DEFAULT_BORGMATIC_SOURCE_DIRECTORY
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_config_paths(bootstrap_arguments, global_arguments, local_borg_version):
|
def get_config_paths(bootstrap_arguments, global_arguments, local_borg_version):
|
||||||
borgmatic_source_directory = bootstrap_arguments.borgmatic_source_directory or DEFAULT_BORGMATIC_SOURCE_DIRECTORY
|
borgmatic_source_directory = (
|
||||||
|
bootstrap_arguments.borgmatic_source_directory or DEFAULT_BORGMATIC_SOURCE_DIRECTORY
|
||||||
|
)
|
||||||
borgmatic_manifest_path = os.path.expanduser(
|
borgmatic_manifest_path = os.path.expanduser(
|
||||||
os.path.join(borgmatic_source_directory, 'bootstrap', 'manifest.json')
|
os.path.join(borgmatic_source_directory, 'bootstrap', 'manifest.json')
|
||||||
)
|
)
|
||||||
|
@ -24,7 +26,7 @@ def get_config_paths(bootstrap_arguments, global_arguments, local_borg_version):
|
||||||
bootstrap_arguments.archive,
|
bootstrap_arguments.archive,
|
||||||
{},
|
{},
|
||||||
local_borg_version,
|
local_borg_version,
|
||||||
global_arguments
|
global_arguments,
|
||||||
),
|
),
|
||||||
[borgmatic_manifest_path],
|
[borgmatic_manifest_path],
|
||||||
{},
|
{},
|
||||||
|
@ -38,14 +40,14 @@ def get_config_paths(bootstrap_arguments, global_arguments, local_borg_version):
|
||||||
|
|
||||||
return manifest_data['config_paths']
|
return manifest_data['config_paths']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def run_bootstrap(bootstrap_arguments, global_arguments, local_borg_version):
|
def run_bootstrap(bootstrap_arguments, global_arguments, local_borg_version):
|
||||||
'''
|
'''
|
||||||
Run the "bootstrap" action for the given repository.
|
Run the "bootstrap" action for the given repository.
|
||||||
'''
|
'''
|
||||||
manifest_config_paths = get_config_paths(bootstrap_arguments, global_arguments, local_borg_version)
|
manifest_config_paths = get_config_paths(
|
||||||
|
bootstrap_arguments, global_arguments, local_borg_version
|
||||||
|
)
|
||||||
|
|
||||||
for config_path in manifest_config_paths:
|
for config_path in manifest_config_paths:
|
||||||
logger.info('Bootstrapping config path %s', config_path)
|
logger.info('Bootstrapping config path %s', config_path)
|
||||||
|
@ -58,7 +60,7 @@ def run_bootstrap(bootstrap_arguments, global_arguments, local_borg_version):
|
||||||
bootstrap_arguments.archive,
|
bootstrap_arguments.archive,
|
||||||
{},
|
{},
|
||||||
local_borg_version,
|
local_borg_version,
|
||||||
global_arguments
|
global_arguments,
|
||||||
),
|
),
|
||||||
[config_path],
|
[config_path],
|
||||||
{},
|
{},
|
||||||
|
@ -70,7 +72,3 @@ def run_bootstrap(bootstrap_arguments, global_arguments, local_borg_version):
|
||||||
strip_components=bootstrap_arguments.strip_components,
|
strip_components=bootstrap_arguments.strip_components,
|
||||||
progress=bootstrap_arguments.progress,
|
progress=bootstrap_arguments.progress,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import argparse
|
import argparse
|
||||||
import collections
|
import collections
|
||||||
|
import itertools
|
||||||
from argparse import Action, ArgumentParser
|
from argparse import Action, ArgumentParser
|
||||||
|
|
||||||
from borgmatic.config import collect
|
from borgmatic.config import collect
|
||||||
|
@ -75,14 +76,20 @@ def parse_subparser_arguments(unparsed_arguments, subparsers):
|
||||||
remaining_arguments.remove(item)
|
remaining_arguments.remove(item)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
arguments[canonical_name] = None if canonical_name in subcommand_parsers_mapping else parsed
|
arguments[canonical_name] = (
|
||||||
|
None if canonical_name in subcommand_parsers_mapping else parsed
|
||||||
|
)
|
||||||
except UnboundLocalError:
|
except UnboundLocalError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for argument in arguments:
|
for argument in arguments:
|
||||||
if not arguments[argument]:
|
if not arguments[argument]:
|
||||||
if not any(subcommand in arguments for subcommand in subcommand_parsers_mapping[argument]):
|
if not any(
|
||||||
raise ValueError(f"Missing subcommand for {argument}. Expected one of {subcommand_parsers_mapping[argument]}")
|
subcommand in arguments for subcommand in subcommand_parsers_mapping[argument]
|
||||||
|
):
|
||||||
|
raise ValueError(
|
||||||
|
f'Missing subcommand for {argument}. Expected one of {subcommand_parsers_mapping[argument]}'
|
||||||
|
)
|
||||||
|
|
||||||
# If no actions are explicitly requested, assume defaults.
|
# If no actions are explicitly requested, assume defaults.
|
||||||
if not arguments and '--help' not in unparsed_arguments and '-h' not in unparsed_arguments:
|
if not arguments and '--help' not in unparsed_arguments and '-h' not in unparsed_arguments:
|
||||||
|
@ -93,6 +100,10 @@ def parse_subparser_arguments(unparsed_arguments, subparsers):
|
||||||
|
|
||||||
remaining_arguments = list(unparsed_arguments)
|
remaining_arguments = list(unparsed_arguments)
|
||||||
|
|
||||||
|
# Now ask each subparser, one by one, to greedily consume arguments, from last to first. This
|
||||||
|
# allows subparsers to consume arguments before their parent subparsers do.
|
||||||
|
remaining_subparser_arguments = []
|
||||||
|
|
||||||
# Now ask each subparser, one by one, to greedily consume arguments, from last to first. This
|
# Now ask each subparser, one by one, to greedily consume arguments, from last to first. This
|
||||||
# allows subparsers to consume arguments before their parent subparsers do.
|
# allows subparsers to consume arguments before their parent subparsers do.
|
||||||
for subparser_name, subparser in reversed(subparsers.items()):
|
for subparser_name, subparser in reversed(subparsers.items()):
|
||||||
|
@ -100,9 +111,23 @@ def parse_subparser_arguments(unparsed_arguments, subparsers):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
subparser = subparsers[subparser_name]
|
subparser = subparsers[subparser_name]
|
||||||
unused_parsed, remaining_arguments = subparser.parse_known_args(
|
unused_parsed, remaining = subparser.parse_known_args(
|
||||||
[argument for argument in remaining_arguments if argument != subparser_name]
|
[argument for argument in unparsed_arguments if argument != subparser_name]
|
||||||
)
|
)
|
||||||
|
remaining_subparser_arguments.append(remaining)
|
||||||
|
|
||||||
|
# Determine the remaining arguments that no subparsers have consumed.
|
||||||
|
if remaining_subparser_arguments:
|
||||||
|
remaining_arguments = [
|
||||||
|
argument
|
||||||
|
for argument in dict.fromkeys(
|
||||||
|
itertools.chain.from_iterable(remaining_subparser_arguments)
|
||||||
|
).keys()
|
||||||
|
if all(
|
||||||
|
argument in subparser_arguments
|
||||||
|
for subparser_arguments in remaining_subparser_arguments
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
# Special case: If "borg" is present in the arguments, consume all arguments after (+1) the
|
# Special case: If "borg" is present in the arguments, consume all arguments after (+1) the
|
||||||
# "borg" action.
|
# "borg" action.
|
||||||
|
@ -551,9 +576,7 @@ def make_parsers():
|
||||||
)
|
)
|
||||||
|
|
||||||
config_group = config_parser.add_argument_group('config arguments')
|
config_group = config_parser.add_argument_group('config arguments')
|
||||||
config_group.add_argument(
|
config_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
||||||
'-h', '--help', action='help', help='Show this help message and exit'
|
|
||||||
)
|
|
||||||
|
|
||||||
config_subparsers = config_parser.add_subparsers(
|
config_subparsers = config_parser.add_subparsers(
|
||||||
title='config subcommands',
|
title='config subcommands',
|
||||||
|
@ -568,7 +591,9 @@ def make_parsers():
|
||||||
description='Extract just the config files that were used to create a borgmatic repository during the "create" operation',
|
description='Extract just the config files that were used to create a borgmatic repository during the "create" operation',
|
||||||
add_help=False,
|
add_help=False,
|
||||||
)
|
)
|
||||||
config_bootstrap_group = config_bootstrap_parser.add_argument_group('config bootstrap arguments')
|
config_bootstrap_group = config_bootstrap_parser.add_argument_group(
|
||||||
|
'config bootstrap arguments'
|
||||||
|
)
|
||||||
config_bootstrap_group.add_argument(
|
config_bootstrap_group.add_argument(
|
||||||
'--repository',
|
'--repository',
|
||||||
help='Path of repository to extract config files from',
|
help='Path of repository to extract config files from',
|
||||||
|
@ -579,7 +604,9 @@ def make_parsers():
|
||||||
help='Path that stores the config files used to create an archive, and additional source files used for temporary internal state like borgmatic database dumps. Defaults to ~/.borgmatic',
|
help='Path that stores the config files used to create an archive, and additional source files used for temporary internal state like borgmatic database dumps. Defaults to ~/.borgmatic',
|
||||||
)
|
)
|
||||||
config_bootstrap_group.add_argument(
|
config_bootstrap_group.add_argument(
|
||||||
'--archive', help='Name of archive to extract config files from, defaults to "latest"', default='latest'
|
'--archive',
|
||||||
|
help='Name of archive to extract config files from, defaults to "latest"',
|
||||||
|
default='latest',
|
||||||
)
|
)
|
||||||
config_bootstrap_group.add_argument(
|
config_bootstrap_group.add_argument(
|
||||||
'--destination',
|
'--destination',
|
||||||
|
@ -947,7 +974,9 @@ def make_parsers():
|
||||||
)
|
)
|
||||||
borg_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
borg_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
||||||
|
|
||||||
merged_subparsers = argparse._SubParsersAction(None, None, metavar=None, dest='merged', parser_class=None)
|
merged_subparsers = argparse._SubParsersAction(
|
||||||
|
None, None, metavar=None, dest='merged', parser_class=None
|
||||||
|
)
|
||||||
|
|
||||||
for name, subparser in subparsers.choices.items():
|
for name, subparser in subparsers.choices.items():
|
||||||
merged_subparsers._name_parser_map[name] = subparser
|
merged_subparsers._name_parser_map[name] = subparser
|
||||||
|
@ -957,7 +986,7 @@ def make_parsers():
|
||||||
merged_subparsers._name_parser_map[name] = subparser
|
merged_subparsers._name_parser_map[name] = subparser
|
||||||
subparser._name_parser_map = merged_subparsers._name_parser_map
|
subparser._name_parser_map = merged_subparsers._name_parser_map
|
||||||
|
|
||||||
return top_level_parser, merged_subparsers
|
return top_level_parser, merged_subparsers
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments(*unparsed_arguments):
|
def parse_arguments(*unparsed_arguments):
|
||||||
|
@ -967,12 +996,15 @@ def parse_arguments(*unparsed_arguments):
|
||||||
'''
|
'''
|
||||||
top_level_parser, subparsers = make_parsers()
|
top_level_parser, subparsers = make_parsers()
|
||||||
|
|
||||||
|
|
||||||
arguments, remaining_arguments = parse_subparser_arguments(
|
arguments, remaining_arguments = parse_subparser_arguments(
|
||||||
unparsed_arguments, subparsers.choices
|
unparsed_arguments, subparsers.choices
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'bootstrap' in arguments.keys() and 'config' in arguments.keys() and len(arguments.keys()) > 2:
|
if (
|
||||||
|
'bootstrap' in arguments.keys()
|
||||||
|
and 'config' in arguments.keys()
|
||||||
|
and len(arguments.keys()) > 2
|
||||||
|
):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'The bootstrap action cannot be combined with other actions. Please run it separately.'
|
'The bootstrap action cannot be combined with other actions. Please run it separately.'
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,10 +18,10 @@ import borgmatic.actions.borg
|
||||||
import borgmatic.actions.break_lock
|
import borgmatic.actions.break_lock
|
||||||
import borgmatic.actions.check
|
import borgmatic.actions.check
|
||||||
import borgmatic.actions.compact
|
import borgmatic.actions.compact
|
||||||
|
import borgmatic.actions.config.bootstrap
|
||||||
import borgmatic.actions.create
|
import borgmatic.actions.create
|
||||||
import borgmatic.actions.export_tar
|
import borgmatic.actions.export_tar
|
||||||
import borgmatic.actions.extract
|
import borgmatic.actions.extract
|
||||||
import borgmatic.actions.config.bootstrap
|
|
||||||
import borgmatic.actions.info
|
import borgmatic.actions.info
|
||||||
import borgmatic.actions.list
|
import borgmatic.actions.list
|
||||||
import borgmatic.actions.mount
|
import borgmatic.actions.mount
|
||||||
|
@ -622,12 +622,14 @@ def collect_configuration_run_summary_logs(configs, arguments):
|
||||||
except ValueError as error:
|
except ValueError as error:
|
||||||
yield from log_error_records(str(error))
|
yield from log_error_records(str(error))
|
||||||
return
|
return
|
||||||
|
|
||||||
if 'bootstrap' in arguments:
|
if 'bootstrap' in arguments:
|
||||||
# no configuration file is needed for bootstrap
|
# no configuration file is needed for bootstrap
|
||||||
local_borg_version = borg_version.local_borg_version({}, 'borg')
|
local_borg_version = borg_version.local_borg_version({}, 'borg')
|
||||||
try:
|
try:
|
||||||
borgmatic.actions.config.bootstrap.run_bootstrap(arguments['bootstrap'], arguments['global'], local_borg_version)
|
borgmatic.actions.config.bootstrap.run_bootstrap(
|
||||||
|
arguments['bootstrap'], arguments['global'], local_borg_version
|
||||||
|
)
|
||||||
yield logging.makeLogRecord(
|
yield logging.makeLogRecord(
|
||||||
dict(
|
dict(
|
||||||
levelno=logging.INFO,
|
levelno=logging.INFO,
|
||||||
|
|
Loading…
Reference in a new issue