Migrate YAML config files in old format

This commit is contained in:
Florian Bruhin 2018-02-20 16:14:06 +01:00
parent b3d788fead
commit 03114ccf51
3 changed files with 51 additions and 19 deletions

View File

@ -80,7 +80,7 @@ class YamlConfig(QObject):
VERSION: The current version number of the config file. VERSION: The current version number of the config file.
""" """
VERSION = 1 VERSION = 2
changed = pyqtSignal() changed = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
@ -173,8 +173,11 @@ class YamlConfig(QObject):
config_version = self._pop_object(yaml_data, 'config_version', int) config_version = self._pop_object(yaml_data, 'config_version', int)
if config_version == 1:
settings = self._load_legacy_settings_object(yaml_data)
self._mark_changed()
else:
settings = self._load_settings_object(yaml_data) settings = self._load_settings_object(yaml_data)
self._dirty = False self._dirty = False
settings = self._handle_migrations(settings) settings = self._handle_migrations(settings)
self._validate(settings) self._validate(settings)
@ -184,9 +187,15 @@ class YamlConfig(QObject):
"""Load the settings from the settings: key.""" """Load the settings from the settings: key."""
return self._pop_object(yaml_data, 'settings', dict) return self._pop_object(yaml_data, 'settings', dict)
def _load_legacy_settings_object(self, yaml_data):
data = self._pop_object(yaml_data, 'global', dict)
settings = {}
for name, value in data.items():
settings[name] = {'global': value}
return settings
def _build_values(self, settings): def _build_values(self, settings):
"""Build up self._values from the values in the given dict.""" """Build up self._values from the values in the given dict."""
# FIXME:conf test this
for name, yaml_values in settings.items(): for name, yaml_values in settings.items():
values = configutils.Values(configdata.DATA[name]) values = configutils.Values(configdata.DATA[name])
if 'global' in yaml_values: if 'global' in yaml_values:
@ -200,9 +209,6 @@ class YamlConfig(QObject):
def _handle_migrations(self, settings): def _handle_migrations(self, settings):
"""Migrate older configs to the newest format.""" """Migrate older configs to the newest format."""
# FIXME:conf handle per-URL settings
# FIXME:conf migrate from older format with global: key
# Simple renamed/deleted options # Simple renamed/deleted options
for name in list(settings): for name in list(settings):
if name in configdata.MIGRATIONS.renamed: if name in configdata.MIGRATIONS.renamed:

View File

@ -45,19 +45,25 @@ class AutoConfigHelper:
def __init__(self, config_tmpdir): def __init__(self, config_tmpdir):
self.fobj = config_tmpdir / 'autoconfig.yml' self.fobj = config_tmpdir / 'autoconfig.yml'
def write(self, values): def write_toplevel(self, data):
data = {'config_version': 1, 'settings': values}
with self.fobj.open('w', encoding='utf-8') as f: with self.fobj.open('w', encoding='utf-8') as f:
utils.yaml_dump(data, f) utils.yaml_dump(data, f)
def write(self, values):
data = {'config_version': 2, 'settings': values}
self.write_toplevel(data)
def write_raw(self, text): def write_raw(self, text):
self.fobj.write_text(text, encoding='utf-8', ensure=True) self.fobj.write_text(text, encoding='utf-8', ensure=True)
def read(self): def read_toplevel(self):
with self.fobj.open('r', encoding='utf-8') as f: with self.fobj.open('r', encoding='utf-8') as f:
data = utils.yaml_load(f) data = utils.yaml_load(f)
assert data['config_version'] == 1 assert data['config_version'] == 2
return data['settings'] return data
def read(self):
return self.read_toplevel()['settings']
def read_raw(self): def read_raw(self):
return self.fobj.read_text('utf-8') return self.fobj.read_text('utf-8')
@ -284,9 +290,9 @@ class TestYaml:
@pytest.mark.parametrize('line, text, exception', [ @pytest.mark.parametrize('line, text, exception', [
('%', 'While parsing', 'while scanning a directive'), ('%', 'While parsing', 'while scanning a directive'),
('settings: 42\nconfig_version: 1', ('settings: 42\nconfig_version: 2',
'While loading data', "'settings' object is not a dict"), 'While loading data', "'settings' object is not a dict"),
('foo: 42\nconfig_version: 1', 'While loading data', ('foo: 42\nconfig_version: 2', 'While loading data',
"Toplevel object does not contain 'settings' key"), "Toplevel object does not contain 'settings' key"),
('settings: {}', 'While loading data', ('settings: {}', 'While loading data',
"Toplevel object does not contain 'config_version' key"), "Toplevel object does not contain 'config_version' key"),
@ -304,6 +310,26 @@ class TestYaml:
assert str(error.exception).splitlines()[0] == exception assert str(error.exception).splitlines()[0] == exception
assert error.traceback is None assert error.traceback is None
def test_legacy_migration(self, yaml, autoconfig, qtbot):
autoconfig.write_toplevel({
'config_version': 1,
'global': {'content.javascript.enabled': True},
})
with qtbot.wait_signal(yaml.changed):
yaml.load()
yaml._save()
data = autoconfig.read_toplevel()
assert data == {
'config_version': 2,
'settings': {
'content.javascript.enabled': {
'global': True,
}
}
}
def test_oserror(self, yaml, autoconfig): def test_oserror(self, yaml, autoconfig):
autoconfig.fobj.ensure() autoconfig.fobj.ensure()
autoconfig.fobj.chmod(0) autoconfig.fobj.chmod(0)

View File

@ -123,19 +123,19 @@ class TestEarlyInit:
'settings:', 'settings:',
' colors.foobar:', ' colors.foobar:',
' global: magenta', ' global: magenta',
'config_version: 1', 'config_version: 2',
], ],
'wrong-type': [ 'wrong-type': [
'settings:', 'settings:',
' tabs.position:', ' tabs.position:',
' global: true', ' global: true',
'config_version: 1', 'config_version: 2',
], ],
False: [ False: [
'settings:', 'settings:',
' colors.hints.fg:', ' colors.hints.fg:',
' global: magenta', ' global: magenta',
'config_version: 1', 'config_version: 2',
], ],
} }
text = '\n'.join(yaml_lines[invalid_yaml]) text = '\n'.join(yaml_lines[invalid_yaml])
@ -240,7 +240,7 @@ class TestEarlyInit:
args.temp_settings = settings args.temp_settings = settings
elif method == 'auto': elif method == 'auto':
autoconfig_file = config_tmpdir / 'autoconfig.yml' autoconfig_file = config_tmpdir / 'autoconfig.yml'
lines = (["config_version: 1", "settings:"] + lines = (["config_version: 2", "settings:"] +
[" {}:\n global:\n '{}'".format(k, v) [" {}:\n global:\n '{}'".format(k, v)
for k, v in settings]) for k, v in settings])
autoconfig_file.write_text('\n'.join(lines), 'utf-8', ensure=True) autoconfig_file.write_text('\n'.join(lines), 'utf-8', ensure=True)