1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# deck-it - configuration loading and validation
# 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.
"""Configuration loading and validation for deck-it."""
import os
import re
import sys
import tomllib
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
MONITOR_NAME = re.compile(r"[A-Za-z0-9_-]{1,32}")
def user_config_path() -> Path:
return Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "deck-it" / "config.toml"
def config_error(cfg: dict) -> str | None:
d, ports = cfg.get("display", {}), cfg.get("ports", {})
if not MONITOR_NAME.fullmatch(str(d.get("name", "TAB"))):
return "display.name must be letters, digits, - or _"
refresh = d.get("refresh", 60)
if not isinstance(refresh, int) or not 1 <= refresh <= 240:
return "display.refresh must be a number from 1 to 240"
for key in ("command_center", "display"):
if key in ports:
v = ports[key]
if not isinstance(v, int) or not 1024 <= v <= 65535:
return f"ports.{key} must be a number from 1024 to 65535"
if ports.get("command_center", 8765) == ports.get("display", 5900):
return "ports.command_center and ports.display must differ"
return None
def load_config() -> dict:
path = user_config_path() if user_config_path().is_file() else ROOT / "config.toml"
with open(path, "rb") as f:
cfg = tomllib.load(f)
if err := config_error(cfg):
sys.exit(f"{path}: {err}")
return cfg
|