pass all tests with wittens recommendation

This commit is contained in:
Divyansh Singh 2023-06-06 23:37:09 +05:30
parent 6a1d1a2e59
commit 4b024daae0
3 changed files with 62 additions and 30 deletions

View file

@ -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,
) )

View file

@ -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.'
) )

View file

@ -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,