vxSDK/vxsdk/core/config.py

169 lines
5.1 KiB
Python

"""
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)