From ef32b292a8456a7177ba51b3c4fc6b4c786a55e8 Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Mon, 10 Jul 2017 16:06:02 -0700 Subject: [PATCH] Provide helpful message when borgmatic is run with only legacy config present. --- README.md | 2 +- borgmatic/commands/borgmatic.py | 9 +++--- borgmatic/config/convert.py | 29 +++++++++++++++++++ borgmatic/tests/unit/config/test_convert.py | 31 +++++++++++++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b1225c346..6c25de2e8 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ upgrade to the new version of borgmatic: Then, run: - sudo upgrade-borgmatic-configuration + sudo upgrade-borgmatic-config That will generate a new YAML configuration file at /etc/borgmatic/config.yaml (by default) using the values from both your existing configuration and diff --git a/borgmatic/commands/borgmatic.py b/borgmatic/commands/borgmatic.py index a1d53e3fc..0299da69d 100644 --- a/borgmatic/commands/borgmatic.py +++ b/borgmatic/commands/borgmatic.py @@ -5,9 +5,10 @@ from subprocess import CalledProcessError import sys from borgmatic import borg -from borgmatic.config.validate import parse_configuration, schema_filename +from borgmatic.config import convert, validate +LEGACY_CONFIG_FILENAME = '/etc/borgmatic/config' DEFAULT_CONFIG_FILENAME = '/etc/borgmatic/config.yaml' DEFAULT_EXCLUDES_FILENAME = '/etc/borgmatic/excludes' @@ -41,11 +42,9 @@ def parse_arguments(*arguments): def main(): # pragma: no cover try: - # TODO: Detect whether only legacy config is present. If so, inform the user about how to - # upgrade, then exit. - args = parse_arguments(*sys.argv[1:]) - config = parse_configuration(args.config_filename, schema_filename()) + convert.guard_configuration_upgraded(LEGACY_CONFIG_FILENAME, args.config_filename) + config = validate.parse_configuration(args.config_filename, validate.schema_filename()) repository = config.location['repository'] remote_path = config.location.get('remote_path') diff --git a/borgmatic/config/convert.py b/borgmatic/config/convert.py index 11618e958..bdf9eb2d3 100644 --- a/borgmatic/config/convert.py +++ b/borgmatic/config/convert.py @@ -1,3 +1,5 @@ +import os + from ruamel import yaml from borgmatic.config import generate @@ -48,3 +50,30 @@ def convert_legacy_parsed_config(source_config, source_excludes, schema): ) return destination_config + + +class LegacyConfigurationNotUpgraded(FileNotFoundError): + def __init__(self): + super(LegacyConfigurationNotUpgraded, self).__init__( + '''borgmatic changed its configuration file format in version 1.1.0 from INI-style +to YAML. This better supports validation, and has a more natural way to express +lists of values. To upgrade your existing configuration, run: + + sudo upgrade-borgmatic-config + +That will generate a new YAML configuration file at /etc/borgmatic/config.yaml +(by default) using the values from both your existing configuration and excludes +files. The new version of borgmatic will consume the YAML configuration file +instead of the old one.''' + ) + + +def guard_configuration_upgraded(source_config_filename, destination_config_filename): + ''' + If legacy souce configuration exists but destination upgraded config doesn't, raise + LegacyConfigurationNotUpgraded. + + The idea is that we want to alert the user about upgrading their config if they haven't already. + ''' + if os.path.exists(source_config_filename) and not os.path.exists(destination_config_filename): + raise LegacyConfigurationNotUpgraded() diff --git a/borgmatic/tests/unit/config/test_convert.py b/borgmatic/tests/unit/config/test_convert.py index a88ed2f0c..2e5849bd0 100644 --- a/borgmatic/tests/unit/config/test_convert.py +++ b/borgmatic/tests/unit/config/test_convert.py @@ -1,6 +1,8 @@ from collections import defaultdict, OrderedDict, namedtuple +import os from flexmock import flexmock +import pytest from borgmatic.config import convert as module @@ -61,3 +63,32 @@ def test_convert_legacy_parsed_config_splits_space_separated_values(): ('retention', OrderedDict()), ('consistency', OrderedDict([('checks', ['repository', 'archives'])])), ]) + + +def test_guard_configuration_upgraded_raises_when_only_source_config_present(): + flexmock(os.path).should_receive('exists').with_args('config').and_return(True) + flexmock(os.path).should_receive('exists').with_args('config.yaml').and_return(False) + + with pytest.raises(module.LegacyConfigurationNotUpgraded): + module.guard_configuration_upgraded('config', 'config.yaml') + + +def test_guard_configuration_upgraded_does_not_raise_when_only_destination_config_present(): + flexmock(os.path).should_receive('exists').with_args('config').and_return(False) + flexmock(os.path).should_receive('exists').with_args('config.yaml').and_return(True) + + module.guard_configuration_upgraded('config', 'config.yaml') + + +def test_guard_configuration_upgraded_does_not_raise_when_both_configs_present(): + flexmock(os.path).should_receive('exists').with_args('config').and_return(True) + flexmock(os.path).should_receive('exists').with_args('config.yaml').and_return(True) + + module.guard_configuration_upgraded('config', 'config.yaml') + + +def test_guard_configuration_upgraded_does_not_raise_when_neither_config_present(): + flexmock(os.path).should_receive('exists').with_args('config').and_return(False) + flexmock(os.path).should_receive('exists').with_args('config.yaml').and_return(False) + + module.guard_configuration_upgraded('config', 'config.yaml')