""" Configuration file wrapper """ import os import toml from core.logger import log __all__ = [ 'config_get', 'config_set', 'config_set_default' ] DEFAULT_CONFIG_KEYVAL = [ ('path.config', '~/.config/vxsdk/config.toml'), ('path.sysroot', '~/.local/share/vxsdk/sysroot'), ('path.packages', '~/.local/share/vxsdk/packages'), ('path.assets', '~/.local/share/vxsdk/assets'), ('path.bin', '~/.local/bin'), ('build.default_target', 'superh'), ('pkg.backend.name', 'gitea'), ('pkg.backend.url', 'https://gitea.planet-casio.com'), ('pkg.local_storage', '{path.packages}') ] __CACHED_CONFIG_FILE = None __CACHED_CONFIG_PATH = None #--- # Internals #--- def __setitem_dots(dictionary, key, value, path=""): if "." not in key: old = dictionary[key] if key in dictionary else None dictionary[key] = value return old group, key = key.split(".", 1) if group in dictionary and not isinstance(dictionary[group], dict): raise ValueError(f"cannot assign {value} into value {path+group}") if group not in dictionary: dictionary[group] = {} return __setitem_dots(dictionary[group], key, value, path + group + ".") def __config_control(name, value=None): """ Common configuration file manipulation If the `value` parameter is not set, only read operation will be performed, otherwise the complete file will be updated. @args > name (str) - dot-separated ker (ex : `default.board.name`) > value (str) - value for the key """ global __CACHED_CONFIG_PATH global __CACHED_CONFIG_FILE # check if config file information are cached # @notes # - create the configuration file folder if needed # - load the TOML content # - cache pathname to avoid path manipulation if not __CACHED_CONFIG_PATH: __CACHED_CONFIG_PATH = os.path.expanduser('~/.config/vxsdk/config.toml') if not __CACHED_CONFIG_FILE: cache_basename = os.path.basename(__CACHED_CONFIG_PATH) if not os.path.exists(cache_basename): os.makedirs(cache_basename) with open(__CACHED_CONFIG_PATH, 'r+', encoding='utf-8') as file: __CACHED_CONFIG_FILE = toml.loads(file.read()) # check "read-only" request (just fetch value) if not value: conf = __CACHED_CONFIG_FILE targets = name.split('.') while targets: if not targets[0] in conf: log.debug(f"[config] unable to find target '{name}'") return None conf = conf[targets[0]] targets = targets[1:] return conf # perform "write-only" request (update the configuration file) old = __setitem_dots(__CACHED_CONFIG_FILE, name, value) with open(__CACHED_CONFIG_PATH, "w", encoding='utf-8') as file: file.write(toml.dumps(__CACHED_CONFIG_FILE)) # return the previous information of the update field (if available) return old def _generate_value(name, val): if not val: return None while val.find('{') >= 0: if val.find('}') < 0: break key = val[val.find('{') + 1: val.find('}')] res = __config_control(key) if not res: log.warn(f"[config] {name} = {val} : unable to find '{key}'") return None val = val[:val.find('{')] + res + val[val.find('}') + 1:] return val #--- # Public functions #--- def config_get(key: str, default_value: str = None) -> str: """ Get configuration key/value This function will try to find the key value of `key`. If the key doest not exists then None will be returned. You can specify a default value if the key doest not exist. @args > key: string - the key name > default_value: string - the key default value if not found @return > return the key value or None if not found nor default value set """ if ret := __config_control(key): return _generate_value(key, ret) default_value = _generate_value(key, default_value) if default_value: __config_control(key, default_value) return default_value def config_set(key: str, value: str) -> str: """ Set configuration key = value This function will try to update the user vxSDK configuration file to add key / value information. Note that the `value` can have placeholder in its content like `{path.sysroot}/superh` wich will fetch the 'path.sysroot' configuration key. @args > key: string - the key name > name: string - the key value @return > the old key value or None if new """ return __config_control(key, value) def config_set_default(list_of_keyval: list): """ Set default key / value This function will setup all default key value if the key doest not exists. This is usefull to centralise all default user configuration information in this file instead of in all project files. @arg > list_of_keyval: list of tuple - [(key, value), ...] """ for key, value in list_of_keyval: if not __config_control(key): __config_control(key, value) # workaround config_set_default(DEFAULT_CONFIG_KEYVAL)