Channels config file now has version information and set up basis for converting to newer versions

This commit is contained in:
Elnath 2021-01-01 22:41:54 +01:00
parent 927a96d8b0
commit 3c7dd2e8a0
2 changed files with 65 additions and 8 deletions

View File

@ -1,19 +1,37 @@
from pathlib import Path
from typing import Union, Dict, List
import logging
import json
import atexit
import json
import logging
from pathlib import Path
from typing import Union, Dict, List, Callable, Tuple
import discord
import utils
from . import vNoneTov1_0
logger = logging.getLogger(__name__)
# Functions used to convert between configuration versions, in a dictionary of: old_version -> converter
# Each converter takes the old configuration and returns the converted configuration and the new version
config_version_converters: Dict[Union[None, str], Callable[[Dict], Tuple[Dict, str]]] = {
None: vNoneTov1_0.convert
}
class ChannelsConfigFile:
"""
Wrapper for the channels configuration file, telling which channels to watch and which channels were created by the bot.
"""
version = "1.0"
@staticmethod
def empty_config() -> Dict:
"""
:return: An empty configuration, used to initialise the configuration file
"""
return {
"__version__": ChannelsConfigFile.version,
}
def __init__(self, config_file_path: Union[str, Path]):
self.config_file = None # File descriptor to the on-disk config file
@ -30,13 +48,15 @@ class ChannelsConfigFile:
if config_file_path.stat().st_size == 0: # Config file is empty
logger.warning(f"Config file {config_file_path} is empty, using empty config")
self.config = {}
self.config = self.empty_config()
self.save_to_file() # So that the file is proper json
else: # Config file is not empty
self.reload_from_disk()
has_been_converted = self.reload_from_disk()
if has_been_converted:
self.save_to_file()
else: # Config file does not exist
self.config_file = config_file_path.open("w+")
self.config = {}
self.config = self.empty_config()
self.save_to_file() # So that the file is proper json
# Verifying that attributes have been initialised properly
@ -45,9 +65,13 @@ class ChannelsConfigFile:
atexit.register(self.save_to_file)
def reload_from_disk(self) -> None:
def reload_from_disk(self) -> bool:
"""
Reload the configuration from the on-disk file
:return: Whether the configuration had to be converted to a more recent version because the on-file was an earlier version
:except json.JSONDecodeError: if the file is not valid json
:except ValueError: if the version of the configuration in the file is not known or can not be converted to a more recent one
"""
logger.debug("Loading channels configuration file from disk")
self.config_file.seek(0) # Moving to beginning of file
@ -56,7 +80,27 @@ class ChannelsConfigFile:
except json.JSONDecodeError as e:
logger.critical(f"JSON Error when parsing channels config file: {e}")
raise e
# Checking configuration version and converting if needed
config_version = self.config["__version__"] if "__version__" in self.config else None
has_been_converted = False
if config_version != self.version:
logger.info(f"Channels configuration file is an older version, converting (on-file: {config_version}, current: {self.version})...")
# Performing the conversion
while config_version != self.version:
if config_version in config_version_converters:
logger.debug(f"Converting from {config_version}")
self.config, config_version = config_version_converters[config_version](self.config)
logger.debug(f"Converted to {config_version}")
else:
logger.critical(f"Impossible to find converter to convert from {config_version}")
raise ValueError(f"Configuration loading: impossible to convert on-file config to current version")
has_been_converted = True
assert self.config["__version__"] == self.version
logger.debug("Loaded channels configuration file from disk")
return has_been_converted
def save_to_file(self, indent = 2) -> None:
"""

View File

@ -0,0 +1,13 @@
"""
Converter for converting ChannelsConfigFile from version "Versions weren't a thing back then" to version 1.0
"""
from typing import Dict, Tuple
def convert(config: Dict) -> Tuple[Dict, str]:
assert "__version__" not in config
# This first simple converter only adds version information to the config
# this poses the basis for version conversion
config["__version__"] = "1.0"
return config, "1.0"