diff options
Diffstat (limited to 'sb_builder/config.py')
| -rw-r--r-- | sb_builder/config.py | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/sb_builder/config.py b/sb_builder/config.py new file mode 100644 index 0000000..4549b66 --- /dev/null +++ b/sb_builder/config.py @@ -0,0 +1,57 @@ +# sb-builder - GUI configuration +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +"""GUI configuration: built-in defaults overlaid by the user's TOML file.""" + +import copy +import os +import tomllib + +DEFAULTS = { + "remote": {"target": "buildsystem", "ssh_options": []}, + "refresh": {"dashboard": 30, "jobs": 5}, + "notify": {"enabled": True, "events": ["finished", "failed", "killed", "lost", "vm-up"]}, + "vm": {"libvirt_uri": "qemu:///system", "domain": "buildsystem", "autostart": False}, +} + + +def path(): + base = os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser("~/.config") + return os.path.join(base, "sb-builder", "config.toml") + + +def load(p=None): + """Return (config, error). On any problem: the defaults plus the error text.""" + p = p or path() + try: + with open(p, "rb") as f: + data = tomllib.load(f) + except FileNotFoundError: + return copy.deepcopy(DEFAULTS), None + except (OSError, tomllib.TOMLDecodeError) as e: + return copy.deepcopy(DEFAULTS), f"{p}: {e}" + cfg = copy.deepcopy(DEFAULTS) + for sec, keys in data.items(): + if sec not in DEFAULTS or not isinstance(keys, dict): + return copy.deepcopy(DEFAULTS), f"{p}: unknown section [{sec}]" + for k, v in keys.items(): + if k not in DEFAULTS[sec]: + return copy.deepcopy(DEFAULTS), f"{p}: unknown key {sec}.{k}" + want = type(DEFAULTS[sec][k]) + if type(v) is not want: + return copy.deepcopy(DEFAULTS), f"{p}: {sec}.{k}: expected {want.__name__}" + cfg[sec][k] = v + return cfg, None |
