Files
2026-03-15 10:07:01 +01:00

163 lines
4.0 KiB
Python
Executable File

#!/usr/bin/env python3
import subprocess
import shutil
from argparse import ArgumentParser
from pathlib import Path
BASE_PKGS = [
"clang", # C/C++ development
"scripts", # scripts & snippets
"stow", # --target=~
]
# for TUI only setups
# e.g. servers that are accessed via SSH only
TUI_PKGS = [
*BASE_PKGS,
"fastfetch", # sys info,
"helix", # editor
"nvim", # editor
"shell", # fish & .bash_profile & shell prompt
"yazi", # terminal file manager
]
# for all WMs and DEs
GUI_BASE_PKGS = [
*TUI_PKGS,
"cava",
"kitty", # terminal emulator
"ghostty", # alternative terminal emulator
"misc", # miscellaneous GUI configs (e.g. *-flags)
# "mpv", # media player
"wallpaper", # wallpapers & manager
"kvantum", # qt theming
"nwg-look", # gtk theming
"wezterm", # alternative terminal emulator
]
# for Hyprland setup
# HYPRLAND_PKGS = [
# *GUI_BASE_PKGS,
# "eww", # widgets
# "hypr", # hypr family
# "hyprland", # wm config
# "mako", # notifications
# "rofi", # application launcher
# "waybar", # status bar
# "wlogout", # logout menu
# ]
# for Niri setup
NIRI_PKGS = [
*GUI_BASE_PKGS,
"hypr", # for hyprlock & hypridle
"niri", # wm config
"quickshell", # widgets & status bar & notifications & ...
"rofi", # application launcher
"wlogout", # logout menu
]
PKGS = {
"base": BASE_PKGS,
"tui": TUI_PKGS,
"gui": GUI_BASE_PKGS,
# "hyprland": HYPRLAND_PKGS,
"niri": NIRI_PKGS,
}
SESSION_NAME = {
"hyprland": "Hyprland",
"niri": "niri",
"default": "default",
}
PKGS_PATH = Path(__file__).resolve().parent.resolve() / "config"
DEST_PATH = Path.home().expanduser()
def _log(level: str, message: str):
color = (
"\033[92m" if level == "INFO" else "\033[91m" if level == "ERROR" else "\033[0m"
)
reset = "\033[0m"
print(f"{color}[{level}] {message}{reset}")
def check_deps() -> bool:
required_deps = ["stow"]
for dep in required_deps:
if not shutil.which(dep):
_log("ERROR", f"Required dependency '{dep}' is not installed.")
return False
return True
def stow(pkg: str):
subprocess.run(
["stow", "-v", "-d", str(PKGS_PATH), "-t", str(DEST_PATH), pkg], check=True
)
def unstow(pkg: str):
subprocess.run(
["stow", "-v", "-d", str(PKGS_PATH), "-t", str(DEST_PATH), "-D", pkg], check=True,
)
def switch(session: str):
subprocess.run(
[str(Path("~/.local/scripts/config-switch").expanduser()), session], check=True
)
def main():
if not check_deps():
exit(1)
parser = ArgumentParser(
description="Stow configuration packages in this repository."
)
parser.add_argument(
"package", choices=PKGS.keys(), help="The configuration package group to stow."
)
parser.add_argument(
"--unstow",
action="store_true",
help="Unstow the specified package group instead of stowing it.",
)
args = parser.parse_args()
selected_pkgs = PKGS[args.package]
is_unstow = args.unstow
for pkg in selected_pkgs:
try:
if is_unstow:
unstow(pkg)
_log("INFO", f"Successfully unstowed package '{pkg}'.")
else:
stow(pkg)
_log("INFO", f"Successfully stowed package '{pkg}'.")
except subprocess.CalledProcessError as e:
_log("ERROR", f"Failed to stow package '{pkg}': {e}")
if is_unstow:
return # No need to switch session if we're just unstowing
if args.package in SESSION_NAME:
session = SESSION_NAME[args.package]
else:
session = SESSION_NAME["default"]
try:
switch(session)
_log("INFO", f"Switched to session profile '{session}'.")
except subprocess.CalledProcessError as e:
_log("ERROR", f"Failed to switch session profile '{session}': {e}")
if __name__ == "__main__":
main()