feat(config): Config loading and merging

This commit is contained in:
2026-05-03 15:09:05 +02:00
parent 190fb86758
commit 7b1dfe6ebc
9 changed files with 176 additions and 37 deletions
+49 -2
View File
@@ -12,20 +12,67 @@ def _load_config_file(file: str):
return parsed
def default_config() -> ArchMgrConfig:
return {
"pkgs": {
"individual": [],
"bundles": [],
"repos": {
"enabled_repos": [
{
"name": "core",
"setup_cmds": [],
"mirrors": {"use_default": True, "extra_mirrors": []},
}
],
"reflector": {
"enabled": False,
"count": 0,
"countries": [],
"interval": 1,
},
},
},
"boot": {
"managed": False,
"bootloader": "grub",
"esp_dir": "/boot",
"os_prober": False,
"theme_folder": "/usr/share/themes/grub",
},
"cmds": {"always": [], "once": []},
"git": {
"repos": [],
"creds": {"manager": "git-credential-manager"},
},
"users": [],
"symlinks": [],
"template_data": [],
"themes": {
"cursor_theme": "oreo_spark_blue_cursor",
"font": "Comfortaa 11",
"gtk": "Adaptive-Theme",
"qt": "gtk3",
"icon_theme": "candy-icons"
},
}
def load_config(file: str) -> ArchMgrConfig:
# Load and validate initial config
try:
loaded_conf = _load_config_file(file)
except Exception:
return {}
return default_config()
if not validator.validate(loaded_conf):
return {}
return default_config()
configuration = cast(dict[str, Any], loaded_conf)
requires = cast(list[str], configuration.pop("requires"))
conf = cast(ArchMgrConfig, configuration)
# Recursively load files
print("Requires", requires)
for conf_file in requires:
conf = merge_configs(conf, load_config(conf_file))
+14 -8
View File
@@ -1,17 +1,23 @@
from typing import TypedDict
from typing import Optional, TypedDict
from config.dtype.cmds import ArchMgrCmdsConfig
from config.dtype.git import ArchMgrGitConfig
from config.dtype.others import ArchMgrBootConfig, ArchMgrSymlinkConfig, ArchMgrTemplateData, ArchMgrThemeConfig, ArchMgrUserConfig
from config.dtype.others import (
ArchMgrBootConfig,
ArchMgrSymlinkConfig,
ArchMgrTemplateData,
ArchMgrThemeConfig,
ArchMgrUserConfig,
)
from config.dtype.pkgs import ArchMgrPkgConfig
class ArchMgrConfig(TypedDict):
pkgs: ArchMgrPkgConfig
users: list[ArchMgrUserConfig]
users: Optional[list[ArchMgrUserConfig]]
boot: ArchMgrBootConfig
themes: ArchMgrThemeConfig
git: ArchMgrGitConfig
template_data: list[ArchMgrTemplateData]
symlinks: list[ArchMgrSymlinkConfig]
cmds: ArchMgrCmdsConfig
themes: Optional[ArchMgrThemeConfig]
git: Optional[ArchMgrGitConfig]
template_data: Optional[list[ArchMgrTemplateData]]
symlinks: Optional[list[ArchMgrSymlinkConfig]]
cmds: Optional[ArchMgrCmdsConfig]
+2 -2
View File
@@ -2,8 +2,8 @@ from typing import Optional, TypedDict
class ArchMgrCmdsConfig(TypedDict):
always: list[ArchMgrCommand]
once: list[ArchMgrCommand]
always: Optional[list[ArchMgrCommand]]
once: Optional[list[ArchMgrCommand]]
class ArchMgrCommand(TypedDict):
+4 -4
View File
@@ -1,13 +1,13 @@
from typing import TypedDict
from typing import Optional, TypedDict
class ArchMgrGitConfig(TypedDict):
creds: ArchMgrGitCredsConfig
repos: list[ArchMgrGitRepoConfig]
creds: Optional[ArchMgrGitCredsConfig]
repos: Optional[list[ArchMgrGitRepoConfig]]
class ArchMgrGitCredsConfig(TypedDict):
manager: str
manager: Optional[str]
class ArchMgrGitRepoConfig(TypedDict):
+13 -13
View File
@@ -1,27 +1,27 @@
from typing import TypedDict
from typing import Optional, TypedDict
class ArchMgrUserConfig(TypedDict):
username: str
groups: list[str]
home_dir: bool
sudo_user: bool
groups: Optional[list[str]]
home_dir: Optional[bool]
sudo_user: Optional[bool]
class ArchMgrBootConfig(TypedDict):
managed: bool
bootloader: str
esp_dir: str
theme_folder: str
os_prober: bool
bootloader: Optional[str]
esp_dir: Optional[str]
theme_folder: Optional[str]
os_prober: Optional[bool]
class ArchMgrThemeConfig(TypedDict):
gtk: str
qt: str
font: str
icon_theme: str
cursor_theme: str
gtk: Optional[str]
qt: Optional[str]
font: Optional[str]
icon_theme: Optional[str]
cursor_theme: Optional[str]
class ArchMgrTemplateData(TypedDict):
+5 -5
View File
@@ -2,14 +2,14 @@ from typing import Optional, TypedDict
class ArchMgrPkgConfig(TypedDict):
individual: list[str]
repos: ArchMgrReposConfig
bundles: list[ArchMgrBundleConfig]
individual: Optional[list[str]]
repos: Optional[ArchMgrReposConfig]
bundles: Optional[list[ArchMgrBundleConfig]]
class ArchMgrReposConfig(TypedDict):
enabled_repos: list[ArchMgrRepoSettings]
reflector: ArchMgrReflectorConfig
enabled_repos: Optional[list[ArchMgrRepoSettings]]
reflector: Optional[ArchMgrReflectorConfig]
class ArchMgrReflectorConfig(TypedDict):
+28 -2
View File
@@ -1,3 +1,4 @@
from typing import cast
from config.dtype import ArchMgrConfig
@@ -5,5 +6,30 @@ def merge_configs(config: ArchMgrConfig, new_config: ArchMgrConfig) -> ArchMgrCo
if len(new_config) == 0 or len(config) == 0:
return config
# Merge configs
return config
def combine(a: dict, b: dict):
combined = {}
for key in b:
val = b[key]
try:
a[key]
if isinstance(val, dict):
combined[key] = combine(val, a[key])
elif isinstance(val, list):
combined[key] = val
for v in a[key]:
combined[key].append(v)
else:
combined[key] = val
except KeyError:
combined[key] = val
for key in a:
try:
b[key]
except KeyError:
combined[key] = a[key]
return combined
# Merge configs (using nasty casts)
return cast(ArchMgrConfig, combine(cast(dict, config), cast(dict, new_config)))