diff --git a/borgmatic/actions/bootstrap.py b/borgmatic/actions/config/bootstrap.py similarity index 81% rename from borgmatic/actions/bootstrap.py rename to borgmatic/actions/config/bootstrap.py index 3a480dd..f3b6459 100644 --- a/borgmatic/actions/bootstrap.py +++ b/borgmatic/actions/config/bootstrap.py @@ -14,14 +14,14 @@ logger = logging.getLogger(__name__) 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_manifest_path = os.path.expanduser( - os.path.join(borgmatic_source_directory, 'bootstrap', 'configs-list.json') + os.path.join(borgmatic_source_directory, 'bootstrap', 'manifest.json') ) extract_process = borgmatic.borg.extract.extract_archive( global_arguments.dry_run, bootstrap_arguments.repository, borgmatic.borg.rlist.resolve_archive_name( bootstrap_arguments.repository, - bootstrap_arguments.archive or 'latest', + bootstrap_arguments.archive, {}, local_borg_version, global_arguments @@ -34,11 +34,7 @@ def get_config_paths(bootstrap_arguments, global_arguments, local_borg_version): extract_to_stdout=True, ) - try: - manifest_data = json.loads(extract_process.stdout.read()) - except json.decoder.JSONDecodeError as error: - logger.error('Error parsing manifest data: %s', error) - raise + manifest_data = json.loads(extract_process.stdout.read()) return manifest_data['config_paths'] @@ -59,7 +55,7 @@ def run_bootstrap(bootstrap_arguments, global_arguments, local_borg_version): bootstrap_arguments.repository, borgmatic.borg.rlist.resolve_archive_name( bootstrap_arguments.repository, - bootstrap_arguments.archive or 'latest', + bootstrap_arguments.archive, {}, local_borg_version, global_arguments @@ -70,7 +66,7 @@ def run_bootstrap(bootstrap_arguments, global_arguments, local_borg_version): local_borg_version, global_arguments, extract_to_stdout=False, - destination_path=bootstrap_arguments.destination or '/', + destination_path=bootstrap_arguments.destination, strip_components=bootstrap_arguments.strip_components, progress=bootstrap_arguments.progress, ) diff --git a/borgmatic/actions/create.py b/borgmatic/actions/create.py index c5a6513..48f863e 100644 --- a/borgmatic/actions/create.py +++ b/borgmatic/actions/create.py @@ -30,7 +30,7 @@ def create_borgmatic_manifest(location, config_paths, dry_run): ) borgmatic_manifest_path = os.path.expanduser( - os.path.join(borgmatic_source_directory, 'bootstrap', 'configs-list.json') + os.path.join(borgmatic_source_directory, 'bootstrap', 'manifest.json') ) if not os.path.exists(borgmatic_manifest_path): diff --git a/borgmatic/commands/arguments.py b/borgmatic/commands/arguments.py index a66f0ed..cbfc9be 100644 --- a/borgmatic/commands/arguments.py +++ b/borgmatic/commands/arguments.py @@ -74,15 +74,15 @@ def parse_subparser_arguments(unparsed_arguments, subparsers): if item in subparsers: remaining_arguments.remove(item) - arguments[canonical_name] = None if canonical_name in subcommand_parsers_mapping else parsed - + try: + arguments[canonical_name] = None if canonical_name in subcommand_parsers_mapping else parsed + except UnboundLocalError: + pass + for argument in arguments: if not arguments[argument]: if not any(subcommand in arguments for subcommand in subcommand_parsers_mapping[argument]): - raise ValueError("Missing subcommand for {}. Expected one of {}".format( - argument, 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 not arguments and '--help' not in unparsed_arguments and '-h' not in unparsed_arguments: @@ -564,28 +564,29 @@ def make_parsers(): config_bootstrap_parser = config_subparsers.add_parser( 'bootstrap', aliases=SUBPARSER_ALIASES['config_bootstrap'], - help='Extract files from a borgmatic created repository to the current directory', - description='Extract a named archive from a borgmatic created repository to the current directory without a configuration file', + help='Extract the config files used to create a borgmatic repository', + description='Extract just the config files that were used to create a borgmatic repository during the "create" operation', add_help=False, ) config_bootstrap_group = config_bootstrap_parser.add_argument_group('config bootstrap arguments') config_bootstrap_group.add_argument( '--repository', - help='Path of repository to extract', + help='Path of repository to extract config files from', required=True, ) config_bootstrap_group.add_argument( '--borgmatic-source-directory', - help='Path of the borgmatic source directory if other than the default', + 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( - '--archive', help='Name of archive to extract, defaults to "latest"' + '--archive', help='Name of archive to extract config files from, defaults to "latest"', default='latest' ) config_bootstrap_group.add_argument( '--destination', metavar='PATH', dest='destination', - help='Directory to extract files into, defaults to /', + help='Directory to extract config files into, defaults to /', + default='/', ) config_bootstrap_group.add_argument( '--strip-components', diff --git a/borgmatic/commands/borgmatic.py b/borgmatic/commands/borgmatic.py index 7aaf570..ddfb989 100644 --- a/borgmatic/commands/borgmatic.py +++ b/borgmatic/commands/borgmatic.py @@ -21,7 +21,7 @@ import borgmatic.actions.compact import borgmatic.actions.create import borgmatic.actions.export_tar import borgmatic.actions.extract -import borgmatic.actions.bootstrap +import borgmatic.actions.config.bootstrap import borgmatic.actions.info import borgmatic.actions.list import borgmatic.actions.mount @@ -627,7 +627,7 @@ def collect_configuration_run_summary_logs(configs, arguments): # no configuration file is needed for bootstrap local_borg_version = borg_version.local_borg_version({}, 'borg') try: - borgmatic.actions.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( dict( levelno=logging.INFO, @@ -635,7 +635,7 @@ def collect_configuration_run_summary_logs(configs, arguments): msg='Bootstrap successful', ) ) - except (CalledProcessError, ValueError, OSError) as error: + except (CalledProcessError, ValueError, OSError, json.JSONDecodeError, KeyError) as error: yield from log_error_records('Error running bootstrap', error) return