feat(config): Config loading and merging
This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
# yaml-language-server: $schema=config.schema.json
|
||||||
|
# TODO: Change the above to an import URL instead
|
||||||
|
requires:
|
||||||
|
- path/to/other/configs/relative/to/this # Reads the other configs after finishing this one
|
||||||
|
|
||||||
|
pkgs:
|
||||||
|
individual:
|
||||||
|
- pkg_name
|
||||||
|
bundles:
|
||||||
|
- name: hyprland
|
||||||
|
repos:
|
||||||
|
reflector:
|
||||||
|
enabled: false
|
||||||
|
countries:
|
||||||
|
- Switzerland
|
||||||
|
|
||||||
|
users:
|
||||||
|
- username: username
|
||||||
|
groups:
|
||||||
|
- group_1
|
||||||
|
home_dir: True
|
||||||
|
|
||||||
|
boot:
|
||||||
|
managed: True
|
||||||
|
bootloader: grub
|
||||||
|
esp_dir: /boot/
|
||||||
|
theme_folder: ~/.path/to/theme/
|
||||||
|
os_prober: False
|
||||||
|
# Also copies over the /etc/default/grub config or equivalent for other supported bootloaders
|
||||||
|
|
||||||
|
# TODO: Desktops, login managers, full disk encryption etc configuration?
|
||||||
|
|
||||||
|
themes:
|
||||||
|
gtk: theme_name
|
||||||
|
qt: theme_name # or use_gtk to use the gtk theme instaed
|
||||||
|
font: Comfortaa 11 # the font name to be used (also needs to be installed)
|
||||||
|
icon_theme: candy-icons # The icon theme to use (also needs to be installed)
|
||||||
|
cursor_theme: oreo_spark_blue_cursors # TODO: Consider if GTK settings file should just be copied
|
||||||
|
|
||||||
|
git:
|
||||||
|
creds:
|
||||||
|
manager: git-credential-manager # or none
|
||||||
|
repos:
|
||||||
|
- url: https://github.com/janishutz/janishutz
|
||||||
|
clone_path: ~/projects/ # Project location will be clone_path/<repo name>
|
||||||
|
- url: git@git.janishutz.com:janishutz/nvim
|
||||||
|
clone_path: ~/projects/ # Project location will be clone_path/<repo name>
|
||||||
|
|
||||||
|
template_data:
|
||||||
|
- name: template_data_name
|
||||||
|
data: the_data
|
||||||
|
|
||||||
|
cmds:
|
||||||
|
always:
|
||||||
|
- cmd: "cmd to run every time archmgr is run"
|
||||||
|
once:
|
||||||
|
- name: "cmd1"
|
||||||
|
cmd: "cmd to run on first execution of archmgr (or if not executed previously)"
|
||||||
+3
-1
@@ -1,7 +1,8 @@
|
|||||||
# yaml-language-server: $schema=config.schema.json
|
# yaml-language-server: $schema=config.schema.json
|
||||||
# TODO: Change the above to an import URL instead
|
# TODO: Change the above to an import URL instead
|
||||||
requires:
|
requires:
|
||||||
- path/to/other/configs/relative/to/this # Reads the other configs after finishing this one
|
- ./config-include-test.yml # Reads the other configs after finishing this one
|
||||||
|
# - path/to/other/configs/relative/to/this # Reads the other configs after finishing this one
|
||||||
|
|
||||||
pkgs:
|
pkgs:
|
||||||
individual:
|
individual:
|
||||||
@@ -21,6 +22,7 @@ users:
|
|||||||
home_dir: True
|
home_dir: True
|
||||||
|
|
||||||
boot:
|
boot:
|
||||||
|
managed: True
|
||||||
bootloader: grub
|
bootloader: grub
|
||||||
esp_dir: /boot/
|
esp_dir: /boot/
|
||||||
theme_folder: ~/.path/to/theme/
|
theme_folder: ~/.path/to/theme/
|
||||||
|
|||||||
+49
-2
@@ -12,20 +12,67 @@ def _load_config_file(file: str):
|
|||||||
return parsed
|
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:
|
def load_config(file: str) -> ArchMgrConfig:
|
||||||
# Load and validate initial config
|
# Load and validate initial config
|
||||||
try:
|
try:
|
||||||
loaded_conf = _load_config_file(file)
|
loaded_conf = _load_config_file(file)
|
||||||
except Exception:
|
except Exception:
|
||||||
return {}
|
return default_config()
|
||||||
if not validator.validate(loaded_conf):
|
if not validator.validate(loaded_conf):
|
||||||
return {}
|
return default_config()
|
||||||
|
|
||||||
configuration = cast(dict[str, Any], loaded_conf)
|
configuration = cast(dict[str, Any], loaded_conf)
|
||||||
requires = cast(list[str], configuration.pop("requires"))
|
requires = cast(list[str], configuration.pop("requires"))
|
||||||
conf = cast(ArchMgrConfig, configuration)
|
conf = cast(ArchMgrConfig, configuration)
|
||||||
|
|
||||||
# Recursively load files
|
# Recursively load files
|
||||||
|
print("Requires", requires)
|
||||||
for conf_file in requires:
|
for conf_file in requires:
|
||||||
conf = merge_configs(conf, load_config(conf_file))
|
conf = merge_configs(conf, load_config(conf_file))
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
from typing import TypedDict
|
from typing import Optional, TypedDict
|
||||||
|
|
||||||
from config.dtype.cmds import ArchMgrCmdsConfig
|
from config.dtype.cmds import ArchMgrCmdsConfig
|
||||||
from config.dtype.git import ArchMgrGitConfig
|
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
|
from config.dtype.pkgs import ArchMgrPkgConfig
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrConfig(TypedDict):
|
class ArchMgrConfig(TypedDict):
|
||||||
pkgs: ArchMgrPkgConfig
|
pkgs: ArchMgrPkgConfig
|
||||||
users: list[ArchMgrUserConfig]
|
users: Optional[list[ArchMgrUserConfig]]
|
||||||
boot: ArchMgrBootConfig
|
boot: ArchMgrBootConfig
|
||||||
themes: ArchMgrThemeConfig
|
themes: Optional[ArchMgrThemeConfig]
|
||||||
git: ArchMgrGitConfig
|
git: Optional[ArchMgrGitConfig]
|
||||||
template_data: list[ArchMgrTemplateData]
|
template_data: Optional[list[ArchMgrTemplateData]]
|
||||||
symlinks: list[ArchMgrSymlinkConfig]
|
symlinks: Optional[list[ArchMgrSymlinkConfig]]
|
||||||
cmds: ArchMgrCmdsConfig
|
cmds: Optional[ArchMgrCmdsConfig]
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ from typing import Optional, TypedDict
|
|||||||
|
|
||||||
|
|
||||||
class ArchMgrCmdsConfig(TypedDict):
|
class ArchMgrCmdsConfig(TypedDict):
|
||||||
always: list[ArchMgrCommand]
|
always: Optional[list[ArchMgrCommand]]
|
||||||
once: list[ArchMgrCommand]
|
once: Optional[list[ArchMgrCommand]]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrCommand(TypedDict):
|
class ArchMgrCommand(TypedDict):
|
||||||
|
|||||||
+4
-4
@@ -1,13 +1,13 @@
|
|||||||
from typing import TypedDict
|
from typing import Optional, TypedDict
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrGitConfig(TypedDict):
|
class ArchMgrGitConfig(TypedDict):
|
||||||
creds: ArchMgrGitCredsConfig
|
creds: Optional[ArchMgrGitCredsConfig]
|
||||||
repos: list[ArchMgrGitRepoConfig]
|
repos: Optional[list[ArchMgrGitRepoConfig]]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrGitCredsConfig(TypedDict):
|
class ArchMgrGitCredsConfig(TypedDict):
|
||||||
manager: str
|
manager: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrGitRepoConfig(TypedDict):
|
class ArchMgrGitRepoConfig(TypedDict):
|
||||||
|
|||||||
+13
-13
@@ -1,27 +1,27 @@
|
|||||||
from typing import TypedDict
|
from typing import Optional, TypedDict
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrUserConfig(TypedDict):
|
class ArchMgrUserConfig(TypedDict):
|
||||||
username: str
|
username: str
|
||||||
groups: list[str]
|
groups: Optional[list[str]]
|
||||||
home_dir: bool
|
home_dir: Optional[bool]
|
||||||
sudo_user: bool
|
sudo_user: Optional[bool]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrBootConfig(TypedDict):
|
class ArchMgrBootConfig(TypedDict):
|
||||||
managed: bool
|
managed: bool
|
||||||
bootloader: str
|
bootloader: Optional[str]
|
||||||
esp_dir: str
|
esp_dir: Optional[str]
|
||||||
theme_folder: str
|
theme_folder: Optional[str]
|
||||||
os_prober: bool
|
os_prober: Optional[bool]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrThemeConfig(TypedDict):
|
class ArchMgrThemeConfig(TypedDict):
|
||||||
gtk: str
|
gtk: Optional[str]
|
||||||
qt: str
|
qt: Optional[str]
|
||||||
font: str
|
font: Optional[str]
|
||||||
icon_theme: str
|
icon_theme: Optional[str]
|
||||||
cursor_theme: str
|
cursor_theme: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrTemplateData(TypedDict):
|
class ArchMgrTemplateData(TypedDict):
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ from typing import Optional, TypedDict
|
|||||||
|
|
||||||
|
|
||||||
class ArchMgrPkgConfig(TypedDict):
|
class ArchMgrPkgConfig(TypedDict):
|
||||||
individual: list[str]
|
individual: Optional[list[str]]
|
||||||
repos: ArchMgrReposConfig
|
repos: Optional[ArchMgrReposConfig]
|
||||||
bundles: list[ArchMgrBundleConfig]
|
bundles: Optional[list[ArchMgrBundleConfig]]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrReposConfig(TypedDict):
|
class ArchMgrReposConfig(TypedDict):
|
||||||
enabled_repos: list[ArchMgrRepoSettings]
|
enabled_repos: Optional[list[ArchMgrRepoSettings]]
|
||||||
reflector: ArchMgrReflectorConfig
|
reflector: Optional[ArchMgrReflectorConfig]
|
||||||
|
|
||||||
|
|
||||||
class ArchMgrReflectorConfig(TypedDict):
|
class ArchMgrReflectorConfig(TypedDict):
|
||||||
|
|||||||
+28
-2
@@ -1,3 +1,4 @@
|
|||||||
|
from typing import cast
|
||||||
from config.dtype import ArchMgrConfig
|
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:
|
if len(new_config) == 0 or len(config) == 0:
|
||||||
return config
|
return config
|
||||||
|
|
||||||
# Merge configs
|
def combine(a: dict, b: dict):
|
||||||
return config
|
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)))
|
||||||
|
|||||||
Reference in New Issue
Block a user