169 lines
5.1 KiB
Python
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)
|