161 Commits
Author SHA1 Message Date
DragonSlayer_14andClaude Sonnet 5 4b8299fede Fix: XanMod-Repo-Suite "releases" existiert nicht mehr
deb.xanmod.org/dists/releases liefert 404; das Repository ist mittlerweile
pro Debian-Codename organisiert (sid, trixie, bookworm, ...). Da dieses
Framework Debian Unstable (Sid) als Zielsystem hat, wird jetzt direkt die
Suite "sid" verwendet (per curl gegen deb.xanmod.org verifiziert).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 23:01:05 +02:00
DragonSlayer_14andClaude Sonnet 5 7296489c11 Feature: Optionale Verlegung des Mesa/DXVK-Shader-Caches
Neue Variable SHADER_CACHE_DIR in config/setup.conf erlaubt es, den
Mesa- (RADV/OpenGL) und DXVK-Shader-Cache (Wine/Proton) auf einen
separaten Speicherort zu verlegen, um Nachcompilierungs-Ruckler nach
Neustarts zu vermeiden. Standardmäßig leer, damit kein hartkodierter
Pfad (z. B. /mnt/Data) vorausgesetzt wird - ohne Angabe bleiben Mesa
und DXVK bei ihren eigenen, überall vorhandenen Cache-Pfaden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 22:53:36 +02:00
DragonSlayer_14andClaude Sonnet 5 7932bb2482 Feature: vkBasalt Vulkan-Postprocessing integriert
Rollt vkBasalt (inkl. 32-Bit-Variante für Proton/Wine) mit einer
vorkonfigurierten Contrast-Adaptive-Sharpening-Config aus. Der MangoHud-
Overlay zeigt den Aktivierungsstatus mit an; Aktivierung erfolgt pro
Spiel über die Steam-Launch-Option ENABLE_VKBASALT=1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 22:52:36 +02:00
DragonSlayer_14andClaude Sonnet 5 0cc710f997 Feature: sched-ext Gaming-Scheduler (scx_lavd) aktiviert
Installiert scx-scheds aus dem bereits konfigurierten XanMod-Repository
und aktiviert den für Gaming/interaktive Desktop-Workloads gebauten
Latency-criticality Aware Virtual Deadline Scheduler im Autopilot-Modus.
Benötigt einen Kernel mit CONFIG_SCHED_CLASS_EXT (bei XanMod bereits
aktiv); nach frischer Kernel-Installation ggf. Neustart nötig.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 22:51:29 +02:00
DragonSlayer_14andClaude Sonnet 5 fec46ef46f Feature: systemd-oomd gegen Einfrieren bei Speicherdruck aktiviert
Ergänzt das bestehende zram-Swap um einen modernen, cgroup-v2/PSI-
basierten Out-of-Memory-Schutz, um Systemfreezes bei gleichzeitiger
Speicher-/Swap-Auslastung (z. B. Spiel + Discord + Browser) zu
verhindern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 22:50:54 +02:00
DragonSlayer_14andClaude Sonnet 5 287e4d815b Feature: GameMode-Tuning, MangoHud-Default & CoreCtrl für Gaming-Setup
Deployt eine getunte /etc/gamemode.ini (Performance-Governor, Renice,
I/O-Priorität, AMD-GPU-Performance-Level) und ergänzt den Zielbenutzer
um die Gruppen render/gamemode. MangoHud erhält ein vorkonfiguriertes
Overlay über den bestehenden Skel-Sync. CoreCtrl wird installiert und
per PolicyKit-Regel ohne wiederholte Passwortabfrage für sudo-Mitglieder
freigegeben.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 22:23:29 +02:00
DragonSlayer_14andClaude Sonnet 5 c1f3851086 Feature: Bei fehlgeschlagenem Befehl Wiederholen/Ignorieren/Abbrechen abfragen
Der ERR-Trap fragt den Benutzer nun interaktiv, wie mit einem
fehlgeschlagenen Befehl verfahren werden soll, statt die Installation
sofort abzubrechen. Zusätzlich aktiviert setup_err_trap jetzt
errtrace/functrace, damit Fehler auch innerhalb von lib/*.sh-Funktionen
abgefangen werden statt das Skript stillschweigend zu beenden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:54:47 +02:00
DragonSlayer_14andClaude Sonnet 5 0bf2e81063 Fix: Ollama-eigenen Standardpfad statt /mnt/Data als Vorschlag anbieten
Bisher wurde in allen drei Dialogvarianten (whiptail-Yesno, whiptail-
Inputbox, CLI-Fallback) derselbe konfigurierte Pfad
(/mnt/Data/Software/ollama/models) sowohl als "Standard" beworben als
auch als vorausgefüllter Eingabewert verwendet - der tatsächliche
Ollama-Standardspeicherort kam nie zum Zug.

prompt_ollama_models_path() unterscheidet jetzt zwischen dem echten
Ollama-Standardpfad (/usr/share/ollama/.ollama/models, verwendet vom
offiziellen Installationsskript / systemd-Dienst) und dem in
OLLAMA_MODELS_DEFAULT konfigurierten Pfadvorschlag. Letzterer wird nur
noch als Vorbelegung im Eingabefeld angezeigt, nachdem der Standardpfad
explizit abgelehnt wurde.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:37:27 +02:00
DragonSlayer_14andClaude Sonnet 5 950eb5d361 Refactor: Verschachtelung im Ollama-Speicherort-Dialog reduziert
Der whiptail-Zweig verschachtelte vier Ebenen tief und verteilte drei
identische chosen="$default_path"-Zuweisungen über if/else-Paare, um
eine einzige lineare Entscheidung abzubilden. Die Ja/Nein-Abfrage und
der Eingabedialog folgen jetzt beide dem Guard-Clause-Muster
(if [[ -z "$chosen" ]]; then ... fi), das bereits für den CLI-Fallback
weiter unten in derselben Funktion verwendet wird.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:33:48 +02:00
DragonSlayer_14andClaude Sonnet 5 9278241dd0 Refactor: Ja/Nein-Abfrage in gemeinsame Hilfsfunktion ausgelagert
prompt_target_user und prompt_ollama_models_path implementierten die
gleiche CLI-Ja/Nein-Abfrage (read + Trim + Regex-Prüfung) unabhängig
voneinander. Beide Kopien waren bereits leicht auseinandergelaufen
(unterschiedliches Fallback-Zeichen, unterschiedliche Regex-
Reihenfolge). confirm_yes_no() bündelt die Logik an einer Stelle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:32:42 +02:00
DragonSlayer_14andClaude Sonnet 5 1fa3770e6e Fix: ESC im Ollama-Speicherort-Dialog fällt auf Standardpfad zurück
whiptail liefert bei ESC den Exit-Code 255, der bisher wie ein
explizites "Nein" (Exit-Code 1) behandelt und in den Eingabedialog für
einen eigenen Pfad geleitet wurde. Das widersprach dem direkt
folgenden Eingabedialog, in dem ESC/Abbruch stattdessen den
Standardpfad übernimmt. ESC verhält sich jetzt in beiden Dialogen
gleich.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:31:53 +02:00
DragonSlayer_14andClaude Sonnet 5 775b03e9de Fix: Trimmen der Ja/Nein-Antwort per xargs durch sed ersetzt
xargs interpretiert Anführungszeichen/Backslashes in der Eingabe und
schlägt bei ungültiger Eingabe mit leerer Ausgabe fehl. Das ließ eine
eigentlich verneinende Antwort fälschlich als "Ja" (Standardpfad)
durchgehen. sed wird bereits an allen anderen Trim-Stellen in dieser
Funktion verwendet und kennt dieses Fehlverhalten nicht.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:31:38 +02:00
DragonSlayer_14andClaude Sonnet 5 d9ec12dba3 Feat: Bestätigungsabfrage vor Ollama-Speicherort-Dialog hinzufügen
prompt_ollama_models_path() fragt jetzt zuerst per Ja/Nein, ob der
konfigurierte Standard-Speicherort (OLLAMA_MODELS_DEFAULT) verwendet werden
soll - analog zum bestehenden Muster in tui_prompt_target_user(). Nur bei
"Eigenen Pfad angeben" erscheint der Eingabedialog, vorbelegt mit genau
diesem Standardpfad. Gilt für whiptail-TUI und den CLI-Fallback gleichermaßen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:15:29 +02:00
DragonSlayer_14andClaude Sonnet 5 1723803e9c Feat: Linutil als letzten Install-Schritt (Stage 11) hinzufügen
Ergänzt stages/11-linutil.sh, das Linutil (Chris Titus Tech System Toolbox,
curl -fsSL https://christitus.com/linux | sh) als Zielbenutzer ausführt -
analog zum bestehenden Hyprland-Installer-Muster in Stage 10, da Linutil
selbst per sudo eskaliert wo nötig. Überspringt sich mit klarer Meldung,
falls kein Terminal verfügbar ist, statt an der interaktiven TUI zu hängen.

--all läuft jetzt 00 bis 11, die whiptail-Checklist sowie Hilfetext,
README.md und AGENTS.md wurden entsprechend ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:07:22 +02:00
DragonSlayer_14andClaude Sonnet 5 2e470d676d Feat: Claude Code & Awesome LLM Skills zur Ersteinrichtung hinzufügen
Ergänzt die bestehende Ersteinrichtung (Dotfiles, Oh-My-Zsh, JetBrains Junie)
um zwei weitere Schritte, analog zum bereits vorhandenen Junie-Muster:

- setup-claude-cli.sh installiert Claude Code über den offiziellen nativen
  Installer (curl -fsSL https://claude.ai/install.sh | bash).
- setup-claude-skills.sh klont/aktualisiert Awesome LLM Skills
  (https://github.com/Prat011/awesome-llm-skills) nach
  ~/.claude/skills/awesome-llm-skills und verlinkt alle Unterordner mit
  SKILL.md direkt nach ~/.claude/skills, damit Claude Code sie erkennt.

first-login-setup.sh ruft beide Schritte zusätzlich auf; Beschreibungen im
systemd-Service und in stages/10-hyprland.sh entsprechend erweitert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 21:02:49 +02:00
DragonSlayer_14andClaude Sonnet 5 8761e1c673 Fix: Ersteinrichtung (Dotfiles, Zsh, Junie) in klare Skripte aufgeteilt und von Hyprland entkoppelt
Das bisherige install-dots-prompt.sh vereinte Dotfiles-Auswahl, Oh-My-Zsh,
JetBrains Junie CLI und AwesomeJunieSkills in einem Skript und wurde per
exec-once direkt von Hyprland gestartet.

Aufgeteilt in eigenständige Skripte (setup-dotfiles.sh, setup-shell.sh,
setup-junie-cli.sh, setup-junie-skills.sh) mit gemeinsamer first-login-setup.sh
als Orchestrator. Systemweit unter /usr/local/lib/first-login-setup installiert
(eine Kopie für alle Nutzer statt Duplikate pro Home) und über einen global
aktivierten systemd --user Service (/etc/systemd/user/) gestartet - bewusst
nicht über hyprland.conf, damit es unabhängig vom gewählten Compositor
funktioniert und Hyprland selbst es nicht mehr ausführt. Der Service sucht das
Wayland-Socket eigenständig, statt sich auf importierte Umgebungsvariablen zu
verlassen, und wiederholt sich bei Bedarf bis die grafische Sitzung bereit ist.

Der Fortschritt liegt in ~/.local/state/first-login-setup (statt ~/.config),
da setup-dotfiles.sh ~/.config komplett durch ein eigenes Dotfiles-Repository
ersetzen kann - das darf den Fortschritt nicht mit sich reißen. Zusätzlich
fragt das Skript jetzt explizit "Jetzt/Später": nur bei "Jetzt" wird der
Marker gesetzt, bei "Später" wird beim nächsten Login erneut gefragt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 20:58:20 +02:00
DragonSlayer_14andClaude Sonnet 5 5a8dd73d32 Fix: whiptail-TUI reagiert nicht auf Tastatureingaben bei curl | bash
sudo, aus einer nicht-interaktiven gepipten Shell heraus aufgerufen, gibt die
Terminal-Vordergrundgruppe nicht zuverlässig an den Kindprozess weiter.
setup.sh lief bisher komplett (inkl. aller whiptail-Dialoge) innerhalb von
sudo, wodurch das Menü zwar sichtbar war, aber keine Tasten mehr ankamen.

setup.sh fragt jetzt alle interaktiven Eingaben (Stage-Auswahl, Zielbenutzer,
Ollama-Pfad) zuerst als normaler Nutzer ab und eskaliert erst danach per
exec sudo, wobei die bereits getroffenen Entscheidungen als Flags/Env-Variablen
durchgereicht werden. install.sh eskaliert dadurch nicht mehr selbst.
Zusätzlich wird die fehlerhafte "-c /dev/tty"-Interaktivitätsprüfung
(prüfte nur Existenz der Gerätedatei, nicht ob ein Terminal verbunden ist)
durch has_tty() ersetzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WMUd2fGsPCtTCVQkSS5TA
2026-09-06 20:31:54 +02:00
DragonSlayer_14andJunie 116a33a876 fix(tui): bind whiptail dialogs to controlling terminal
Interactive stage selection did not receive any keyboard input when the
setup was started through a pipe (curl ... | bash), because the dialogs
inherited the pipe as stdin/stdout and ENTER/SPACE went to the shell.

- lib/utils.sh: add has_tty, ensure_term, get_term_size and a run_whiptail
  wrapper that binds dialog I/O to /dev/tty and returns results via
  --output-fd 3
- lib/tui.sh: run all dialogs through run_whiptail, add tui_is_available
  and tui_calc_geometry to clamp dialog geometry to the terminal size
- setup.sh: re-attach stdin/stdout to /dev/tty when piped, normalize TERM
  and use has_tty for the interactive check
- install.sh: reconnect stdout as well and normalize TERM before running
  setup.sh

Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 17:37:59 +02:00
DragonSlayer_14andJunie e87342d3b7 fix(install): reconnect stdin to tty for interactive TUI in piped execution
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 17:16:50 +02:00
DragonSlayer_14andJunie c219988011 fix(install): use direct process redirection to /dev/tty for setup child process
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 17:05:59 +02:00
DragonSlayer_14andJunie 174014cae0 fix(tui): fix whiptail dialog progression, output descriptor handling and terminal scaling
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 16:54:17 +02:00
DragonSlayer_14andJunie 2f02c1b74a fix(tui): fix initial dialog interaction and user detection in interactive mode
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 16:30:28 +02:00
DragonSlayer_14andJunie f093cce7dc fix(install): prevent stdin stream truncation when running via pipe
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 16:13:51 +02:00
DragonSlayer_14andJunie 85408020c6 Feat: Automatische Konfiguration aller LAN-Schnittstellen und Loopback im Debian-Installer-Standard
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 15:56:54 +02:00
DragonSlayer_14andJunie c35f49d9fc Add install.sh web installer bootstrap script for curl one-liner execution
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 15:31:06 +02:00
DragonSlayer_14andJunie 37a2c49855 feat(bootloader): add grub-btrfs snapshot boot support
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 15:19:23 +02:00
DragonSlayer_14andJunie 74803cd258 Feat: Automatische Timeshift Boot- und APT-Update-Snapshots sowie Retention-Limit konfiguriert
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 15:06:24 +02:00
DragonSlayer_14andJunie d0f88a3608 Feat: Automatische Timeshift Btrfs-Snapshots an kritischen Meilensteinen integriert
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 14:53:37 +02:00
DragonSlayer_14andJunie 5889acd1e3 Feat: Automatische Btrfs-Root-Erkennung und Subvolume-Migration (@, @home) hinzugefügt
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 14:44:24 +02:00
DragonSlayer_14andJunie a949899168 Docs: Schnellstart-One-Liner zum Klonen und Ausführen zu README.md hinzugefügt
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 13:40:20 +02:00
DragonSlayer_14andJunie 20d4952740 Refactor: Aufteilung in Stage 08 (Flatpaks), 09 (Apps & MIME) und 10 (Hyprland) sowie ShellCheck-Bereinigung
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 13:36:52 +02:00
DragonSlayer_14andJunie 579489fa9c Feat: OpenDeck-Installation zu Stage 08 hinzugefügt
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 13:30:27 +02:00
DragonSlayer_14andJunie d69534d286 Feat: Ollama-Installation und systemd-Service-Konfiguration mit anpassbarem Modellpfad hinzugefügt
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 13:23:32 +02:00
DragonSlayer_14andJunie 6cd6e789ba Fix: Keyring-Handling, Error-Traps und Docker/Spotify-Repositorys korrigiert
- lib/apt.sh: GPG-Dearmor mit --yes --batch und ASCII-Armor-Erkennung über grep

- stages/05-fonts.sh: Bereinigung nur noch bei EXIT trappen

- stages/06-services.sh: Standard-Codename für Docker-Repo auf trixie gesetzt

- stages/08-flatpaks-apps.sh: Einheitliche Hilfsfunktion apt_add_keyring_from_url für Spotify genutzt

Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 13:12:37 +02:00
DragonSlayer_14 8e36e4ce0d FEat: Fügt Architectures: amd64 in sources.list ein 2026-09-06 13:01:04 +02:00
DragonSlayer_14andJunie 4afce9cdb1 Feat: Fehlende APT-Pakete wiederhergestellt und Gitea-Paketquellen eingerichtet
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 12:58:30 +02:00
DragonSlayer_14andJunie bb3e42a8e3 Feat: Native Installation von Steam, Heroic und Lutris über APT sowie 32-Bit-Multiarch-Aktivierung
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 12:39:57 +02:00
DragonSlayer_14andJunie c4241d7015 feat(zsh): provision Oh-My-Zsh and plugins for all users on login
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 12:30:51 +02:00
DragonSlayer_14andJunie 28319183b6 feat(hyprland): add Junie CLI and AwesomeJunieSkills to first-login setup
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 12:17:57 +02:00
DragonSlayer_14andJunie 04a68df15c Feat: Hyprland-Desktop mit Debian-Hyprland-Installer und interaktivem Dotfiles-Setup
Co-authored-by: Junie <junie@jetbrains.com>
2026-09-06 12:05:35 +02:00
DragonSlayer_14 3c1601fc2f Feat: Fütgt kitty in den Packages hinzu 2026-09-06 11:14:46 +02:00
DragonSlayer_14 d424b5eed7 Feat: Überarbeitet die Install Struktur 2026-09-06 11:11:46 +02:00
DragonSlayer_14 90dd188555 Feat: Fügt speech-dispatcher hinzu 2026-09-01 17:21:00 +02:00
DragonSlayer_14 24d8ba379f Feat: Fügt glances hinzu 2026-08-31 21:56:09 +02:00
DragonSlayer_14 ad7b31a67a Feat: FÜgt htop hinzu 2026-08-31 21:53:45 +02:00
DragonSlayer_14 b237de1fc5 Feat: Kommentiert Docker wieder ein 2026-08-31 21:49:17 +02:00
DragonSlayer_14 6e303b041f Feat: Passt .gitignore an 2026-08-31 21:26:40 +02:00
DragonSlayer_14 3788422797 Feat: Entfernt LM-Studio 2026-08-31 21:23:31 +02:00
DragonSlayer_14 10aec5458a Feat: Ersetzt lm-studio AppImage durch lm-studio Flatpak 2026-08-31 20:51:25 +02:00
DragonSlayer_14 4feb815d97 Feat: Installiert LM-Studio als AppImage 2026-08-30 21:13:21 +02:00
DragonSlayer_14 279a137132 Feat: Fügt LM-Studio hinzu 2026-08-30 21:09:28 +02:00
DragonSlayer_14 fe02dd23c6 Ref: Passt Sortierung an 2026-08-30 13:51:59 +02:00
DragonSlayer_14 8a5c4094ba Feat: Fügt command-not-found hinzu 2026-08-30 09:32:33 +02:00
DragonSlayer_14 9b0dce0d84 Feat: Fügt gparted hinzu 2026-08-30 09:29:37 +02:00
DragonSlayer_14 8d2e4b3b0e Feat: Installiert Lutris als Flatpak 2026-08-30 00:08:15 +02:00
DragonSlayer_14 f810149f95 Feat: Fügt vulkan-tools hinzu 2026-08-30 00:07:24 +02:00
DragonSlayer_14 f32e1ca6d4 Feat: INstalliert Heroic als Flatpak 2026-08-30 00:06:12 +02:00
DragonSlayer_14 da0367a43c Feat: Fügt mangoapp hinzu 2026-08-29 19:39:07 +02:00
DragonSlayer_14 3a9cf54b2f Feat: Fügt -y bei apt install hinzu 2026-08-29 00:02:31 +02:00
DragonSlayer_14 4f87611c66 Feat: Sortiert apt-Pakete um 2026-08-29 00:00:38 +02:00
DragonSlayer_14 ace5cfee5c Feat: Installiert heroic über den Mirror 2026-08-28 23:33:00 +02:00
DragonSlayer_14 858b3a4cb5 Feat: Installiert topgrade über den Mirror 2026-08-28 23:25:45 +02:00
DragonSlayer_14 b92c49048b Feat: Entfernt deb-get 2026-08-28 23:25:03 +02:00
DragonSlayer_14 394746f658 Feat: Fügt TODO ein 2026-08-28 23:22:38 +02:00
DragonSlayer_14 d86a1dde3d Feat: Passt Sortierung an 2026-08-28 23:21:36 +02:00
DragonSlayer_14 22b4ca5c9e Feat: Installiert codium über den Mirror 2026-08-28 23:19:56 +02:00
DragonSlayer_14 c48ebeda9c Feat: Kommentriert Spotify wieder ein 2026-08-28 23:14:45 +02:00
DragonSlayer_14 b74436b7c0 Feat: Installiert Floorp über den Mirror 2026-08-28 23:14:10 +02:00
DragonSlayer_14 13a40d5ac5 Feat: Installiert Vesktop über den Mirror 2026-08-28 23:05:26 +02:00
DragonSlayer_14 f1ba8513fc Feat: Fügt lutris hinzu 2026-08-28 22:59:46 +02:00
DragonSlayer_14 3d06340314 Feat: Fügt yazi hinzu 2026-08-28 22:54:19 +02:00
DragonSlayer_14 c2611debfa Feat: Fügt Kommentar hinzu 2026-08-28 22:48:38 +02:00
DragonSlayer_14 9cb077e4fb Feat: Passt Sortierung der Flatpak-Pakete an 2026-08-28 22:45:29 +02:00
DragonSlayer_14 5c4b9ad08d Feat: Ersetzt das Flatpak localsend durch das apt-Paket 2026-08-28 22:43:39 +02:00
DragonSlayer_14 5bc8227773 Feat: Ersetzt das Flatpak rpi-imager durch das apt-Paket 2026-08-28 22:34:29 +02:00
DragonSlayer_14 0c0b6da0ea Feat: Ersetzt das Flatpak cryptomator durch das apt-Paket 2026-08-28 22:25:57 +02:00
DragonSlayer_14 7c2ca5b6b2 Feat: Ersetzt das Flatpak bruno durch das apt-Paket bruno 2026-08-28 22:14:51 +02:00
DragonSlayer_14 4b0047484d Fix: Passt Signed-By Wert für gitea-mirror.sources an 2026-08-28 22:12:40 +02:00
DragonSlayer_14 d5b1da9745 Feat: Fügt apt-Mirror https://gitea.creative-dragonslayer.de/api/packages/Mirror/debian hinzu 2026-08-28 22:07:28 +02:00
DragonSlayer_14 dc8c4c9062 Feat: Ersetzt das Flatpak decoder durch das apt-Paket gnome-decoder 2026-08-28 22:01:18 +02:00
DragonSlayer_14 aa68e0e1f7 Feat: Ersetzt das Flatpak TextEditor durch das apt-Paket gnome-text-editor 2026-08-28 21:59:57 +02:00
DragonSlayer_14 bff9822c86 Ersetzt das Flatpak font-viewer durch das apt-Paket gnome-font-viewer 2026-08-28 21:57:39 +02:00
DragonSlayer_14 1aa3a164ab Ersetzt das Flatpak calculator durch das Apt-Paket gnome-calculator 2026-08-28 21:55:50 +02:00
DragonSlayer_14 742cee14f1 Feat: Ersetzt Logs durch das Apt-Paket gnome-logs 2026-08-28 21:50:41 +02:00
DragonSlayer_14 532d34a6ae Feat: Ersetzt das Amberol-Flatpak durch das apt-Paket 2026-08-28 21:49:14 +02:00
DragonSlayer_14 61034975db Fix: Passt .desktop-Name von Loupe an 2026-08-28 21:47:51 +02:00
DragonSlayer_14 d4de7d0056 Feat: Ersetzt das Flatpak snapshot durch das apt Paket gnome-snapshot 2026-08-28 21:40:01 +02:00
DragonSlayer_14 93f0757f49 Feat: Ersetzt das Flatpak SimpleScan durch das entsprechende apt-Paket 2026-08-28 21:37:46 +02:00
DragonSlayer_14 697196c99b Update default image viewer to Loupe and adjust dependencies
Replaced default image viewer with Loupe for JPEG and PNG files in `03-install.sh` and removed redundant installation and configuration steps from `07-programs.sh`. Ensured required dependency `loupe` is included in the apt package list.
2026-08-28 21:36:39 +02:00
DragonSlayer_14 a3630b9d28 Set Betterbird as default mail app with a TODO note
Betterbird is installed and set as the default mail application. A TODO comment is added to replace Betterbird with Melia in the future.
2026-08-28 21:31:10 +02:00
DragonSlayer_14 176240f3b7 Add 'bat' package to the installation script
The 'bat' package has been added to the list of stable packages in 03-install.sh. This enhances the toolset by providing a modern alternative to 'cat' with additional features like syntax highlighting and Git integration.
2026-08-28 18:39:17 +02:00
DragonSlayer_14 7af43e0850 Update package lists and adjust Easyeffects installation method
Added "easyeffects" to apt installation in `03-install.sh` and removed its Flatpak installation from `07-programs.sh`. This ensures Easyeffects is installed via the system package manager instead of Flatpak for better integration.
2026-08-27 19:23:49 +02:00
DragonSlayer_14 5b3fd6848d Add Remmina to apt install and remove its Flatpak version
Replaced Remmina's Flatpak installation with its APT package counterpart for consistency with other system-installed software. This ensures better integration and potentially reduced redundancy in package management.
2026-08-27 19:22:39 +02:00
DragonSlayer_14 ef08a0221b Add PrismLauncher to APT install and remove Flatpak installation
PrismLauncher is now installed via the system package manager (APT) instead of Flatpak for consistency and better integration with the system. The Flatpak installation of PrismLauncher has been removed accordingly.
2026-08-27 19:17:43 +02:00
DragonSlayer_14 29948841cd Add Flameshot to APT installation; remove redundant Flatpak install
Moved Flameshot installation to APT package list for consistency and removed its duplicate Flatpak installation from the programs script. This change ensures that Flameshot is installed via the system's package manager instead of Flatpak for better integration.
2026-08-27 19:14:00 +02:00
DragonSlayer_14 cf24a033da Update package lists and remove redundant Flatseal install
Added "Flatseal" to the apt package list and removed its redundant Flatpak installation in the scripts. This change ensures consistency by managing Flatseal through the system package manager instead of Flatpak.
2026-08-27 19:12:48 +02:00
DragonSlayer_14 4516129bec Add 'obfuscate' package to apt and remove its Flatpak version
Moved the 'obfuscate' package installation from Flatpak to apt for consistency in package management. Removed the Flatpak-specific installation step and added 'obfuscate' to the apt package install list.
2026-08-27 19:10:47 +02:00
DragonSlayer_14 7176a8d796 Update package list and remove redundant flatpak install
Added "resources" to the apt package list, replacing its previous installation via flatpak. Removed the flatpak installation of "net.nokyan.Resources" as it is now included as a system package. This ensures better consistency and avoids duplicate installations.
2026-08-27 19:09:00 +02:00
DragonSlayer_14 01e7b63c7f Add 'impression' package to APT and remove redundant Flatpak
The package 'impression' was added to the APT installation list for improved management while its Flatpak installation was removed from the script. This ensures consistency by reducing duplication and aligning package management under APT.
2026-08-27 19:05:34 +02:00
DragonSlayer_14 934dbd1ea6 Update package list and remove redundant Flatpak installation
Added 'fragments' to the APT package installation list while removing its Flatpak installation to streamline package management. This ensures consistency and avoids duplicate installations across package managers.
2026-08-27 19:03:07 +02:00
DragonSlayer_14 fc6385d400 Remove installation of Cartridges application
The Cartridges app installation command was removed from the script, likely due to redundancy or a change in requirements. This ensures the script installs only the necessary applications.
2026-08-27 18:59:59 +02:00
DragonSlayer_14 6fdd50341c Remove Ente Authenticator flatpak installation
The installation command for Ente Authenticator has been removed from the script. This change simplifies the setup process by excluding unnecessary software.
2026-08-27 18:59:26 +02:00
DragonSlayer_14 aab24c5d1d Update package list to include VLC and remove Flatpak install
Added VLC and its related plugins to installation via apt in `03-install.sh` for system-wide availability. Removed redundant Flatpak-based VLC installation from `07-programs.sh` to streamline the setup process.
2026-08-27 18:55:20 +02:00
DragonSlayer_14 5c4097bb6e Update package list and reorganize installation steps
Added 'baobab' to apt package installations and removed its Flatpak counterpart from the program script to streamline installation. Also included a comment placeholder for installing 'yazi' with a link to its documentation.
2026-08-27 18:44:17 +02:00
DragonSlayer_14 6885535b72 Add gnome-keyring to the list of installed packages
Included gnome-keyring to enhance GNOME desktop functionality. This ensures better keyring management and integration for secure storage of credentials. Other packages remain unchanged.
2026-08-23 12:19:13 +02:00
DragonSlayer_14 0c9cc435d5 Add wayland-utils to the package installation list
Included wayland-utils as part of the stable package installation in `03-install.sh` to support Wayland-specific functionality. This ensures better compatibility and enhances user experience on Wayland-based systems.
2026-08-19 22:54:56 +02:00
DragonSlayer_14 1b1be169cf Add installation of GE-Proton via Flatpak
This commit includes the installation command for GE-Proton, a Steam compatibility tool, using Flatpak. This ensures improved game compatibility for Steam users.
2026-08-18 19:44:06 +02:00
DragonSlayer_14 07fe48a33e Add steam-devices to the package installation list.
This change ensures that the steam-devices package is included during the installation process, which is essential for better hardware support in gaming scenarios. No other modifications were made to the script.
2026-08-17 17:11:06 +02:00
DragonSlayer_14 13da1e980b Add MangoHud installation to 07-programs.sh
Included the MangoHud Vulkan layer installation via Flatpak. This provides an overlay for monitoring performance metrics in games.
2026-08-16 11:34:00 +02:00
DragonSlayer_14 b13a0831fa Add Gamescope installation via Flatpak
This commit includes the addition of a Flatpak command to install Gamescope, a Vulkan-based compositor for gaming. It ensures a more complete setup for gaming-related tools.
2026-08-16 11:28:41 +02:00
DragonSlayer_14 f60be958f6 Add Scopebuddy GUI to Flatpak install list
This commit adds the Scopebuddy GUI application to the programs installed via Flatpak in the script. This ensures the tool is included alongside other essential applications for consistency.
2026-08-16 11:21:35 +02:00
DragonSlayer_14 b8c856a7d3 Remove unused Steam Homebrew installation script
The Steam Homebrew installation script was deemed unnecessary and has been removed from the program setup file. Flatpak installation for Steam remains as the primary method.
2026-08-16 11:17:56 +02:00
DragonSlayer_14 94996e1bb8 Reorganize and relocate installer commands for clarity
Moved Linutil and Steam Homebrew installer commands to more relevant sections in the scripts. This enhances organization and ensures commands are executed in appropriate contexts.
2026-08-16 11:14:55 +02:00
DragonSlayer_14 2481f515b8 Disable addition of i386 architecture in apt setup
Commented out the command for adding i386 architecture to apt, likely aiming to prevent compatibility issues or unnecessary package handling. This change ensures a cleaner and more controlled apt configuration process.
2026-08-16 11:01:55 +02:00
DragonSlayer_14 39b9de3443 Update package installations and add Steam via Flatpak
Removed Steam installer from aptitude to avoid redundancy and added Steam installation through Flatpak. This ensures consistency with the Flatpak approach and streamlines dependency management.
2026-08-16 11:00:49 +02:00
DragonSlayer_14 eca438f7cb Add Local Send flatpak installation
This commit adds the installation command for Local Send via Flatpak and ensures the Flatsweep installation command uses the `-y` flag for automated installation. These changes improve the script's functionality and user experience.
2026-08-15 19:05:57 +02:00
DragonSlayer_14 ddf8585a16 Update installation script with QEMU setup and auto-cpufreq fix
Removed unnecessary sudo from auto-cpufreq installation command for better compatibility. Added a conditional QEMU and virtualization setup to streamline virtual machine installations and configurations. Includes user group adjustments and default network setup for libvirt.
2026-08-13 17:16:56 +02:00
DragonSlayer_14 cb89d422e7 Add dconf-editor to the list of installable packages
Included `dconf-editor` in the stable package installation list for easier system configuration management. This ensures users have access to a critical GUI tool for editing system settings.
2026-08-09 19:29:40 +02:00
DragonSlayer_14 8c1b7168bc Update APT sources to use Debian unstable
Replaced the Debian stable sources configuration with Debian unstable. This change ensures access to the latest packages and updates from the unstable distribution. The security sources for the stable suite were also removed as part of this update.
2026-08-09 13:38:59 +02:00
DragonSlayer_14 f8cbcc1cc6 Feat: Aktualisiert das System auf Debian-unstable und fügt gitea-apt-REpositories hinzu. 2026-08-09 12:00:51 +02:00
DragonSlayer_14 36e56b67b7 Disable installation steps for Lutris, Spotify, Floorp, and Codium.
Commented out commands for installing Lutris, Spotify, Floorp, and Codium in the installation script. This prevents these applications from being installed during script execution. No functional changes to remaining installation steps.
2026-08-09 11:55:05 +02:00
DragonSlayer_14 7c4db527cc Disable Docker and deb-get setup in install script
Commented out Docker installation and deb-get setup steps to streamline the script for specific use cases. Adjusted the AppImage installer to use the home directory for temporary files. Further changes ensure the script aligns with simplified installation requirements.
2026-08-09 11:43:03 +02:00
DragonSlayer_14 a12f135d3f Add protontricks to package installation list
Protontricks was added to the list of stable packages to ensure better compatibility and management of Proton configurations in gaming setups. This enhances the utility of the install script for users running Steam with Proton.
2026-08-09 00:07:15 +02:00
DragonSlayer_14 12240a0ec5 Add AMD CPU-specific game optimization parameters to README
Added detailed launch parameters and configuration examples for optimizing gaming performance on AMD CPUs. Includes settings for ray tracing, upscaling, and general performance improvements to enhance user guidance.
2026-08-08 23:48:25 +02:00
DragonSlayer_14 4a77bb10d6 Add zram-tools to the package installation list
Updated the 03-install.sh script to include zram-tools in the stable package installation section. This addition ensures better memory compression and system performance optimization where zram-tools is applicable.
2026-08-08 23:36:09 +02:00
DragonSlayer_14 fbea2fef38 Add CPU vendor detection and dynamic kernel parameter updates
Implement logic to detect CPU vendor (Intel/AMD) and append appropriate pstate parameters to GRUB configuration. Improve localization, enhance idempotency when setting parameters, and include backup creation and theme update handling.
2026-08-08 23:27:00 +02:00
DragonSlayer_14 6fbc4ff9d0 Set threadirqs in GRUB_CMDLINE_LINUX_DEFAULT
Added the 'threadirqs' parameter to the kernel command line to improve interrupt handling and optimize performance for threaded IRQs. This change ensures better responsiveness and system behavior in specific workloads.
2026-08-08 23:18:14 +02:00
DragonSlayer_14 6f67a5b034 Add radeontop to the list of installed stable packages
Included `radeontop` in the installation script to provide GPU monitoring capabilities for Radeon users. This enhances system resource monitoring and troubleshooting during usage.
2026-08-08 23:07:32 +02:00
DragonSlayer_14 9b7f391cb0 Add script to run Linutil during installation
Integrated the Linutil script from christitus.com into the installation process. This addition enhances system setup by automating essential Linux configurations.
2026-08-08 22:50:46 +02:00
DragonSlayer_14 7290ffdc4a Add installation of 32-bit libs and Steam Brew script
Install `libssl-dev:i386` for 32-bit compatibility and add a script to set up Steam Brew. These changes support better gaming functionality and system setup.
2026-08-08 22:39:56 +02:00
DragonSlayer_14 1dfd42dd1a Add Heroic Games Launcher installation to script
This update adds a command to install the Heroic Games Launcher using deb-get. It ensures users have an easy way to set up the launcher during the script execution.
2026-08-08 22:14:47 +02:00
DragonSlayer_14 82f23a9651 Add auto-cpufreq installation to 03-install.sh
Integrates automated CPU performance and power optimization by including the installation of auto-cpufreq. Clones the repository, runs the installer, and enables the service for system-wide use.
2026-08-08 22:10:40 +02:00
DragonSlayer_14 c1873b34bf Add installation script for AM - AppImage Manager
This commit adds a script to install AM, the AppImage Manager, using a curl command to download and execute the installer. The script ensures proper cleanup by removing the installer after execution.
2026-08-08 22:00:57 +02:00
DragonSlayer_14 b8efa35307 Add installation step for topgrade via deb-get
This ensures that the topgrade tool is installed automatically as part of the script. It simplifies the process for users by combining all necessary installations into the same setup routine.
2026-08-08 21:54:54 +02:00
DragonSlayer_14 778c845db1 Remove redundant apt update and install; add deb-get setup
The apt update and ca-certificates/curl install commands were removed as they were unnecessary for the script's context. Additionally, support for installing deb-get was added to streamline package management.
2026-08-08 21:54:40 +02:00
DragonSlayer_14 bf976533ba Enable AppArmor in GRUB boot configuration.
Added the `apparmor=1` parameter to the `GRUB_CMDLINE_LINUX_DEFAULT` option to explicitly enable AppArmor. This enhances security by enforcing mandatory access control policies.
2026-08-08 21:44:58 +02:00
DragonSlayer_14 504c1f0494 Add AppArmor installation and enable by default
AppArmor packages are now included in the list of installations, and the service is enabled and started by default. This enhances system security by proactively managing application privileges.
2026-08-08 21:41:47 +02:00
DragonSlayer_14 5f6851c65e Add Docker installation to setup script
This update incorporates commands for installing Docker, including setting up its repository, importing the GPG key, and installing necessary packages. These changes streamline Docker installation during the setup process.
2026-08-08 12:00:52 +02:00
DragonSlayer_14 9d6ed39b5e Add gnome-firmware to the list of stable packages
This update enhances the system setup script by including gnome-firmware in the stable packages installation list. Gnome-firmware allows for better firmware management and updates directly within the system. This addition improves overall system functionality and user experience.
2026-07-29 17:54:30 +02:00
DragonSlayer_14 468b900561 Fix typo in Flatpak install command comment
Corrected a missing comment symbol in the Flatpak install command for RPI-Imager. This ensures consistency and avoids unintended execution or errors in the script.
2026-07-14 18:28:37 +02:00
DragonSlayer_14 f0ee6a0dce Add RPI-Imager installation to 07-programs.sh
Included the command to install the Raspberry Pi Imager via Flatpak. This ensures the tool is available for creating and managing Raspberry Pi OS images efficiently.
2026-07-14 18:11:17 +02:00
DragonSlayer_14 ddc142da78 Add Flatsweep installation to programs script
Flatsweep is now included in the list of Flatpak installations in `07-programs.sh`. This ensures easier setup and uniformity when deploying required applications.
2026-07-11 12:19:58 +02:00
DragonSlayer_14 33d5c78cd5 Add firmware-linux packages to installation script
Included firmware-linux, firmware-linux-nonfree, and firmware-misc-nonfree in the package installation list. This ensures better hardware compatibility and support for devices requiring proprietary firmware.
2026-06-20 21:03:10 +02:00
DragonSlayer_14 0aeb0fd221 Feat: Fügt systemd-timesyncd und adb hinzu 2026-06-07 12:59:47 +02:00
DragonSlayer_14 9fdb2c4982 Feat: Fügt systemd-timesyncd hinzu 2026-05-25 15:34:19 +02:00
DragonSlayer_14 21115bbcd1 Feat: Passt Pfade an 2026-05-21 00:26:04 +02:00
DragonSlayer_14 3f1a3fb554 Fix: Liest HOME richtig aus 2026-05-21 00:19:05 +02:00
DragonSlayer_14 d2579c8f45 Fix: Behebt Fehler 2026-05-21 00:16:29 +02:00
DragonSlayer_14 70d6d09c65 Feat: Passt Default-Config an 2026-05-21 00:13:11 +02:00
DragonSlayer_14 23494013c8 Feat: Entfernt gelöschte Zeile 2026-05-20 23:10:36 +02:00
DragonSlayer_14 173f9ecbe4 Feat: Passt Paketursprünge an 2026-05-20 22:49:49 +02:00
DragonSlayer_14 2c70d0a709 Feat: Fügt imagemagick hinzu 2026-05-20 22:24:08 +02:00
DragonSlayer_14 0cf512fc4f Feat: Passt Installation an 2026-05-20 22:10:54 +02:00
DragonSlayer_14 7f7431029f Verschiebt einzelne Pakete wieder zurück 2026-05-20 21:16:29 +02:00
DragonSlayer_14 cef7039f29 Lagert Stable-Pakete in 00 aus 2026-05-20 19:47:26 +02:00
DragonSlayer_14 338393580a Feat: Installiert und nutzt aptitude 2026-05-20 19:42:08 +02:00
DragonSlayer_14 60191445bc Feat: Schiebt rsync in der Installation weiter nach vorne 2026-05-20 19:30:31 +02:00
DragonSlayer_14 9c1e62dfe8 Feat: Passt Hyprland-Install-Skript URL an 2026-05-20 19:08:52 +02:00
DragonSlayer_14 6fbc98bc98 Feat: Passt Branch-URL an 2026-05-20 19:07:51 +02:00
DragonSlayer_14 f9c892baee Feat: Passt README an 2026-05-20 19:06:27 +02:00
DragonSlayer_14 51a7a9a927 Feat: Fügt neue Version ein 2026-05-20 19:05:33 +02:00
65 changed files with 5042 additions and 21 deletions
+15
View File
@@ -77,3 +77,18 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# ---> VisualStudioCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
.junie/plans
+1
View File
@@ -0,0 +1 @@
{}
+236
View File
@@ -0,0 +1,236 @@
# AGENTS.md — Richtlinien und Architektur-Leitfaden für KI-Agenten
Dieses Dokument enthält Richtlinien, Architekturstandards, Konventionen und Arbeitsanweisungen für KI-Agenten und Entwickler, die an diesem Repository arbeiten oder es warten.
---
## 1. Projektübersicht
Dieses Repository ist ein modulares, automatisiertes Setup- und Konfigurations-Framework für **Debian GNU/Linux Unstable (Sid)** mit:
- **Hyprland** (Wayland-Compositor) und Waybar-Desktopumgebung
- **XanMod-Kernel** (main/edge) mit CPU P-State-Tuning (AMD/Intel) und `auto-cpufreq`
- **Bootloader & Splash**: GRUB-Konfiguration mit Vimix-Theme und Plymouth Solar-Splash
- **Gaming & Multimedia**: MangoHud, Gamescope, Lutris, Steam, Wine, Pro-Audio via PipeWire
- **Virtualisierung & Container**: QEMU/KVM, Libvirt, Docker, Waydroid
- **Paket- und Anwendungsmanagement**: Deb822-Quellen, APT-Pinning, Flatpaks (Flathub), isolierte Schriften-Installation
---
## 2. Projekt- und Verzeichnisstruktur
```
.
├── install.sh # Web-Installer & Bootstrap-Skript (curl | bash, klont nach /tmp)
├── setup.sh # Zentraler Orchestrator (CLI Flags & whiptail TUI)
├── lib/ # Wiederverwendbare Funktionsbibliotheken
│ ├── utils.sh # Logging, Error-Traps, Benutzer- und Pfadermittlung, Backups
│ ├── apt.sh # Deb822-Quellen, Keyrings (/etc/apt/keyrings), APT-Pinning, Paketinstallation
│ ├── btrfs.sh # Btrfs Root- & Subvolume-Erkennung, Migration (@, @home), fstab-Verwaltung
│ ├── network.sh # Loopback- & LAN-Schnittstellenkonfiguration (Debian Installer Standard)
│ └── tui.sh # Whiptail-TUI-Menüs und Dialoge
├── config/ # Konfigurationsdateien & Paketlisten
│ ├── setup.conf # Globale Umgebungsvariablen und Standardwerte
│ └── packages/ # Thematisch gegliederte Paketlisten (*.list)
│ ├── 01-base.list # Basiswerkzeuge, Firmware, Microcode
│ ├── 02-desktop.list # Hyprland, Waybar, SDDM, XDG-Portale, PipeWire
│ ├── 03-gaming.list # Steam, Heroic, Lutris, Gamescope, MangoHud, Wine
│ ├── 04-virtualization.list # QEMU, KVM, Libvirt, Bridge-Tools
│ ├── 05-multimedia.list # VLC, Amberol, GIMP, Loupe, LibreOffice
│ └── 06-flatpaks.list # Flathub App-IDs
├── stages/ # Sequenziell und modular ausführbare Phasen (00 bis 11)
│ ├── 00-preflight.sh # Systemvoraussetzungen, Root/User-Erkennung, Internetverbindung
│ ├── 01-apt-unstable.sh # Deb822-Quellen, Keyrings, Pinning, apt-listbugs, dist-upgrade
│ ├── 02-kernel-hardware.sh # XanMod-Kernel, CPU P-State, Microcode, auto-cpufreq, Shader-Cache-Pfad
│ ├── 03-bootloader.sh # GRUB Kernel-Parameter, Vimix-Theme, Plymouth Solar
│ ├── 04-packages.sh # Installation der thematischen Paketlisten
│ ├── 05-fonts.sh # Download & Installation von Coding- & Nerd-Fonts
│ ├── 06-services.sh # Aktivierung von AppArmor, Docker, Libvirt, zram, Ollama, GameMode/CoreCtrl, systemd-oomd, scx-Scheduler
│ ├── 07-skel-and-user.sh # /etc/skel Vorlagen, ZSH-Shell-Setzen, Dotfiles-Sync
│ ├── 08-flatpaks.sh # Flathub Setup, Flatpak-Paketlisten-Installation
│ ├── 09-apps.sh # Spotify, Waydroid, OpenDeck, Desktop-Starter, MIME-Types
│ ├── 10-hyprland.sh # LinuxBeginnings Debian-Hyprland Auto-Installer & Desktop-Setup
│ └── 11-linutil.sh # Linutil (Chris Titus Tech System Toolbox), letzter Install-Schritt
├── data/ # Statische Konfigurationsdateien & Vorlagen
│ ├── apt/
│ │ ├── sources.list.d/ # Deb822-Quellen (debian-unstable.sources, xanmod.sources)
│ │ └── preferences.d/ # Pinning-Konfigurationen
│ ├── etc/
│ │ ├── environment.d/ # Globale Umgebungsvariablen (Raytracing, Upscaling)
│ │ ├── gamemode.ini # GameMode Performance-Daemon Defaults (Governor, Renice, GPU)
│ │ ├── polkit-1/rules.d/ # 90-corectrl.rules (passwortlose CoreCtrl-Freigabe für sudo-Gruppe)
│ │ └── profile.d/ # Globale Profil-Skripte (z. B. XDG User Dirs Update)
│ ├── skel/ # Vorlagen für /etc/skel (.zshrc, .config/MangoHud, .config/vkBasalt, Dokumentvorlagen)
│ └── usr/share/applications/ # Desktop-Starter-Dateien
├── README.md # Projektdokumentation für Endanwender
└── LICENSE # MIT-Lizenz
```
---
## 3. Architekturprinzipien und Entwicklungsrichtlinien
### 3.1 Idempotenz (Mehrfache Ausführbarkeit)
- Jedes Skript und jede Phase muss **vollständig idempotent** sein: Die wiederholte Ausführung darf keine Fehler erzeugen und keine doppelten Konfigurationseinträge hinterlassen.
- Verwende vor dem Hinzufügen von Zeilen zu Konfigurationsdateien Prüfungen (z. B. `grep -q`) oder nutze saubere Konfigurationsverzeichnisse (`.d/`-Verzeichnisse).
### 3.2 Strikte Trennung von Root- und Benutzerrechten
- Die Skripte laufen grundsätzlich mit Root-Rechten (`sudo ./setup.sh`).
- **Niemals** Benutzerkonfigurationen unter `/root/` ablegen, wenn sie für den Desktop-Benutzer gedacht sind.
- Der Zielbenutzer wird in `$TARGET_USER` gespeichert (ermittelt über `prompt_target_user` in `lib/utils.sh`).
- Befehle im Kontext des regulären Benutzers **müssen** über `run_as_user "<befehl>"` ausgeführt werden.
- Das Home-Verzeichnis des Zielbenutzers muss über `get_target_home "$TARGET_USER"` ermittelt werden.
### 3.3 Fehlerbehandlung und Shell-Standards
- Alle Bash-Skripte **müssen** mit folgenden Flags starten:
```bash
#!/usr/bin/env bash
set -euo pipefail
```
- Binde `lib/utils.sh` ein und rufe `setup_err_trap` am Anfang jedes Skripts auf:
```bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/utils.sh
source "$SCRIPT_DIR/../lib/utils.sh"
setup_err_trap
```
- `setup_err_trap` aktiviert `errtrace`/`functrace`, damit Fehler auch innerhalb von `lib/*.sh`-Funktionen abgefangen werden, und registriert `error_handler` als ERR-Trap. Schlägt ein Befehl fehl, wird der Benutzer interaktiv gefragt, ob der Befehl **wiederholt**, **ignoriert** oder die **Installation abgebrochen** werden soll (`ask_retry_ignore_abort`). In nicht-interaktiven Läufen (`CI=1`, `DEBIAN_FRONTEND=noninteractive`, `AUTO_CONFIRM=1`, keine TTY) wird immer automatisch abgebrochen, wie zuvor.
- Verwende für temporäre Verzeichnisse immer `mktemp -d` und stelle sicher, dass am Skriptende oder bei Fehlern aufgeräumt wird:
```bash
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
```
### 3.4 Dateisicherungen (Backups)
- Modifiziere bestehende Konfigurationsdateien (z. B. in `/etc/default/grub` oder `/etc/apt/`) nie ohne vorheriges Backup.
- Nutze die Bibliotheksfunktion `backup_file "$DATEIPFAD"`. Diese erstellt Backups im Format `<datei>.backup_YYYYMMDD_HHMMSS`.
### 3.5 Debian-Standards & APT-Hygiene
- **Deb822-Format**: Neue Paketquellen ausschließlich im Deb822-Format (`.sources`) unter `/etc/apt/sources.list.d/` ablegen.
- **Keyrings**: GPG-Schlüsselbunde gehören nach `/etc/apt/keyrings/` mit Rechten `644`. Das veraltete `apt-key` darf **nicht** verwendet werden.
- **Pinning**: APT-Prioritäten in `/etc/apt/preferences.d/` verwalten.
- **Nicht-interaktive Paketinstallation**: APT-Befehle müssen immer `DEBIAN_FRONTEND=noninteractive` und `-y` bzw. `--no-install-recommends` (sofern passend) verwenden. Verwende bevorzugt die Wrapper in `lib/apt.sh` (`safe_apt_update`, `install_packages_from_file`).
### 3.6 Keine gefährlichen Login-Hooks & Shell-Verwaltung
- **Keine Live-Downloads** (`curl | sh` / `wget | bash`) in `/etc/profile.d/` oder Login-Skripten.
- Dotfiles und Vorlagen gehören nach `/etc/skel/` und werden bei Bedarf einmalig für bestehende Nutzer synchronisiert (`stages/07-skel-and-user.sh`).
- Ändere Login-Shells niemals durch direkte Bearbeitung von `/etc/passwd` via `sed` oder `awk`, sondern ausschließlich über `chsh -s "$(command -v zsh)" "$TARGET_USER"`.
---
## 4. Hilfsbibliotheken (`lib/`)
### `lib/utils.sh`
- `log_info "Nachricht"`: Blaue Info-Meldung.
- `log_success "Nachricht"`: Grüne Erfolgsmeldung (`[✓]`).
- `log_warn "Nachricht"`: Gelbe Warnung (`[WARN]`).
- `log_error "Nachricht"`: Rote Fehlermeldung (`[ERROR]`).
- `log_step "Titel"`: Hervorgehobener Abschnitts-Header.
- `log_substep "Titel"`: Eingerückter Unterabschnitt.
- `setup_err_trap`: Aktiviert `errtrace`/`functrace` und registriert `error_handler` als ERR-Trap für das gesamte Skript (inkl. `lib/*.sh`-Funktionen).
- `error_handler` / `ask_retry_ignore_abort` / `resume_after_error`: Zentrale Fehlerbehandlung. Bei einem fehlgeschlagenen Befehl wird interaktiv nach Wiederholen/Ignorieren/Abbrechen gefragt; nicht-interaktiv wird immer abgebrochen.
- `require_root`: Bricht ab, wenn das Skript nicht mit Root-Rechten ausgeführt wird.
- `command_exists "tool"`: Prüft, ob ein Befehl im Pfad verfügbar ist.
- `prompt_target_user`: Erkennt `$SUDO_USER` oder fragt interaktiv nach dem Zielbenutzer.
- `prompt_ollama_models_path`: Fragt interaktiv nach dem Speicherort für Ollama KI-Modelle oder nutzt Standardpfad.
- `get_target_home [username]`: Gibt den absoluten Pfad des Home-Verzeichnisses des Nutzers zurück.
- `run_as_user "command"`: Führt einen Befehl als `$TARGET_USER` via `su - "$TARGET_USER" -c ...` aus.
- `backup_file "filepath"`: Erstellt ein Backup einer Datei mit Zeitstempel.
### `lib/apt.sh`
- `safe_apt_update`: Führt ein abgesichertes `apt-get update` durch.
- `install_apt_keyring "name" "url"`: Lädt einen GPG-Schlüssel herunter, de-armort ihn sauber und speichert ihn in `/etc/apt/keyrings/<name>.gpg`.
- `install_packages_from_file "filepath"`: Liest eine `.list`-Datei ein (ignoriert Kommentare `#` und Leerzeilen) und installiert alle Pakete via `apt-get install -y`.
### `lib/btrfs.sh`
- `is_root_btrfs`: Prüft, ob das Root-Dateisystem auf Btrfs liegt.
- `is_root_subvolume_configured`: Prüft, ob Root bereits in einem Subvolume (`@`) läuft.
- `update_btrfs_fstab "fstab_file" "root_id"`: Aktualisiert Mount-Optionen in `/etc/fstab` für `@` und `@home`.
- `check_and_setup_btrfs_subvolumes`: Erkennt flache Btrfs-Root-Volumes und migriert `/` und `/home` transparent in Subvolumes `@` und `@home`.
- `ensure_timeshift_btrfs_config`: Erstellt bzw. initialisiert die Timeshift-Btrfs-Konfiguration (`/etc/timeshift/timeshift.json`, automatische Boot-Snapshots, Retention auf 5 Snapshots) für die Root-UUID.
- `ensure_timeshift_boot_service`: Richtet den `timeshift-boot.service` und Cron-Einträge für automatische Boot-Snapshots ein.
- `ensure_timeshift_apt_hook`: Richtet einen DPkg/APT-Hook (`/etc/apt/apt.conf.d/80timeshift-auto-snapshot` und `/usr/local/bin/timeshift-apt-hook`) für automatische Snapshots vor System-Updates ein.
- `ensure_grub_btrfs`: Installiert und konfiguriert `grub-btrfs` sowie den `grub-btrfsd`-Dienst für die automatische Generierung von Snapshot-Bootmenüeinträgen in GRUB.
- `create_timeshift_snapshot "comment" [tags]`: Erstellt einen Timeshift-Btrfs-Snapshot an kritischen Setup-Meilensteinen (idempotent, steuerbar über `ENABLE_TIMESHIFT_SNAPSHOTS` in `config/setup.conf`).
### `lib/network.sh`
- `get_lan_interfaces`: Erkennt alle physischen LAN/Ethernet-Schnittstellen dynamisch auf jedem System (unter Ausschluss von Loopback, Wi-Fi, Bridges und virtuellen Containern).
- `is_interface_configured "iface"`: Prüft, ob eine Schnittstelle bereits in `/etc/network/interfaces` oder `/etc/network/interfaces.d/` konfiguriert ist.
- `configure_loopback_interface`: Richtet das Loopback-Interface `lo` in `/etc/network/interfaces` (`auto lo`, `iface lo inet loopback`) sowie `/etc/hosts` ein und aktiviert es.
- `configure_lan_interfaces`: Richtet alle erkannten physischen LAN-Schnittstellen im Debian-Installer-Standard (`allow-hotplug <iface>`, `iface <iface> inet dhcp`, `iface <iface> inet6 auto`) ein und aktiviert diese.
- `configure_network_manager`: Konfiguriert `/etc/NetworkManager/NetworkManager.conf` mit `[ifupdown] managed=true` für nahtlose Desktop- und Waybar-Integration.
- `enable_network_services`: Aktiviert und startet `networking.service` und `NetworkManager.service`.
- `configure_network_all`: Zentraler Orchestrator zur vollständigen Netzwerkeinrichtung.
### `lib/tui.sh`
- `tui_check_whiptail`: Stellt sicher, dass `whiptail` installiert ist.
- `tui_welcome`: Zeigt den Begrüßungsdialog.
- `tui_select_stages`: Zeigt ein `whiptail` Checklist-Menü zur interaktiven Auswahl der auszuführenden Phasen.
- `tui_prompt_target_user [default_user]`: Bestätigt oder erfragt den Desktop-Zielbenutzer per Dialog und exportiert `TARGET_USER`.
- `tui_confirm_execution "stages" "user"`: Bestätigungsdialog vor dem Start der Installation.
---
## 5. Arbeitsanweisungen für Modifikationen
### Neue Phase (Stage) hinzufügen
1. Erstelle eine neue Datei `stages/XX-<name>.sh` (nummeriert nach Reihenfolge, mit `chmod +x`).
2. Nutze das Standard-Template:
```bash
#!/usr/bin/env bash
# ==============================================================================
# stages/XX-<name>.sh - Kurzbeschreibung der Phase
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/utils.sh
source "$SCRIPT_DIR/../lib/utils.sh"
setup_err_trap
require_root
log_step "Stage XX: <Name der Phase>"
TARGET_USER="${TARGET_USER:-$(prompt_target_user)}"
TARGET_HOME="$(get_target_home "$TARGET_USER")"
# Implementierung (idempotent) ...
log_success "Stage XX abgeschlossen."
```
3. Registriere die neue Phase im Orchestrator `setup.sh` (Hilfetext `show_help`, Validierung in `run_stages`).
4. Ergänze die Phase im TUI-Auswahlmenü in `lib/tui.sh`.
5. Aktualisiere `README.md`.
### Paketlisten anpassen
- Paketdateien liegen unter `config/packages/<kategorie>.list`.
- Jede Zeile enthält genau einen Paketnamen.
- Kommentare beginnen mit `#`. Leerzeilen sind erlaubt.
### Vorlagen und Skel-Dateien hinzufügen
- Konfigurationsvorlagen für neue Benutzer gehören in `data/skel/`.
- Dateivorlagen für den Dateimanager (XDG Templates) gehören nach `data/skel/Templates/`.
---
## 6. Verifikation & Qualitätssicherung
Bevor Änderungen eingecheckt oder abgeschlossen werden:
1. **ShellCheck ausführen**:
Alle Bash-Skripte auf statische Fehler und Warnungen prüfen:
```bash
shellcheck setup.sh lib/*.sh stages/*.sh
```
2. **Dry-Run Validierung**:
Sicherstellen, dass der Orchestrator im Simulationsmodus funktioniert:
```bash
./setup.sh --dry-run --stages 00,01,02
```
3. **Syntaxprüfung**:
```bash
bash -n setup.sh
for f in lib/*.sh stages/*.sh; do bash -n "$f"; done
```
4. **Pfad- und Berechtigungskonsistenz**:
Prüfen, dass keine absoluten Pfade auf Benutzerverzeichnisse (`/home/...`) hartcodiert sind.
+178 -21
View File
@@ -1,32 +1,189 @@
# Setup
# Debian Unstable (Sid) & Hyprland Setup Framework
## Übersicht
Ein modulares, sicheres und erweiterbares Framework zur automatisierten Einrichtung von **Debian GNU/Linux Unstable (Sid)** mit Hyprland Desktop, XanMod-Kernel, Hardware-Tuning und thematisch gegliederten Anwendungen.
Dieses Repository enthält Skripte um ein Linux System mit Hyprland und diversen Programmen aufzusetzen.
Die entsprechenden Skripte befinden sich in den Branches zur jeweiligen Distribution.
---
## Anforderungen
## 🚀 Schnellstart
Um die Skripte in diesem Repository auszuführen, stelle sicher, dass die folgenden Voraussetzungen erfüllt sind:
### 1. Web-Installer (Curl One-Liner)
Das Setup kann direkt ohne vorheriges manuelles Klonen via `curl` gestartet werden. Das Installationsskript (`install.sh`) installiert bei Bedarf `git`, klont das Repository automatisch in ein temporäres Verzeichnis (`/tmp`), startet den Orchestrator und räumt nach Abschluss sauber auf:
- Die Skripte sind als bash-Skripte konzipiert.
- Für die Skripte muss der richtige Branch der jewiligen Distribution ausgewählt werden.
- Daten werden vor der Ausführung nicht gesichert. Datenverlust möglich!
```bash
# Interaktiver Modus (whiptail Menü)
curl -fsSL https://gitea.creative-dragonslayer.de/Scripts/Setup/raw/branch/main/install.sh | bash
## Nutzung
# Vollautomatischer Modus (alle Stages 00 bis 11)
curl -fsSL https://gitea.creative-dragonslayer.de/Scripts/Setup/raw/branch/main/install.sh | bash -s -- --all
1. Klone das Repository:
```bash
git clone https://gitea.creative-dragonslayer.de/DragonSlayer_14/Setup.git
```
2. Wechsle in den richtigen Branch.
3. Navigiere in das Verzeichnis `Setup`, um die ausführbaren Dateien und Ressourcen zu finden.
4. Folge den spezifischen Anweisungen in einzelnen Dateien oder Skripten für die korrekte Ausführung.
# Gezielte Modulauswahl (z. B. Paketlisten und Schriften)
curl -fsSL https://gitea.creative-dragonslayer.de/Scripts/Setup/raw/branch/main/install.sh | bash -s -- --stages 04,05
```
## Lizenz
### 2. Manuelles Klonen & Starten
Alternativ kann das Repository manuell geklont und ausgeführt werden:
```bash
git clone https://gitea.creative-dragonslayer.de/Scripts/Setup.git && cd Setup && ./setup.sh
```
Oder direkt vollautomatisch alle Stages (`00` bis `10`) ausführen:
```bash
git clone https://gitea.creative-dragonslayer.de/Scripts/Setup.git && cd Setup && ./setup.sh --all
```
Dieses Projekt steht unter einer Open-Source-Lizenz. Weitere Informationen findest du in der Datei `LICENSE`.
> `setup.sh` fragt zuerst alle nötigen Eingaben (Modulauswahl, Zielbenutzer, ...) direkt am Terminal ab und eskaliert erst danach selbstständig per `sudo`. Ein manuelles `sudo` davor ist nicht nötig, funktioniert aber ebenfalls.
## Autor
### 3. Interaktiver TUI-Modus
Starte das grafische Terminal-Menü (`whiptail`) zur flexiblen Auswahl einzelner Module:
```bash
./setup.sh
```
Erstellt und gepflegt von DragonSlayer_14.
### 4. Vollautomatischer CLI-Modus
Führe alle Phasen (`00` bis `10`) ohne Interaktion aus:
```bash
./setup.sh --all
```
### 5. Gezielte Modulauswahl
Installiere nur bestimmte Phasen (z. B. nur Paketlisten und Schriften):
```bash
./setup.sh --stages 04,05
```
### 6. Simulationslauf (Dry-Run)
Überprüfe geplante Aktionen, ohne Änderungen am System vorzunehmen:
```bash
./setup.sh --dry-run --stages 01,02,04
```
---
## 🛠️ CLI-Optionen
| Option | Argument | Beschreibung |
| :--- | :--- | :--- |
| `-a`, `--all` | | Führt alle Phasen (`00` bis `10`) sequenziell aus |
| `-s`, `--stages` | `<01,02,...>` | Kommagetrennte Liste der auszuführenden Phasen |
| `-u`, `--user` | `<username>` | Zielbenutzer für Userland/Dotfiles (Standard: `$SUDO_USER` mit Bestätigungsabfrage) |
| `-d`, `--dry-run` | | Simuliert die Ausführung ohne Systemänderungen |
| `-h`, `--help` | | Zeigt die Hilfe und alle verfügbaren Stages an |
---
## 📁 Projektstruktur
```
.
├── install.sh # Web-Installer & Bootstrap-Skript (curl | bash, klont nach /tmp)
├── setup.sh # Zentraler Orchestrator (CLI Flags & whiptail TUI)
├── lib/ # Wiederverwendbare Hilfsbibliotheken
│ ├── utils.sh # Logging, Error-Traps (set -euo pipefail), Root/User-Erkennung & Abfrage
│ ├── apt.sh # APT-Keyring-Management (/etc/apt/keyrings/), Deb822, Pinning
│ ├── btrfs.sh # Btrfs Root- & Subvolume-Erkennung, Migration (@, @home), Timeshift-Snapshots
│ ├── network.sh # Loopback- & LAN-Schnittstellenkonfiguration (Debian Installer Standard)
│ └── tui.sh # Whiptail-Menüs und Dialoge
├── config/ # Konfigurationsdateien & Paketlisten
│ ├── setup.conf # Globale Variablen (Kernel, GRUB-Theme, Plymouth)
│ └── packages/ # Thematische Paketlisten
│ ├── 01-base.list # Grundlegende Systemwerkzeuge, Firmware, Microcode
│ ├── 02-desktop.list # Hyprland, Waybar, SDDM, Portale, Pipewire
│ ├── 03-gaming.list # Steam, Heroic, Lutris, Gamescope, MangoHud, Wine
│ ├── 04-virtualization.list # QEMU, KVM, Libvirt, Bridge-Tools
│ ├── 05-multimedia.list # VLC, Amberol, GIMP, Loupe, LibreOffice
│ └── 06-flatpaks.list # Flatpak App-IDs & Flathub
├── stages/ # Sequenzielle, modular ausführbare Phasen
│ ├── 00-preflight.sh # Prüfung von Rechten, Ziel-User ($SUDO_USER) und Internet
│ ├── 01-apt-unstable.sh # Deb822-Quellen, Keyrings, Pinning, apt-listbugs, dist-upgrade
│ ├── 02-kernel-hardware.sh # XanMod-Kernel (main/edge), CPU P-State, Microcode, auto-cpufreq (Source)
│ ├── 03-bootloader.sh # GRUB Kernel-Parameter, Vimix-Theme, Plymouth Solar
│ ├── 04-packages.sh # Installation der ausgewählten thematischen Paketlisten
│ ├── 05-fonts.sh # Download & Installation von JetBrainsMono, Fantasque, VictorMono
│ ├── 06-services.sh # Aktivierung von AppArmor, Docker, Libvirt, zram, Ollama
│ ├── 07-skel-and-user.sh # /etc/skel Vorlagen, ZSH-Shell-Setzen, Dotfiles-Sync
│ ├── 08-flatpaks.sh # Flathub Setup, Flatpak-Paketlisten-Installation
│ ├── 09-apps.sh # Spotify, Waydroid, OpenDeck, Desktop-Starter, MIME-Types
│ ├── 10-hyprland.sh # LinuxBeginnings Debian-Hyprland Auto-Installer & Dotfiles
│ └── 11-linutil.sh # Linutil (Chris Titus Tech System Toolbox), letzter Install-Schritt
└── data/ # Statische Konfigurationsdateien & Vorlagen
├── apt/
│ ├── sources.list.d/ # debian-unstable.sources, xanmod.sources
│ └── preferences.d/ # Pinning-Konfigurationen (unstable, xanmod)
├── etc/
│ ├── environment.d/ # 99-raytracing.conf, 99-upscaling.conf (99-shader-cache.conf wird optional zur Laufzeit generiert)
│ ├── gamemode.ini # GameMode Performance-Daemon Defaults
│ ├── polkit-1/rules.d/ # 90-corectrl.rules (passwortlose CoreCtrl-Freigabe für sudo-Gruppe)
│ └── profile.d/ # Bereinigte System-Profile-Skripte
├── skel/ # .zshrc, .config/hypr, .config/MangoHud, .config/vkBasalt, Templates für Dokumente & Skripte
└── usr/share/applications/ # Desktop-Dateien (z. B. Spotify)
```
---
## 🔒 Sicherheits- & Stabilitätsmerkmale
1. **Rechte- und Nutzertrennung**:
- Automatische Erkennung des regulären Desktop-Benutzers via `$SUDO_USER` / interactivem Fallback.
- Benutzerkonfigurationen und Gruppenrechte (`sudo`, `docker`, `libvirt`) werden sauber für den Zielbenutzer gesetzt.
2. **Keine gefährlichen Login-Hooks**:
- Vollständige Beseitigung unkontrollierter Live-Downloads (`curl | sh`) beim Login.
- Standardkonforme Bereitstellung über `/etc/skel` für neue und bestehende Benutzer.
3. **Idempotenz, Backups & Timeshift Btrfs-Snapshots**:
- Alle Phasen können beliebig oft wiederholt werden.
- Vorhandene Dotfiles (`~/.zshrc`) und Konfigurationen (`/etc/default/grub`) werden vor Änderungen automatisch mit Zeitstempel (`.backup_YYYYMMDD_HHMMSS`) gesichert.
- Auf Btrfs-Systemen werden mit Timeshift automatisch Rollback-Punkte vor und nach kritischen Operationen (Dist-Upgrade, Kernel-Installation, Paketinstallation, Desktop-Setup), bei jedem System-Update (automatischer APT/DPkg-Pre-Invoke-Hook) sowie bei jedem Systemstart (`timeshift-boot.service`) erstellt, wobei standardmäßig die letzten 5 Snapshots vorgehalten werden.
- Mittels `grub-btrfs` und dem Hintergrunddienst `grub-btrfsd` werden Btrfs-Snapshots automatisch in das GRUB-Bootmenü integriert, sodass direkt beim Systemstart in beliebige Snapshots gebootet werden kann.
4. **Debian Unstable Absicherung**:
- Moderne Deb822-Quellen und dedizierte Keyrings in `/etc/apt/keyrings/`.
- Installation von `apt-listbugs` und `apt-listchanges` vor dem `dist-upgrade` schützt vor bekannten kritischen Paketproblemen.
5. **Sichere Shell-Verwaltung**:
- Standardkonforme Änderung der Login-Shell via `chsh -s` statt direkter `/etc/passwd`-Modifikation.
6. **Netzwerk- & Schnittstellenkonfiguration (Debian Installer Standard)**:
- Automatische Erkennung und Konfiguration aller physischen LAN-Netzwerkschnittstellen via DHCP und IPv6 SLAAC (`allow-hotplug <iface>`, `iface <iface> inet dhcp`, `iface <iface> inet6 auto`).
- Standardkonforme Einrichtung des Loopback-Interfaces (`auto lo`, `iface lo inet loopback`) in `/etc/network/interfaces` und `/etc/hosts`.
- Nahtlose NetworkManager-Integration (`managed=true`) und Berechtigung des Zielbenutzers via `netdev`-Gruppe.
---
## 🎮 Gaming & Performance-Optimierungen
### GameMode, MangoHud & CoreCtrl
- **GameMode**: `stages/06-services.sh` rollt eine getunte `/etc/gamemode.ini` aus (`desiredgov=performance`, Renice, I/O-Priorität, AMD-GPU-Performance-Level `high`) und fügt den Zielbenutzer automatisch den Gruppen `gamemode` (Renice/Core-Parking) und `render` (Vulkan/GPU-Compute) hinzu.
- **MangoHud**: `data/skel/.config/MangoHud/MangoHud.conf` liefert ein vorkonfiguriertes Overlay (FPS, Frametime, CPU/GPU-Temperatur & -Takt, VRAM/RAM, GameMode-Indikator), das über `stages/07-skel-and-user.sh` automatisch für neue und bestehende Benutzer bereitgestellt wird. Umschalten mit `Shift+F12` (Position mit `Shift+F11`).
- **CoreCtrl**: Für Fankurven, Power-States und Undervolting von AMD-CPU/GPU. Eine PolicyKit-Regel (`90-corectrl.rules`) erlaubt Mitgliedern der `sudo`-Gruppe den Start ohne wiederholte Passwortabfrage.
### systemd-oomd (Out-of-Memory-Schutz)
- Wird aktiviert, um Einfrieren des Systems bei gleichzeitiger Speicher-/Swap-Auslastung (Spiel + Discord + Browser) zu verhindern ergänzt das bestehende zram-Swap.
### Sched-ext Gaming-Scheduler
- **sched-ext (`scx-scheds`)**: `stages/06-services.sh` installiert das Paket aus dem bereits konfigurierten XanMod-Repository und aktiviert den Scheduler `scx_lavd` (Latency-criticality Aware Virtual Deadline speziell für Gaming/interaktive Desktop-Workloads) im `--autopilot`-Modus über `/etc/default/scx` und `scx.service`. Benötigt einen Kernel mit `CONFIG_SCHED_CLASS_EXT` (bei XanMod bereits aktiv); nach einer frischen Kernel-Installation ist ggf. ein Neustart nötig.
### vkBasalt (Vulkan-Postprocessing)
- ReShade-ähnliche Vulkan-Postprocessing-Shader (Contrast Adaptive Sharpening als Standard) mit vorkonfigurierter `~/.config/vkBasalt/vkBasalt.conf`. Aktivierung pro Spiel über die Steam-Launch-Option `ENABLE_VKBASALT=1 %command%`; Status wird von MangoHud mit angezeigt.
### Persistenter Shader-Cache (optional)
- Standardmäßig bleiben Mesa (RADV/OpenGL) und DXVK (Wine/Proton) bei ihren eigenen Cache-Pfaden (`~/.cache/mesa_shader_cache`, `~/.cache/dxvk`). Wird `SHADER_CACHE_DIR` in `config/setup.conf` gesetzt (z. B. auf eine separate/schnelle Festplatte), verlegt `stages/02-kernel-hardware.sh` beide Caches dorthin, um Nachcompilierungs-Ruckler nach Neustarts zu vermeiden.
### CPU P-State & Kernel-Parameter
In `stages/03-bootloader.sh` wird der CPU-Hersteller automatisch ermittelt und in `/etc/default/grub` eingetragen:
- **AMD CPUs**: `amd_pstate=active`
- **Intel CPUs**: `intel_pstate=active`
- **Latenz-Optimierung**: `rcutree.rcu_idle_gp_delay=1 threadirqs`
### Game Launch-Parameter (Steam / Lutris)
```bash
# Standard Gaming Launch-Optionen mit MangoHud & Gamescope
gamemoderun gamescope -W 2560 -H 1440 --force-grab-cursor --hdr-enabled --adaptive-sync -f -o 240 -r 240 -- mangohud %command%
# Raytracing für DX12 Titel (RADV / Mesa)
RADV_PERFTEST=gpl,rt,ngg_streamout VKD3D_CONFIG=dxr,dxr11 DXVK_ASYNC=1 AMD_VULKAN_ICD=RADV gamemoderun gamescope -W 2560 -H 1440 --force-grab-cursor --hdr-enabled --adaptive-sync -f -o 240 -r 240 -- mangohud %command%
# Mit vkBasalt-Postprocessing (Schärfung via Contrast Adaptive Sharpening)
ENABLE_VKBASALT=1 gamemoderun gamescope -W 2560 -H 1440 --force-grab-cursor --hdr-enabled --adaptive-sync -f -o 240 -r 240 -- mangohud %command%
```
---
## 📜 Lizenz & Autor
- **Lizenz**: MIT License (siehe `LICENSE`)
- **Autor**: DragonSlayer_14
+87
View File
@@ -0,0 +1,87 @@
# ==============================================================================
# config/packages/01-base.list - Base system utilities, firmware, shell & diagnostics
# ==============================================================================
7zip
adb
apparmor
apparmor-notify
apparmor-profiles
apparmor-profiles-extra
apparmor-utils
apt-listbugs
apt-listchanges
aptitude
baobab
bat
bleachbit
bluetooth
blueman
bluez
bruno
btop
ca-certificates
clamav
clamav-daemon
clamav-docs
clamav-freshclam
command-not-found
cpupower-gui
cryptomator
curl
dconf-editor
debian-goodies
ethtool
fastfetch
file-roller
firmware-linux
firmware-linux-nonfree
firmware-misc-nonfree
flatpak
flatseal
fzf
git
glances
gnome-disk-utility
gnome-firmware
gnome-logs
gnome-system-monitor
gparted
htop
hunspell
hunspell-de-de-frami
ifupdown
inotify-tools
iproute2
irqbalance
isc-dhcp-client
keepassxc
lsd
man
net-tools
network-manager
network-manager-gnome
plymouth
plymouth-themes
resources
rfkill
ripgrep
rpi-imager
shellcheck
sl
systemd-oomd
systemd-timesyncd
tar
tealdeer
timeshift
topgrade
tree
unrar
unzip
wireless-regdb
wpasupplicant
zram-tools
zsh
zsh-autosuggestions
zsh-doc
zsh-syntax-highlighting
+40
View File
@@ -0,0 +1,40 @@
# ==============================================================================
# config/packages/02-desktop.list - Wayland/Hyprland desktop, display manager & tools
# ==============================================================================
cava
codium
dconf-editor
flameshot
floorp
fragments
gnome-calculator
gnome-decoder
gnome-font-viewer
gnome-keyring
gnome-snapshot
gnome-text-editor
grim
impression
input-remapper
kitty
localsend
nodejs
nwg-displays
nwg-look
obfuscate
pipewire
pipewire-pulse
remmina
sddm
slurp
speech-dispatcher
swappy
swaybg
thunar
vesktop
wayland-utils
wireplumber
wl-clipboard
xdg-user-dirs
yazi
+25
View File
@@ -0,0 +1,25 @@
# ==============================================================================
# config/packages/03-gaming.list - Gaming tools, Vulkan drivers, Wine & Emulation
# ==============================================================================
corectrl
gameconqueror
gamemode
gamescope
heroic
lutris
mangohud
mangoapp
mesa-utils
mesa-vulkan-drivers
openrgb
prismlauncher
protontricks
radeontop
steam-installer
steam-devices
vkbasalt
vkbasalt:i386
vulkan-tools
wine
winetricks
+10
View File
@@ -0,0 +1,10 @@
# ==============================================================================
# config/packages/04-virtualization.list - QEMU, KVM & Libvirt packages
# ==============================================================================
bridge-utils
libvirt-clients
libvirt-daemon-system
qemu-system-x86
qemu-utils
virt-manager
+22
View File
@@ -0,0 +1,22 @@
# ==============================================================================
# config/packages/05-multimedia.list - Audio, Video, Graphics & Productivity
# ==============================================================================
amberol
easyeffects
ffmpeg
gimp
libreoffice
libreoffice-gtk4
libreoffice-l10n-de
loupe
simple-scan
vlc
vlc-data
vlc-l10n
vlc-plugin-access-extra
vlc-plugin-base
vlc-plugin-notify
vlc-plugin-pipewire
vlc-plugin-qt
vlc-plugin-video-output
+17
View File
@@ -0,0 +1,17 @@
# ==============================================================================
# config/packages/06-flatpaks.list - Flathub Flatpak Application IDs
# ==============================================================================
# Communication & Productivity
eu.betterbird.Betterbird
im.fluffychat.Fluffychat
org.pvermeer.WebAppHub
io.github.giantpinkrobots.flatsweep
# Creativity & AI
org.musescore.MuseScore
com.jeffser.Alpaca
# Gaming & Compatibility
net.davidotek.pupgui2
io.github.rfrench3.scopebuddy-gui
+43
View File
@@ -0,0 +1,43 @@
# ==============================================================================
# config/setup.conf - Configuration parameters for Debian Unstable Setup
# ==============================================================================
# Kernel & Hardware
# XanMod branches: "main" (stable & recommended), "edge" (bleeding-edge), "lts" (long-term support), "rt" (real-time)
XANMOD_BRANCH="main"
CPU_PSTATE_AUTO=1
# Backup & System Snapshots (Timeshift Btrfs)
ENABLE_TIMESHIFT_SNAPSHOTS=1
TIMESHIFT_COUNT_BOOT=5
TIMESHIFT_SCHEDULE_BOOT="true"
TIMESHIFT_SNAPSHOT_ON_UPDATE="true"
ENABLE_GRUB_BTRFS=1
# Bootloader & Appearance
GRUB_THEME="vimix"
PLYMOUTH_THEME="solar"
GRUB_TIMEOUT=5
GRUB_TIMEOUT_STYLE="menu"
# Shell & Userland
DEFAULT_SHELL="zsh"
# Gaming: Persistent Shader Cache (Mesa & DXVK)
# Optional relocation of the shader/pipeline cache onto separate/bulk storage.
# Leave empty to keep Mesa's and DXVK's own default cache locations
# (~/.cache/mesa_shader_cache, ~/.cache/dxvk) - recommended unless you have a
# specific reason (small root disk, dedicated fast scratch drive, ...).
# Example: SHADER_CACHE_DIR="/mnt/Data/Software/mesa_shader_cache"
SHADER_CACHE_DIR=""
# Ollama AI Configuration
# Suggested custom models path, pre-filled only if the user declines
# Ollama's own default storage location (/usr/share/ollama/.ollama/models).
OLLAMA_MODELS_DEFAULT="/mnt/Data/Software/ollama/models"
OLLAMA_FLASH_ATTENTION="1"
OLLAMA_KV_CACHE_TYPE="q8_0"
OLLAMA_KEEP_ALIVE="30m"
# Default Stages (if --all is passed or in default batch mode)
ALL_STAGES="00 01 02 03 04 05 06 07 08 09 10"
+7
View File
@@ -0,0 +1,7 @@
Package: *
Pin: release a=unstable
Pin-Priority: 900
Package: *
Pin: release a=experimental
Pin-Priority: 100
+3
View File
@@ -0,0 +1,3 @@
Package: *
Pin: origin deb.xanmod.org
Pin-Priority: 900
+5
View File
@@ -0,0 +1,5 @@
Types: deb deb-src
URIs: http://deb.debian.org/debian/
Suites: unstable
Components: main non-free-firmware non-free contrib
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
@@ -0,0 +1,5 @@
Types: deb
URIs: https://gitea.creative-dragonslayer.de/api/packages/Linuxapps/debian/
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/gitea-Linuxapps.asc
@@ -0,0 +1,6 @@
Types: deb
URIs: https://gitea.creative-dragonslayer.de/api/packages/Mirror/debian/
Suites: stable
Components: main
Architectures: amd64
Signed-By: /etc/apt/keyrings/gitea-Mirror.asc
+5
View File
@@ -0,0 +1,5 @@
Types: deb
URIs: http://deb.xanmod.org
Suites: sid
Components: main
Signed-By: /etc/apt/keyrings/xanmod-archive-keyring.gpg
@@ -0,0 +1,3 @@
# Raytracing support environment flags for RADV / Mesa
VKD3D_CONFIG=dxr11,dxr
RADV_PERFTEST=rt
+3
View File
@@ -0,0 +1,3 @@
# Upscaling and gaming enhancement variables
WINE_FULLSCREEN_FSR=1
WINE_FULLSCREEN_FSR_STRENGTH=2
+34
View File
@@ -0,0 +1,34 @@
# ==============================================================================
# data/etc/gamemode.ini - GameMode performance daemon defaults
# ==============================================================================
# Deployed to /etc/gamemode.ini by stages/06-services.sh
# Full reference: /usr/share/gamemode/gamemode.ini
[general]
; Use the "performance" CPU governor while a game is running instead of
; "powersave"/"ondemand", restoring the previous governor once it exits.
desiredgov=performance
; Renice game processes for smoother frame pacing (0-20, applied as a negated
; nice value). Requires the target user to be a member of the "gamemode"
; group, which the setup framework adds automatically.
renice=5
; Lower I/O priority class while gaming (0 = highest Best-Effort priority).
ioprio=0
; Keep the screen from blanking/locking while a game has focus.
inhibit_screensaver=1
[gpu]
; Apply AMD/NVIDIA GPU performance-level optimisations while gaming.
apply_gpu_optimisations=accept-responsibility
gpu_device=0
; AMD: force the "high" DPM performance level during GameMode sessions
; (requires an up-to-date amdgpu kernel module).
amd_performance_level=high
; NVIDIA-specific PowerMizer tuning (nv_powermizer_mode, nv_core_clock_mhz_offset,
; nv_mem_clock_mhz_offset) requires the "coolbits" Xorg option and is not
; configured by default, since this setup targets AMD/Intel GPUs.
@@ -0,0 +1,10 @@
// Allow members of the "sudo" administrative group to start/stop CoreCtrl's
// privileged helper without an interactive PolicyKit password prompt.
// Deployed by stages/06-services.sh.
polkit.addRule(function(action, subject) {
if ((action.id == "org.corectrl.helper.init" ||
action.id == "org.corectrl.helperkiller.init") &&
subject.isInGroup("sudo")) {
return polkit.Result.YES;
}
});
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
# Update XDG User Dirs if tool is present
if command -v xdg-user-dirs-update >/dev/null 2>&1; then
xdg-user-dirs-update
fi
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
# Hide Waydroid desktop applications from standard desktop menus
if [ -d "$HOME/.local/share/applications" ]; then
for app in "$HOME"/.local/share/applications/waydroid.*.desktop; do
[ -f "$app" ] || continue
if ! grep -q "NoDisplay" "$app"; then
sed -i '/^Icon=/a NoDisplay=true' "$app" 2>/dev/null || true
fi
done
fi
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
# Add sbin and /usr/sbin to PATH for sudoers if not already present
if groups 2>/dev/null | grep -q "\bsudo\b"; then
case ":$PATH:" in
*":/sbin:"*) ;;
*) export PATH="$PATH:/sbin" ;;
esac
case ":$PATH:" in
*":/usr/sbin:"*) ;;
*) export PATH="$PATH:/usr/sbin" ;;
esac
fi
+23
View File
@@ -0,0 +1,23 @@
#!/bin/sh
# Display sudo reminder for administrative users once after initial setup
SUDO_FILE="$HOME/.sudo_as_admin_successful"
HUSH_FILE="$HOME/.hushlogin"
if [ -f "$SUDO_FILE" ]; then
FILE_MOD_TIME=$(stat -c %Y "$SUDO_FILE" 2>/dev/null || echo 0)
ONE_WEEK_AGO=$(date -d '7 days ago' +%s 2>/dev/null || echo 0)
if [ "$FILE_MOD_TIME" -gt 0 ] && [ "$ONE_WEEK_AGO" -gt 0 ] && [ "$FILE_MOD_TIME" -lt "$ONE_WEEK_AGO" ]; then
rm -f "$SUDO_FILE"
fi
fi
if [ ! -e "$SUDO_FILE" ] && [ ! -e "$HUSH_FILE" ]; then
case " $(groups 2>/dev/null) " in
*\ admin\ *|*\ sudo\ *)
if [ -x /usr/bin/sudo ]; then
echo 'To run a command as administrator (user "root"), use "sudo <command>".'
echo 'See "man sudo_root" for details.'
fi
;;
esac
fi
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
# /etc/profile.d/desktop_session_xdg_dirs.sh - Prepend a $DESKTOP_SESSION-named directory to $XDG_CONFIG_DIRS and $XDG_DATA_DIRS
DEFAULT_XDG_CONFIG_DIRS="/etc/xdg"
DEFAULT_XDG_DATA_DIRS="/usr/local/share/:/usr/share/"
if [ -n "$DESKTOP_SESSION" ]; then
# readd default if was empty
if [ -z "$XDG_CONFIG_DIRS" ]; then
XDG_CONFIG_DIRS="$DEFAULT_XDG_CONFIG_DIRS"
fi
if [ -n "${XDG_CONFIG_DIRS##*"$DEFAULT_XDG_CONFIG_DIRS"/xdg-"$DESKTOP_SESSION"*}" ]; then
XDG_CONFIG_DIRS="$DEFAULT_XDG_CONFIG_DIRS"/xdg-"$DESKTOP_SESSION":"$XDG_CONFIG_DIRS"
fi
export XDG_CONFIG_DIRS
# gnome is already added if gnome-session installed
if [ "$DESKTOP_SESSION" != "gnome" ]; then
if [ -z "$XDG_DATA_DIRS" ]; then
XDG_DATA_DIRS="$DEFAULT_XDG_DATA_DIRS"
fi
if [ -n "${XDG_DATA_DIRS##*/usr/share/"$DESKTOP_SESSION"*}" ]; then
XDG_DATA_DIRS=/usr/share/"$DESKTOP_SESSION":"$XDG_DATA_DIRS"
fi
export XDG_DATA_DIRS
fi
fi
@@ -0,0 +1,24 @@
[Unit]
Description=Ersteinrichtung: Dotfiles, Oh-My-Zsh, JetBrains Junie, Claude Code & Skills
# Systemweit installiert unter /etc/systemd/user/ und global aktiviert
# (siehe stages/10-hyprland.sh) - gilt fuer alle Benutzer, ohne dass etwas
# in einzelne Home-Verzeichnisse kopiert werden muss. Bewusst NICHT an
# Hyprland gebunden - laeuft ueber den systemd --user Manager, unabhaengig
# davon, welcher Compositor/welche Desktop-Sitzung gestartet wird.
After=default.target
StartLimitIntervalSec=300
StartLimitBurst=60
[Service]
Type=oneshot
ExecStart=/usr/local/lib/first-login-setup/first-login-setup.sh
# first-login-setup.sh beendet sich mit Exit-Code 1, solange die grafische
# Sitzung (Wayland-Socket) noch nicht bereit ist - in diesem Fall einfach
# erneut versuchen, bis sie verfuegbar ist. Das Skript selbst entscheidet
# anhand von ~/.local/state/first-login-setup/completed (pro Benutzer), ob
# es fuer den aktuellen Benutzer ueberhaupt noch etwas zu tun gibt.
Restart=on-failure
RestartSec=3
[Install]
WantedBy=default.target
+35
View File
@@ -0,0 +1,35 @@
### MangoHud default overlay configuration
### Deployed to ~/.config/MangoHud/MangoHud.conf via stages/07-skel-and-user.sh
### Full reference: https://github.com/flightlessmango/MangoHud/blob/master/data/MangoHud.conf
# Toggle the overlay on/off with Shift+F12, move it with Shift+F11
toggle_hud=Shift_L+F12
toggle_hud_position=Shift_L+F11
# Performance metrics
fps
frametime
frame_timing
cpu_stats
cpu_temp
cpu_power
gpu_stats
gpu_temp
gpu_power
gpu_core_clock
gpu_mem_clock
vram
ram
io_read
io_write
# GameMode / vkBasalt indicators
gamemode
vkbasalt
# Presentation
position=top-left
background_alpha=0.4
font_size=20
round_corners=6
table_columns=3
+100
View File
@@ -0,0 +1,100 @@
# ==============================================================================
# Rudimentäre Hyprland-Konfiguration (Standard für neue Benutzer)
# ==============================================================================
# Monitor Setup (Standard: Automatische Auflösung & Positionierung)
monitor = , preferred, auto, 1
# Modifikator-Taste: SUPER (Windows-Taste)
$mainMod = SUPER
# Standard-Terminal
$terminal = kitty
# ------------------------------------------------------------------------------
# Tastenbelegungen (Keybindings)
# ------------------------------------------------------------------------------
# SUPER + ENTER: Kitty Terminal öffnen
bind = $mainMod, RETURN, exec, $terminal
bind = $mainMod, Return, exec, $terminal
# SUPER + Q: Aktives Fenster schließen
bind = $mainMod, Q, killactive,
# Grundlegende Navigation & Fensterverwaltung
bind = $mainMod, M, exit,
bind = $mainMod, E, exec, thunar
bind = $mainMod, V, togglefloating,
bind = $mainMod, F, fullscreen,
# Fokus mit Pfeiltasten wechseln
bind = $mainMod, left, movefocus, l
bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
# Workspaces 1-10 wechseln
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Aktives Fenster auf Workspace 1-10 verschieben
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Fenster mit Maus bewegen und vergrößern/verkleinern
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# ------------------------------------------------------------------------------
# Erscheinungsbild & Verhalten
# ------------------------------------------------------------------------------
general {
gaps_in = 4
gaps_out = 8
border_size = 2
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = rgba(595959aa)
layout = dwindle
}
decoration {
rounding = 8
}
animations {
enabled = yes
}
input {
kb_layout = de
follow_mouse = 1
touchpad {
natural_scroll = yes
}
}
# ------------------------------------------------------------------------------
# Ersteinrichtung
# ------------------------------------------------------------------------------
# Dotfiles-Auswahl, Oh-My-Zsh, JetBrains Junie CLI & AwesomeJunieSkills starten
# automatisch beim Login über den systemweiten systemd --user Service
# 'first-login-setup.service' (/etc/systemd/user/) - bewusst NICHT hier per
# exec-once, damit die Ersteinrichtung unabhängig vom gewählten Compositor
# funktioniert. Manueller Aufruf jederzeit möglich mit:
# /usr/local/lib/first-login-setup/first-login-setup.sh --force
+18
View File
@@ -0,0 +1,18 @@
### vkBasalt default post-processing configuration
### Deployed to ~/.config/vkBasalt/vkBasalt.conf via stages/07-skel-and-user.sh
### Full reference: https://github.com/DadSchoorse/vkBasalt
###
### Only active for games launched with ENABLE_VKBASALT=1, e.g. as a Steam
### launch option: ENABLE_VKBASALT=1 %command%
# Effect chain to apply, in order
effects = cas
# Contrast Adaptive Sharpening strength (0.0 - 1.0)
casSharpness = 0.4
# Apply the effect chain immediately without needing to press toggleKey first
enableOnLaunch = True
# Key to toggle all effects on/off at runtime
toggleKey = Home
+75
View File
@@ -0,0 +1,75 @@
# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH
export ZSH="$HOME/.oh-my-zsh"
# Automatic Oh-My-Zsh installation on login / shell startup if not yet installed
if [[ ! -d "$ZSH" ]]; then
if command -v git >/dev/null 2>&1; then
echo "Oh-My-Zsh ist nicht eingerichtet. Installiere Oh-My-Zsh für $USER..."
if git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git "$ZSH" 2>/dev/null; then
mkdir -p "${ZSH_CUSTOM:-$ZSH/custom}/plugins"
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-autosuggestions" 2>/dev/null || true
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-syntax-highlighting" 2>/dev/null || true
echo "Oh-My-Zsh erfolgreich eingerichtet."
fi
fi
else
# Plugins sicherstellen, falls Oh-My-Zsh existiert aber Custom-Plugins fehlen
if [[ ! -d "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-autosuggestions" ]] && command -v git >/dev/null 2>&1; then
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-autosuggestions" 2>/dev/null || true
fi
if [[ ! -d "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-syntax-highlighting" ]] && command -v git >/dev/null 2>&1; then
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting "${ZSH_CUSTOM:-$ZSH/custom}/plugins/zsh-syntax-highlighting" 2>/dev/null || true
fi
fi
apt_pref='apt'
apt_upgr='upgrade'
ZSH_THEME="agnosterzak"
plugins=(
alias-finder
aliases
colored-man-pages
command-not-found
common-aliases
composer
cp
debian
docker
git
jsontools
kitty
python
ssh
symfony
themes
vscode
zsh-autosuggestions
zsh-syntax-highlighting
)
# Oh-My-Zsh configuration
if [[ -d "$ZSH" && -f "$ZSH/oh-my-zsh.sh" ]]; then
source "$ZSH/oh-my-zsh.sh"
fi
# Fastfetch system info banner
if command -v fastfetch >/dev/null 2>&1; then
if [[ -f "$HOME/.config/fastfetch/config-compact.jsonc" ]]; then
fastfetch -c "$HOME/.config/fastfetch/config-compact.jsonc"
else
fastfetch
fi
fi
# Aliases using modern tools with fallback
if command -v lsd >/dev/null 2>&1; then
alias ls='lsd'
alias l='ls -l'
alias la='ls -a'
alias lla='ls -la'
alias lt='ls --tree'
fi
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env python3
+1
View File
@@ -0,0 +1 @@
BIN
View File
Binary file not shown.
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/_lib.sh
# Gemeinsame Farbcodes & Ausgabe-Helfer für die first-login-setup.sh Skripte.
# Nicht zur direkten Ausführung gedacht - wird von den anderen Skripten source't.
# ==============================================================================
CLR_RESET='\033[0m'
CLR_BOLD='\033[1m'
CLR_CYAN='\033[0;36m'
CLR_GREEN='\033[0;32m'
CLR_YELLOW='\033[0;33m'
CLR_RED='\033[0;31m'
CLR_BLUE='\033[0;34m'
CLR_MAGENTA='\033[0;35m'
print_header() {
printf "\n"
printf "%b\n" "${CLR_BOLD}${CLR_CYAN}==============================================================================${CLR_RESET}"
printf "%b\n" "${CLR_BOLD}${CLR_CYAN}$1${CLR_RESET}"
printf "%b\n" "${CLR_BOLD}${CLR_CYAN}==============================================================================${CLR_RESET}"
printf "\n"
}
print_info() {
printf "%b\n" "${CLR_CYAN}[INFO] $*${CLR_RESET}"
}
print_success() {
printf "%b\n" "${CLR_GREEN}[✓] $*${CLR_RESET}"
}
print_warn() {
printf "%b\n" "${CLR_YELLOW}[WARNUNG] $*${CLR_RESET}"
}
print_error() {
printf "%b\n" "${CLR_RED}[FEHLER] $*${CLR_RESET}"
}
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/first-login-setup.sh
# Ersteinrichtung nach der ersten Anmeldung. Führt der Reihe nach aus:
# 1) setup-dotfiles.sh - Desktop-Konfiguration (LinuxBeginnings / eigenes Repo)
# 2) setup-shell.sh - Oh-My-Zsh & Plugins
# 3) setup-junie-cli.sh - JetBrains Junie CLI
# 4) setup-junie-skills.sh - AwesomeJunieSkills
# 5) setup-claude-cli.sh - Claude Code (Anthropic)
# 6) setup-claude-skills.sh - Awesome LLM Skills
#
# Wird automatisch beim Login über den systemweiten systemd --user Service
# 'first-login-setup.service' (/etc/systemd/user/) gestartet - bewusst NICHT
# über hyprland.conf, damit die Ersteinrichtung unabhängig vom gewählten
# Compositor funktioniert. Kann jederzeit auch manuell aufgerufen werden.
# Jedes der obigen Skripte kann auch einzeln & unabhängig ausgeführt werden.
#
# Liegt system- statt benutzerweit unter /usr/local/lib (eine gemeinsame
# Kopie für alle Benutzer, statt in jedes Home dupliziert zu werden), und
# NICHT unter ~/.config: setup-dotfiles.sh kann ~/.config komplett durch ein
# eigenes Dotfiles-Repository ersetzen - das darf weder dieses Skript noch
# den Fortschritt (siehe MARKER_FILE) mit sich reißen.
#
# Läuft wirklich nur bei der allerersten Anmeldung eines Benutzers, oder
# erneut, wenn zuvor explizit "Später" gewählt wurde (siehe unten) - danach
# nie wieder, sobald MARKER_FILE gesetzt ist.
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib.sh
source "$SCRIPT_DIR/_lib.sh"
MARKER_FILE="$HOME/.local/state/first-login-setup/completed"
FORCE=0
for arg in "$@"; do
case "$arg" in
-f|--force)
FORCE=1
;;
esac
done
# Wenn bereits abgeschlossen und kein --force übergeben wurde, beenden.
# (Ein zuvor gewähltes "Später" setzt MARKER_FILE bewusst NICHT, siehe unten -
# das Skript fragt in diesem Fall beim nächsten Login erneut.)
if [[ "$FORCE" -eq 0 && -f "$MARKER_FILE" ]]; then
exit 0
fi
# Wenn nicht in einem interaktiven Terminal ausgeführt (z. B. via systemd
# --user Service oder Keybind ohne Terminal), starte das Skript in einem
# Kitty-Fenster:
if [[ ! -t 0 || ! -t 1 ]]; then
# Beim Start über systemd --user ist WAYLAND_DISPLAY/DISPLAY meist nicht
# gesetzt, da der Dienst unabhängig vom Compositor läuft. Das
# Wayland-Socket direkt suchen, statt uns auf eine importierte Umgebung
# zu verlassen.
if [[ -z "${WAYLAND_DISPLAY:-}" && -z "${DISPLAY:-}" && -n "${XDG_RUNTIME_DIR:-}" ]]; then
wl_socket="$(find "$XDG_RUNTIME_DIR" -maxdepth 1 -name 'wayland-*' ! -name '*.lock' 2>/dev/null | head -n1)"
if [[ -n "$wl_socket" ]]; then
export WAYLAND_DISPLAY
WAYLAND_DISPLAY="$(basename "$wl_socket")"
fi
fi
if [[ -z "${WAYLAND_DISPLAY:-}" && -z "${DISPLAY:-}" ]]; then
# Grafische Sitzung ist noch nicht bereit (z. B. Compositor startet
# gerade erst). Mit Exit-Code 1 beenden, damit systemd den Dienst
# gemäß 'Restart=on-failure' erneut versucht.
exit 1
fi
if command -v kitty >/dev/null 2>&1; then
exec kitty --title "System-Ersteinrichtung & Dotfiles" bash -c "$0 --in-terminal; echo; read -r -p 'Drücke Enter zum Schließen...' || true"
else
exit 0
fi
fi
mark_as_prompted() {
mkdir -p "$(dirname "$MARKER_FILE")" 2>/dev/null || true
touch "$MARKER_FILE" 2>/dev/null || true
}
clear 2>/dev/null || true
print_header " Hyprland Desktop - Ersteinrichtung "
printf "%b\n" "Willkommen auf Ihrem neuen Debian Unstable Hyprland-System!"
printf "\n"
printf "%b\n" "Aktuell ist eine rudimentäre Basiskonfiguration aktiv:"
printf "%b\n" " - ${CLR_BOLD}SUPER + ENTER${CLR_RESET} : Terminal (Kitty) öffnen"
printf "%b\n" " - ${CLR_BOLD}SUPER + Q${CLR_RESET} : Aktives Fenster schließen"
printf "\n"
printf "%b\n" "Folgende Schritte können nacheinander ausgeführt werden:"
printf "%b\n" " 1) Desktop-Konfiguration (Dotfiles)"
printf "%b\n" " 2) Oh-My-Zsh & Shell-Plugins"
printf "%b\n" " 3) JetBrains Junie CLI"
printf "%b\n" " 4) AwesomeJunieSkills"
printf "%b\n" " 5) Claude Code"
printf "%b\n" " 6) Awesome LLM Skills"
printf "\n"
printf "%b\n" "${CLR_BOLD}${CLR_CYAN}------------------------------------------------------------------------------${CLR_RESET}"
# Explizite Ja/Später-Abfrage: Nur bei "Jetzt" wird MARKER_FILE gesetzt.
# Bei "Später" bricht das Skript ohne Marker ab, sodass es beim nächsten
# Login erneut über first-login-setup.service gestartet wird und wieder fragt.
answer=""
read -r -p "Ersteinrichtung jetzt durchführen? [J]etzt / [S]päter (beim nächsten Login erneut fragen): " answer || answer="j"
answer="$(echo "$answer" | xargs)"
if [[ "$answer" =~ ^[Ss] ]]; then
printf "\n"
print_warn "Ersteinrichtung verschoben. Sie werden beim nächsten Login erneut gefragt."
printf "%b\n" "Manueller Aufruf jederzeit möglich mit: ${CLR_BOLD}/usr/local/lib/first-login-setup/first-login-setup.sh${CLR_RESET}"
exit 0
fi
bash "$SCRIPT_DIR/setup-dotfiles.sh"
bash "$SCRIPT_DIR/setup-shell.sh"
bash "$SCRIPT_DIR/setup-junie-cli.sh"
bash "$SCRIPT_DIR/setup-junie-skills.sh"
bash "$SCRIPT_DIR/setup-claude-cli.sh"
bash "$SCRIPT_DIR/setup-claude-skills.sh"
mark_as_prompted
printf "\n"
print_success "Ersteinrichtung vollständig abgeschlossen!"
printf "%b\n" "Sie können dieses Menü jederzeit erneut aufrufen mit:"
printf "%b\n" " ${CLR_BOLD}/usr/local/lib/first-login-setup/first-login-setup.sh --force${CLR_RESET}"
printf "%b\n" "Oder einzelne Schritte direkt erneut ausführen, z. B.:"
printf "%b\n" " ${CLR_BOLD}/usr/local/lib/first-login-setup/setup-junie-skills.sh${CLR_RESET}"
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/setup-claude-cli.sh
# Installiert Claude Code (Anthropic) über den offiziellen nativen Installer.
#
# Kann eigenständig ausgeführt werden, unabhängig von first-login-setup.sh.
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib.sh
source "$SCRIPT_DIR/_lib.sh"
install_claude_cli() {
print_header " Claude Code Installation "
if command -v curl >/dev/null 2>&1; then
if curl -fsSL https://claude.ai/install.sh | bash; then
print_success "Claude Code erfolgreich installiert."
else
print_warn "Installation von Claude Code fehlgeschlagen oder unterbrochen."
fi
else
print_error "'curl' ist nicht installiert. Claude Code konnte nicht geladen werden."
fi
}
# Nur ausführen, wenn das Skript direkt gestartet wird (nicht bei source)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
install_claude_cli
fi
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/setup-claude-skills.sh
# Klont/aktualisiert Awesome LLM Skills (https://github.com/Prat011/awesome-llm-skills)
# in ~/.claude/skills und verknüpft alle gefundenen Skills, damit Claude Code
# sie automatisch erkennt.
#
# Kann eigenständig ausgeführt werden, unabhängig von first-login-setup.sh.
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib.sh
source "$SCRIPT_DIR/_lib.sh"
install_claude_skills() {
print_header " Awesome LLM Skills Installation "
local skills_dir="$HOME/.claude/skills"
local repo_dir="$skills_dir/awesome-llm-skills"
mkdir -p "$skills_dir"
if ! command -v git >/dev/null 2>&1; then
print_error "'git' ist nicht installiert. Awesome LLM Skills konnte nicht eingerichtet werden."
return 1
fi
if [[ -d "$repo_dir/.git" ]]; then
print_info "Repository existiert bereits in $repo_dir. Führe 'git pull' aus..."
if git -C "$repo_dir" pull --ff-only 2>/dev/null; then
print_success "Awesome LLM Skills erfolgreich aktualisiert."
else
print_warn "'git pull' in $repo_dir fehlgeschlagen."
fi
else
print_info "Klone Awesome LLM Skills nach $repo_dir..."
rm -rf "$repo_dir" 2>/dev/null || true
if git clone https://github.com/Prat011/awesome-llm-skills.git "$repo_dir"; then
print_success "Awesome LLM Skills erfolgreich nach $repo_dir geklont."
else
print_warn "Klonen von Awesome LLM Skills fehlgeschlagen."
fi
fi
# Symlinks für alle Skills im Skill-Hauptordner erstellen
if [[ -d "$repo_dir" ]]; then
local count=0
for skill_path in "$repo_dir"/*; do
if [[ -d "$skill_path" && -f "$skill_path/SKILL.md" ]]; then
local s_name
s_name="$(basename "$skill_path")"
ln -sfn "$skill_path" "$skills_dir/$s_name"
((count++)) || true
fi
done
print_success "$count Skills verknüpft in '$skills_dir' (kann via 'git pull' in '$repo_dir' aktualisiert werden)."
fi
}
# Nur ausführen, wenn das Skript direkt gestartet wird (nicht bei source)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
install_claude_skills
fi
+185
View File
@@ -0,0 +1,185 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/setup-dotfiles.sh
# Interaktive Auswahl & Einrichtung der Desktop-Konfiguration (Dotfiles):
# LinuxBeginnings Hyprland-Dots, eigenes Git-Repository, oder überspringen.
#
# Kann eigenständig ausgeführt werden, unabhängig von first-login-setup.sh.
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib.sh
source "$SCRIPT_DIR/_lib.sh"
install_linuxbeginnings() {
printf "\n"
printf "%b\n" "${CLR_GREEN}${CLR_BOLD}[INFO] Starte Installation der LinuxBeginnings Hyprland-Dotfiles...${CLR_RESET}"
printf "\n"
if command -v curl >/dev/null 2>&1; then
sh <(curl -fsSL https://raw.githubusercontent.com/LinuxBeginnings/Hyprland-Dots/main/Distro-Hyprland.sh)
else
print_error "'curl' ist nicht installiert. Bitte installieren Sie curl und wiederholen Sie den Vorgang."
fi
}
clone_custom_repo() {
if ! command -v git >/dev/null 2>&1; then
printf "\n"
print_error "'git' ist nicht installiert. Bitte installieren Sie git zuerst."
return 1
fi
while true; do
printf "\n"
printf "%b\n" "${CLR_BOLD}${CLR_CYAN}--- Eigenes Git-Repository für ~/.config klonen ---${CLR_RESET}"
printf "%b\n" "Geben Sie die Git-URL Ihres Dotfiles-/Config-Repositories an."
printf "%b\n" "Beispiele:"
printf "%b\n" " HTTPS : ${CLR_BLUE}https://github.com/Benutzername/mein-config-repo.git${CLR_RESET}"
printf "%b\n" " SSH : ${CLR_BLUE}git@github.com:Benutzername/mein-config-repo.git${CLR_RESET}"
printf "\n"
printf "%b\n" "${CLR_YELLOW}Hinweise zur Authentifizierung:${CLR_RESET}"
printf "%b\n" " - ${CLR_BOLD}HTTPS:${CLR_RESET} Bei privaten Repositories fragt Git nach Benutzername & Personal Access Token (PAT)."
printf "%b\n" " - ${CLR_BOLD}SSH:${CLR_RESET} Erfordert einen hinterlegten SSH-Schlüssel (z. B. in ~/.ssh/ oder via ssh-agent)."
printf "\n"
read -r -p "Git-Repository-URL (oder 'q' zum Abbrechen): " repo_url
repo_url="$(echo "$repo_url" | xargs)"
if [[ "$repo_url" == "q" || "$repo_url" == "Q" || -z "$repo_url" ]]; then
print_warn "Vorgang abgebrochen. Kehre zum Hauptmenü zurück."
return 0
fi
# SSH-Prüfung und Hilfestellung
if [[ "$repo_url" =~ ^git@ || "$repo_url" =~ ^ssh:// ]]; then
local ssh_keys_found=0
if [[ -d "$HOME/.ssh" ]]; then
for k in "$HOME/.ssh"/id_*; do
if [[ -f "$k" && ! "$k" =~ \.pub$ ]]; then
ssh_keys_found=1
break
fi
done
fi
if [[ "$ssh_keys_found" -eq 0 ]]; then
printf "\n"
print_warn "Es wurde kein lokaler SSH-Privatschlüssel in ~/.ssh/ gefunden."
read -r -p "Möchten Sie vor dem Klonen ein neues SSH-Schlüsselpaar (ed25519) generieren? [j/N]: " gen_ssh || gen_ssh="n"
if [[ "$gen_ssh" =~ ^[JjYy] ]]; then
mkdir -p "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
ssh-keygen -t ed25519 -f "$HOME/.ssh/id_ed25519" -C "$USER@$(hostname)"
printf "\n%b\n" "${CLR_GREEN}Neuer öffentlicher SSH-Schlüssel (~/.ssh/id_ed25519.pub):${CLR_RESET}"
cat "$HOME/.ssh/id_ed25519.pub"
printf "\n%b\n" "Bitte fügen Sie diesen Schlüssel bei GitHub/GitLab zu Ihrem Account hinzu."
if command -v wl-copy >/dev/null 2>&1; then
if wl-copy < "$HOME/.ssh/id_ed25519.pub" 2>/dev/null; then
print_success "(In die Zwischenablage kopiert!)"
fi
fi
read -r -p "Drücken Sie Enter, sobald der SSH-Key hinterlegt wurde..."
fi
fi
fi
# Backup und Klon-Vorgang vorbereiten
local timestamp
timestamp="$(date +%Y%m%d_%H%M%S)"
local backup_dir="$HOME/.config.backup_$timestamp"
printf "\n"
printf "%b\n" "${CLR_CYAN}[1/3] Sichere bestehendes ~/.config-Verzeichnis nach ${backup_dir}...${CLR_RESET}"
if [[ -d "$HOME/.config" ]]; then
mv "$HOME/.config" "$backup_dir"
fi
printf "%b\n" "${CLR_CYAN}[2/3] Klone Repository direkt nach ~/.config...${CLR_RESET}"
# Git ausführen mit aktivierter Terminal-Eingabeaufforderung für Authentifizierung
if env GIT_TERMINAL_PROMPT=1 git clone --recurse-submodules "$repo_url" "$HOME/.config"; then
printf "\n"
printf "%b\n" "${CLR_GREEN}${CLR_BOLD}[ERFOLG] Repository wurde erfolgreich nach ~/.config geklont!${CLR_RESET}"
printf "%b\n" " - Ihr gesamter ${CLR_BOLD}~/.config${CLR_RESET}-Ordner ist nun das Git-Repository."
printf "%b\n" " - Vorherige Konfigurationen wurden gesichert in: ${CLR_BOLD}${backup_dir}${CLR_RESET}"
# Hyprland-Konfiguration neu laden falls aktiv
if command -v hyprctl >/dev/null 2>&1; then
printf "\n"
printf "%b\n" "${CLR_CYAN}[3/3] Lade Hyprland-Konfiguration neu...${CLR_RESET}"
hyprctl reload 2>/dev/null || true
print_success "Hyprland erfolgreich aktualisiert."
fi
printf "\n"
print_success "Dotfiles-Einrichtung abgeschlossen!"
return 0
else
printf "\n"
print_error "Git Clone ist fehlgeschlagen (Authentifizierungsfehler, falsche URL oder Netzwerkproblem)."
print_warn "[ROLLBACK] Stelle vorheriges ~/.config-Verzeichnis aus dem Backup wieder her..."
rm -rf "$HOME/.config" 2>/dev/null || true
if [[ -d "$backup_dir" ]]; then
mv "$backup_dir" "$HOME/.config"
print_success "Ursprüngliches ~/.config-Verzeichnis wurde vollständig wiederhergestellt."
fi
printf "\n"
read -r -p "Möchten Sie es erneut versuchen? [J/n]: " retry || retry="n"
if [[ ! "$retry" =~ ^[JjYy] && -n "$retry" ]]; then
return 0
fi
fi
done
}
run_dotfiles_menu() {
print_header " Hyprland Desktop - Dotfiles Setup & Konfiguration "
printf "%b\n" "Wie möchten Sie Ihre Desktop-Konfiguration (Dotfiles) einrichten?"
printf "\n"
printf "%b\n" " ${CLR_BOLD}[1]${CLR_RESET} ${CLR_GREEN}LinuxBeginnings Hyprland-Dotfiles installieren${CLR_RESET}"
printf "%b\n" " Vollständig vorkonfiguriertes Setup (Waybar, Rofi, Animationen, Themes)"
printf "%b\n" " URL: https://github.com/LinuxBeginnings/Hyprland-Dots"
printf "\n"
printf "%b\n" " ${CLR_BOLD}[2]${CLR_RESET} ${CLR_MAGENTA}Eigenes Git-Repository als ~/.config klonen${CLR_RESET}"
printf "%b\n" " Klont Ihr eigenes Git-Repository direkt als vollständigen ~/.config-Ordner."
printf "%b\n" " (Unterstützt HTTPS & SSH inkl. Authentifizierung)"
printf "\n"
printf "%b\n" " ${CLR_BOLD}[3]${CLR_RESET} ${CLR_YELLOW}Überspringen / Basiskonfiguration beibehalten${CLR_RESET}"
printf "%b\n" " Keine Änderungen vornehmen (kann später manuell eingerichtet werden)."
printf "\n"
printf "%b\n" "${CLR_BOLD}${CLR_CYAN}------------------------------------------------------------------------------${CLR_RESET}"
while true; do
read -r -p "Bitte wählen Sie eine Option [1-3] (Standard: 1): " choice || choice="1"
choice="$(echo "$choice" | xargs)"
[[ -z "$choice" ]] && choice="1"
case "$choice" in
1)
install_linuxbeginnings
break
;;
2)
clone_custom_repo
break
;;
3)
printf "\n"
print_warn "Dotfiles-Einrichtung übersprungen. Die Basiskonfiguration bleibt aktiv."
break
;;
*)
print_error "Ungültige Eingabe. Bitte 1, 2 oder 3 wählen."
;;
esac
done
}
# Nur ausführen, wenn das Skript direkt gestartet wird (nicht bei source)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
run_dotfiles_menu
fi
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/setup-junie-cli.sh
# Installiert die JetBrains Junie CLI.
#
# Kann eigenständig ausgeführt werden, unabhängig von first-login-setup.sh.
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib.sh
source "$SCRIPT_DIR/_lib.sh"
install_junie_cli() {
print_header " JetBrains Junie CLI Installation "
if command -v curl >/dev/null 2>&1; then
if curl -fsSL https://junie.jetbrains.com/install.sh | bash; then
print_success "JetBrains Junie CLI erfolgreich installiert."
else
print_warn "Installation von JetBrains Junie CLI fehlgeschlagen oder unterbrochen."
fi
else
print_error "'curl' ist nicht installiert. Junie CLI konnte nicht geladen werden."
fi
}
# Nur ausführen, wenn das Skript direkt gestartet wird (nicht bei source)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
install_junie_cli
fi
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/setup-junie-skills.sh
# Klont/aktualisiert AwesomeJunieSkills in ~/.junie/skills, verknüpft alle
# gefundenen Skills und trägt das Repository in ~/.junie/config.json ein.
#
# Kann eigenständig ausgeführt werden, unabhängig von first-login-setup.sh.
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib.sh
source "$SCRIPT_DIR/_lib.sh"
install_junie_skills() {
print_header " AwesomeJunieSkills Installation "
local skills_dir="$HOME/.junie/skills"
local repo_dir="$skills_dir/awesome-junie-skills"
mkdir -p "$skills_dir"
if ! command -v git >/dev/null 2>&1; then
print_error "'git' ist nicht installiert. AwesomeJunieSkills konnte nicht eingerichtet werden."
return 1
fi
if [[ -d "$repo_dir/.git" ]]; then
print_info "Repository existiert bereits in $repo_dir. Führe 'git pull' aus..."
if git -C "$repo_dir" pull --ff-only 2>/dev/null; then
print_success "AwesomeJunieSkills erfolgreich aktualisiert."
else
print_warn "'git pull' in $repo_dir fehlgeschlagen."
fi
else
print_info "Klone AwesomeJunieSkills nach $repo_dir..."
rm -rf "$repo_dir" 2>/dev/null || true
if git clone https://github.com/alebaffa/awesome-junie-skills.git "$repo_dir"; then
print_success "AwesomeJunieSkills erfolgreich nach $repo_dir geklont."
else
print_warn "Klonen von AwesomeJunieSkills fehlgeschlagen."
fi
fi
# Symlinks für alle Skills im Skill-Hauptordner erstellen
if [[ -d "$repo_dir" ]]; then
local count=0
for skill_path in "$repo_dir"/*; do
if [[ -d "$skill_path" && -f "$skill_path/SKILL.md" ]]; then
local s_name
s_name="$(basename "$skill_path")"
ln -sfn "$skill_path" "$skills_dir/$s_name"
((count++)) || true
fi
done
print_success "$count Skills verknüpft in '$skills_dir' (kann via 'git pull' in '$repo_dir' aktualisiert werden)."
fi
# Junie config.json konfigurieren (skill-locations)
mkdir -p "$HOME/.junie"
local config_file="$HOME/.junie/config.json"
if command -v python3 >/dev/null 2>&1; then
python3 -c "
import json, os
cfg_path = os.path.expanduser('$config_file')
repo_path = os.path.expanduser('$repo_dir')
data = {}
if os.path.exists(cfg_path):
try:
with open(cfg_path, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception:
data = {}
locs = data.get('skill-locations', [])
if repo_path not in locs:
locs.append(repo_path)
data['skill-locations'] = locs
with open(cfg_path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2)
" 2>/dev/null || true
fi
}
# Nur ausführen, wenn das Skript direkt gestartet wird (nicht bei source)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
install_junie_skills
fi
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/lib/first-login-setup/setup-shell.sh
# Richtet Oh-My-Zsh samt nützlicher Plugins (autosuggestions, syntax-highlighting)
# für den aktuellen Benutzer ein.
#
# Kann eigenständig ausgeführt werden, unabhängig von first-login-setup.sh.
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_lib.sh
source "$SCRIPT_DIR/_lib.sh"
install_oh_my_zsh() {
local zsh_dir="$HOME/.oh-my-zsh"
print_header " Oh-My-Zsh & Shell-Konfiguration "
if [[ ! -d "$zsh_dir" ]]; then
print_info "Richte Oh-My-Zsh für $USER ein..."
if command -v git >/dev/null 2>&1; then
if git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git "$zsh_dir"; then
mkdir -p "$zsh_dir/custom/plugins"
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$zsh_dir/custom/plugins/zsh-autosuggestions" 2>/dev/null || true
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting "$zsh_dir/custom/plugins/zsh-syntax-highlighting" 2>/dev/null || true
print_success "Oh-My-Zsh erfolgreich eingerichtet."
else
print_warn "Oh-My-Zsh konnte nicht geklont werden."
fi
else
print_error "'git' ist nicht installiert. Oh-My-Zsh konnte nicht eingerichtet werden."
fi
else
# Plugins sicherstellen
if [[ ! -d "$zsh_dir/custom/plugins/zsh-autosuggestions" ]] && command -v git >/dev/null 2>&1; then
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$zsh_dir/custom/plugins/zsh-autosuggestions" 2>/dev/null || true
fi
if [[ ! -d "$zsh_dir/custom/plugins/zsh-syntax-highlighting" ]] && command -v git >/dev/null 2>&1; then
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting "$zsh_dir/custom/plugins/zsh-syntax-highlighting" 2>/dev/null || true
fi
print_success "Oh-My-Zsh ist bereits vorhanden und konfiguriert."
fi
}
# Nur ausführen, wenn das Skript direkt gestartet wird (nicht bei source)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
install_oh_my_zsh
fi
+7
View File
@@ -0,0 +1,7 @@
[Desktop Entry]
Name=Spotify
Exec=/usr/bin/spotify
Icon=spotify-client
Terminal=false
Type=Application
Categories=Audio;Music;
Executable
+141
View File
@@ -0,0 +1,141 @@
#!/usr/bin/env bash
# ==============================================================================
# install.sh - Web installer and bootstrap script for Debian Setup Framework
# ==============================================================================
# Usage:
# curl -fsSL https://gitea.creative-dragonslayer.de/Scripts/Setup/raw/branch/main/install.sh | bash
# curl -fsSL https://gitea.creative-dragonslayer.de/Scripts/Setup/raw/branch/main/install.sh | bash -s -- --all
# ==============================================================================
set -euo pipefail
# ANSI Color Codes
CLR_RESET='\033[0m'
CLR_BOLD='\033[1m'
CLR_RED='\033[0;31m'
CLR_GREEN='\033[0;32m'
CLR_YELLOW='\033[0;33m'
CLR_BLUE='\033[0;34m'
CLR_CYAN='\033[0;36m'
if [[ ! -t 1 ]]; then
CLR_RESET=""
CLR_BOLD=""
CLR_RED=""
CLR_GREEN=""
CLR_YELLOW=""
CLR_BLUE=""
CLR_CYAN=""
fi
log_info() {
printf "${CLR_BLUE}[INFO]${CLR_RESET} %s\n" "$*"
}
log_success() {
printf "${CLR_GREEN}[✓]${CLR_RESET} %s\n" "$*"
}
log_warn() {
printf "${CLR_YELLOW}[WARN]${CLR_RESET} %s\n" "$*" >&2
}
log_error() {
printf "${CLR_RED}[ERROR]${CLR_RESET} %s\n" "$*" >&2
}
log_step() {
printf "\n${CLR_BOLD}${CLR_CYAN}==>${CLR_RESET} ${CLR_BOLD}%s${CLR_RESET}\n" "$*"
}
TMP_DIR=""
cleanup() {
if [[ -n "${TMP_DIR:-}" && -d "$TMP_DIR" ]]; then
log_info "Cleaning up temporary installation files..."
rm -rf "$TMP_DIR"
fi
}
trap cleanup EXIT INT TERM
main() {
local repo_url="${REPO_URL:-https://gitea.creative-dragonslayer.de/Scripts/Setup.git}"
local repo_branch="${REPO_BRANCH:-dev}"
log_step "Debian Unstable & Hyprland Setup Framework Installer"
log_info "Repository: $repo_url ${repo_branch:+(Branch: $repo_branch)}"
# Ensure git is available
if ! command -v git >/dev/null 2>&1; then
log_info "Installing git..."
if [[ "$(id -u)" -eq 0 ]]; then
DEBIAN_FRONTEND=noninteractive apt-get update -y
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends git ca-certificates
else
if ! command -v sudo >/dev/null 2>&1; then
log_error "sudo is required to install prerequisites. Please run as root or install sudo."
exit 1
fi
sudo DEBIAN_FRONTEND=noninteractive apt-get update -y
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends git ca-certificates
fi
fi
# Create temporary directory
TMP_DIR="$(mktemp -d /tmp/debian-setup-XXXXXX)"
log_info "Cloning repository into temporary directory: $TMP_DIR..."
local clone_success=0
if [[ -n "$repo_branch" ]]; then
if git clone --depth 1 -b "$repo_branch" "$repo_url" "$TMP_DIR" 2>/dev/null; then
clone_success=1
else
log_warn "Failed to clone branch '$repo_branch', falling back to default branch..."
rm -rf "${TMP_DIR:?}"/* "${TMP_DIR:?}"/.* 2>/dev/null || true
fi
fi
if [[ "$clone_success" -eq 0 ]]; then
if git clone --depth 1 "$repo_url" "$TMP_DIR"; then
clone_success=1
fi
fi
if [[ "$clone_success" -eq 0 ]]; then
log_error "Failed to clone repository from $repo_url"
exit 1
fi
cd "$TMP_DIR"
chmod +x setup.sh
log_success "Repository cloned successfully. Starting setup orchestrator..."
# setup.sh itself elevates to root via sudo once it needs it - after all
# interactive TUI/prompts have already run as the current user. Escalating
# here instead would wrap the whiptail dialogs in sudo, which (when sudo is
# invoked from this non-interactive piped shell) leaves them unable to
# receive keystrokes. See setup.sh for details.
local -a setup_cmd=(./setup.sh "$@")
# Reconnect stdin/stdout to /dev/tty before executing setup.sh if piped
# (e.g. curl ... | bash), otherwise the interactive TUI receives no keystrokes
if [[ -c /dev/tty ]] && ( : < /dev/tty ) 2>/dev/null; then
if [[ ! -t 0 ]]; then
exec < /dev/tty
fi
if [[ ! -t 1 ]]; then
exec > /dev/tty
fi
fi
# Ensure a terminal type whiptail/newt is able to render
case "${TERM:-}" in
""|dumb|unknown)
export TERM="xterm-256color"
;;
esac
"${setup_cmd[@]}"
}
main "$@"
Executable
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/env bash
# ==============================================================================
# lib/apt.sh - APT, Deb822, GPG Keyring and Package installation utilities
# ==============================================================================
set -euo pipefail
APT_KEYRINGS_DIR="/etc/apt/keyrings"
APT_SOURCES_DIR="/etc/apt/sources.list.d"
APT_PREFERENCES_DIR="/etc/apt/preferences.d"
# Ensure the standard keyring directory exists
apt_ensure_keyrings_dir() {
if [[ ! -d "$APT_KEYRINGS_DIR" ]]; then
log_info "Creating keyrings directory: $APT_KEYRINGS_DIR"
mkdir -p "$APT_KEYRINGS_DIR"
chmod 0755 "$APT_KEYRINGS_DIR"
fi
}
# Enable i386 (32-bit) multiarch architecture
apt_enable_i386() {
if ! dpkg --print-foreign-architectures | grep -q "^i386$"; then
log_info "Enabling 32-bit (i386) multiarch architecture..."
dpkg --add-architecture i386
log_success "32-bit (i386) architecture enabled."
else
log_info "32-bit (i386) architecture is already enabled."
fi
}
# Download and install a GPG key into /etc/apt/keyrings/
# Usage: apt_add_keyring_from_url "https://example.com/key.gpg" "example.gpg"
apt_add_keyring_from_url() {
local url="$1"
local keyring_filename="$2"
local dest_path="$APT_KEYRINGS_DIR/$keyring_filename"
apt_ensure_keyrings_dir
log_substep "Fetching GPG keyring from: $url -> $dest_path"
local tmp_key
tmp_key="$(mktemp /tmp/apt-key.XXXXXX)"
if curl -fsSL "$url" -o "$tmp_key"; then
# Check if the key is ASCII armored or binary
if gpg --dry-run --quiet --import "$tmp_key" >/dev/null 2>&1; then
if grep -q "BEGIN PGP PUBLIC KEY BLOCK" "$tmp_key"; then
gpg --dearmor --yes --batch -o "$dest_path" < "$tmp_key" 2>/dev/null || cp "$tmp_key" "$dest_path"
else
cp "$tmp_key" "$dest_path"
fi
chmod 0644 "$dest_path"
log_success "Keyring installed: $dest_path"
else
# If gpg check fails, fallback to direct copy if non-empty
if [[ -s "$tmp_key" ]]; then
cp "$tmp_key" "$dest_path"
chmod 0644 "$dest_path"
log_success "Keyring installed (raw): $dest_path"
else
log_error "Downloaded key from $url is empty or invalid."
rm -f "$tmp_key"
return 1
fi
fi
rm -f "$tmp_key"
else
rm -f "$tmp_key"
log_error "Failed to download GPG key from $url"
return 1
fi
}
# Install Deb822 sources file
# Usage: apt_install_sources_file "/path/to/source.sources" "debian-unstable.sources"
apt_install_sources_file() {
local src_path="$1"
local dest_name="$2"
local dest_path="$APT_SOURCES_DIR/$dest_name"
if [[ ! -f "$src_path" ]]; then
log_error "Source file does not exist: $src_path"
return 1
fi
mkdir -p "$APT_SOURCES_DIR"
cp "$src_path" "$dest_path"
chmod 0644 "$dest_path"
log_success "Installed APT Deb822 source: $dest_path"
}
# Install APT preferences file
# Usage: apt_install_preference_file "/path/to/pinning.pref" "99-custom.pref"
apt_install_preference_file() {
local src_path="$1"
local dest_name="$2"
local dest_path="$APT_PREFERENCES_DIR/$dest_name"
if [[ ! -f "$src_path" ]]; then
log_error "Preference file does not exist: $src_path"
return 1
fi
mkdir -p "$APT_PREFERENCES_DIR"
cp "$src_path" "$dest_path"
chmod 0644 "$dest_path"
log_success "Installed APT preference: $dest_path"
}
# Update APT package indexes
apt_update() {
log_step "Updating APT package indexes..."
DEBIAN_FRONTEND=noninteractive apt-get update -y
}
# Dist-upgrade system
apt_dist_upgrade() {
log_step "Upgrading system packages (dist-upgrade)..."
DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y
}
# Install packages from a .list file
# Usage: apt_install_package_list_file "/path/to/packages.list"
apt_install_package_list_file() {
local list_file="$1"
if [[ ! -f "$list_file" ]]; then
log_error "Package list file not found: $list_file"
return 1
fi
local -a pkgs=()
while IFS= read -r line || [[ -n "$line" ]]; do
# Trim leading/trailing whitespace
line="$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
# Skip empty lines and comment lines
[[ -z "$line" || "$line" =~ ^# ]] && continue
pkgs+=("$line")
done < "$list_file"
if [[ ${#pkgs[@]} -eq 0 ]]; then
log_info "No packages to install from $list_file"
return 0
fi
log_info "Installing ${#pkgs[@]} packages from $(basename "$list_file")..."
DEBIAN_FRONTEND=noninteractive apt-get install -y "${pkgs[@]}"
log_success "Installed packages from $(basename "$list_file")"
}
+619
View File
@@ -0,0 +1,619 @@
#!/usr/bin/env bash
# ==============================================================================
# lib/btrfs.sh - Btrfs root volume detection, subvolume management & migration
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=lib/utils.sh
source "$SCRIPT_DIR/lib/utils.sh"
# Check if the root filesystem is Btrfs
is_root_btrfs() {
local fstype
fstype="$(findmnt -n -o FSTYPE / 2>/dev/null || true)"
[[ "$fstype" == "btrfs" ]]
}
# Resolve the root block device (stripping any subvolume bracket suffix)
get_root_btrfs_device() {
local dev
dev="$(findmnt -n -o SOURCE --canonical / 2>/dev/null || findmnt -n -o SOURCE / 2>/dev/null || true)"
dev="${dev%%\[*}"
echo "$dev"
}
# Resolve UUID of root filesystem
get_root_btrfs_uuid() {
local uuid dev
uuid="$(findmnt -n -o UUID / 2>/dev/null || true)"
if [[ -z "$uuid" ]]; then
dev="$(get_root_btrfs_device)"
if [[ -n "$dev" && -b "$dev" ]]; then
uuid="$(blkid -s UUID -o value "$dev" 2>/dev/null || true)"
fi
fi
echo "$uuid"
}
# Check if /home is mounted on a separate filesystem / partition from /
is_home_separate_filesystem() {
local root_dev home_dev
root_dev="$(get_root_btrfs_device)"
home_dev="$(findmnt -n -o SOURCE --canonical /home 2>/dev/null || findmnt -n -o SOURCE /home 2>/dev/null || true)"
home_dev="${home_dev%%\[*}"
if [[ -n "$home_dev" && -n "$root_dev" && "$home_dev" != "$root_dev" ]]; then
return 0
fi
return 1
}
# Check if root is already running from a dedicated subvolume (@ or @rootfs)
is_root_subvolume_configured() {
local fsroot opts
fsroot="$(findmnt -n -o FSROOT / 2>/dev/null || true)"
opts="$(findmnt -n -o OPTIONS / 2>/dev/null || true)"
if [[ "$fsroot" == "/@" || "$fsroot" == "/@rootfs" ]] || \
[[ "$opts" =~ subvol=@ || "$opts" =~ subvol=/@ ]]; then
return 0
fi
return 1
}
# Update /etc/fstab to mount / with subvol=@ and /home with subvol=@home
update_btrfs_fstab() {
local fstab_file="$1"
local root_id="$2"
[[ -f "$fstab_file" ]] || return 0
backup_file_or_dir "$fstab_file"
local tmp_fstab
tmp_fstab="$(mktemp)"
local found_root=0
local found_home=0
local root_spec="${root_id:-}"
local root_opts="defaults,subvol=@"
while IFS= read -r line || [[ -n "$line" ]]; do
# Retain comments and blank lines
if [[ "$line" =~ ^[[:space:]]*# || -z "${line// /}" ]]; then
echo "$line" >> "$tmp_fstab"
continue
fi
# Parse fields
local spec mnt type opts freq pass
read -r spec mnt type opts freq pass <<< "$line"
if [[ "$mnt" == "/" && "$type" == "btrfs" ]]; then
found_root=1
root_spec="${root_id:-$spec}"
local new_opts="$opts"
if [[ "$new_opts" =~ subvol= ]] || [[ "$new_opts" =~ subvolid= ]]; then
new_opts="$(echo "$new_opts" | sed -E 's/(subvol|subvolid)=[^,]*/subvol=@/g')"
else
new_opts="${new_opts},subvol=@"
fi
new_opts="$(echo "$new_opts" | sed -E -e 's/,,+/,/g' -e 's/^,//' -e 's/,$//')"
root_opts="$new_opts"
spec="$root_spec"
printf "%s\t%s\t%s\t%s\t%s\t%s\n" "$spec" "$mnt" "$type" "$new_opts" "${freq:-0}" "${pass:-0}" >> "$tmp_fstab"
elif [[ "$mnt" == "/home" && "$type" == "btrfs" ]]; then
found_home=1
local new_opts="$opts"
if [[ "$new_opts" =~ subvol= ]] || [[ "$new_opts" =~ subvolid= ]]; then
new_opts="$(echo "$new_opts" | sed -E 's/(subvol|subvolid)=[^,]*/subvol=@home/g')"
else
new_opts="${new_opts},subvol=@home"
fi
new_opts="$(echo "$new_opts" | sed -E -e 's/,,+/,/g' -e 's/^,//' -e 's/,$//')"
spec="${root_id:-$spec}"
printf "%s\t%s\t%s\t%s\t%s\t%s\n" "$spec" "$mnt" "$type" "$new_opts" "${freq:-0}" "${pass:-0}" >> "$tmp_fstab"
else
echo "$line" >> "$tmp_fstab"
fi
done < "$fstab_file"
# If home was not present in fstab and root was found/specified, add /home entry
if [[ "$found_home" -eq 0 && ( "$found_root" -eq 1 || -n "$root_spec" ) ]]; then
local home_opts="${root_opts/subvol=@/subvol=@home}"
if [[ "$home_opts" == "$root_opts" ]]; then
home_opts="defaults,subvol=@home"
fi
printf "%s\t%s\t%s\t%s\t%s\t%s\n" "$root_spec" "/home" "btrfs" "$home_opts" "0" "0" >> "$tmp_fstab"
fi
if ! cat "$tmp_fstab" > "$fstab_file" 2>/dev/null; then
log_warn "Could not write to $fstab_file (permission denied)."
fi
rm -f "$tmp_fstab"
}
# Main function to check and configure Btrfs subvolumes for root and home
check_and_setup_btrfs_subvolumes() {
if ! is_root_btrfs; then
local fstype
fstype="$(findmnt -n -o FSTYPE / 2>/dev/null || echo "unknown")"
log_info "Root filesystem is not Btrfs ($fstype). Skipping Btrfs subvolume migration."
return 0
fi
log_info "Btrfs root filesystem detected."
if is_root_subvolume_configured; then
local fsroot
fsroot="$(findmnt -n -o FSROOT / 2>/dev/null || true)"
log_success "Root filesystem is already running inside subvolume '$fsroot'."
return 0
fi
# Ensure btrfs utility is available
if ! command_exists btrfs; then
log_info "Installing btrfs-progs..."
DEBIAN_FRONTEND=noninteractive apt-get update -y >/dev/null 2>&1 || true
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends btrfs-progs || {
log_error "btrfs-progs could not be installed."
return 1
}
fi
local root_dev root_uuid
root_dev="$(get_root_btrfs_device)"
root_uuid="$(get_root_btrfs_uuid)"
if [[ -z "$root_dev" ]]; then
log_warn "Could not determine root block device for Btrfs. Skipping migration."
return 0
fi
local root_fstab_id
if [[ -n "$root_uuid" ]]; then
root_fstab_id="UUID=$root_uuid"
else
root_fstab_id="$root_dev"
fi
log_step "Btrfs Migration: Creating subvolumes '@' and '@home'..."
local tmp_mnt
tmp_mnt="$(mktemp -d /tmp/btrfs-toplevel.XXXXXX)"
# Trap to safely unmount and remove temporary mountpoint
cleanup_tmp_mnt() {
if [[ -d "$tmp_mnt" ]]; then
if mountpoint -q "$tmp_mnt"; then
umount "$tmp_mnt" 2>/dev/null || true
fi
rm -rf "$tmp_mnt"
fi
}
# Mount top-level btrfs root (subvolid=5)
if ! mount -t btrfs -o subvolid=5 "$root_dev" "$tmp_mnt"; then
log_error "Failed to mount top-level Btrfs volume on $tmp_mnt."
rm -rf "$tmp_mnt"
return 1
fi
# 1. Create or snapshot '@' subvolume for root
if [[ ! -d "$tmp_mnt/@" ]]; then
log_info "Creating snapshot of top-level filesystem into '@' subvolume..."
btrfs subvolume snapshot "$tmp_mnt" "$tmp_mnt/@"
log_success "Created '@' subvolume snapshot."
else
log_info "'@' subvolume already exists in top-level Btrfs tree."
fi
# 2. Create '@home' subvolume if /home is on the same volume
if ! is_home_separate_filesystem; then
if [[ ! -d "$tmp_mnt/@home" ]]; then
log_info "Creating '@home' subvolume..."
btrfs subvolume create "$tmp_mnt/@home"
log_success "Created '@home' subvolume."
# Move existing home data into @home
if [[ -d "$tmp_mnt/@/home" && "$(ls -A "$tmp_mnt/@/home" 2>/dev/null)" ]]; then
log_info "Moving existing /home data to '@home' subvolume..."
cp -a --reflink=auto "$tmp_mnt/@/home/." "$tmp_mnt/@home/"
# Clean up the directory inside @/home so it acts as an empty mountpoint
rm -rf "$tmp_mnt/@/home"/* "$tmp_mnt/@/home"/.[!.]* "$tmp_mnt/@/home"/..?* 2>/dev/null || true
chmod 755 "$tmp_mnt/@/home" 2>/dev/null || true
chown root:root "$tmp_mnt/@/home" 2>/dev/null || true
log_success "Moved /home data to '@home' subvolume."
fi
else
log_info "'@home' subvolume already exists in top-level Btrfs tree."
fi
else
log_info "/home is mounted on a separate filesystem. Skipping '@home' subvolume creation."
fi
# 3. Set default subvolume to '@'
local subvol_at_id
subvol_at_id="$(btrfs subvolume list "$tmp_mnt" 2>/dev/null | awk '$NF == "@" {print $2}' | tail -n1)"
if [[ -n "$subvol_at_id" ]]; then
btrfs subvolume set-default "$subvol_at_id" "$tmp_mnt"
log_success "Set default Btrfs subvolume to '@' (ID: $subvol_at_id)."
fi
# 4. Update /etc/fstab (and the snapshotted @/etc/fstab)
log_info "Updating /etc/fstab entries for '@' and '@home'..."
update_btrfs_fstab "/etc/fstab" "$root_fstab_id"
if [[ -f "$tmp_mnt/@/etc/fstab" ]]; then
update_btrfs_fstab "$tmp_mnt/@/etc/fstab" "$root_fstab_id"
fi
log_success "Updated /etc/fstab with subvolume mount options."
# 5. Mount '@home' at /home for the current live session if not already mounted
if ! is_home_separate_filesystem; then
if ! findmnt /home >/dev/null 2>&1; then
log_info "Mounting '@home' subvolume at /home for current setup session..."
mount -t btrfs -o subvol=@home "$root_dev" /home || log_warn "Could not mount @home at /home live."
fi
fi
# Clean up temporary top-level mount
cleanup_tmp_mnt
log_success "Btrfs subvolume setup and migration completed successfully."
}
# Ensure Timeshift APT hook is configured for automatic snapshots on system updates
ensure_timeshift_apt_hook() {
local root_prefix="${ROOT_PREFIX:-}"
local snapshot_on_update="${TIMESHIFT_SNAPSHOT_ON_UPDATE:-true}"
local apt_conf_file="${root_prefix}/etc/apt/apt.conf.d/80timeshift-auto-snapshot"
local hook_script="${root_prefix}/usr/local/bin/timeshift-apt-hook"
# If disabled in configuration, remove hook if present
if [[ "$snapshot_on_update" != "1" && "$snapshot_on_update" != "true" ]]; then
if [[ -f "$apt_conf_file" || -f "$hook_script" ]]; then
log_info "Disabling Timeshift APT update snapshot hook..."
rm -f "$apt_conf_file" "$hook_script"
fi
return 0
fi
mkdir -p "${root_prefix}/usr/local/bin" "${root_prefix}/etc/apt/apt.conf.d"
# Create hook script
log_info "Configuring Timeshift APT update hook ($hook_script)..."
cat > "$hook_script" <<'EOF'
#!/usr/bin/env bash
# ==============================================================================
# /usr/local/bin/timeshift-apt-hook - Automatic Timeshift Snapshot on APT updates
# ==============================================================================
set -euo pipefail
# Check if timeshift binary is available
if ! command -v timeshift >/dev/null 2>&1; then
exit 0
fi
# Check if timeshift configuration exists
if [[ ! -f /etc/timeshift/timeshift.json && ! -f /etc/timeshift.json ]]; then
exit 0
fi
# Check if root filesystem is Btrfs
if command -v findmnt >/dev/null 2>&1; then
if [[ "$(findmnt -n -o FSTYPE / 2>/dev/null || true)" != "btrfs" ]]; then
exit 0
fi
fi
# Prevent duplicate snapshots within 60 seconds (rate limiting)
STAMP_FILE="/run/timeshift-apt-hook.stamp"
if [[ -f "$STAMP_FILE" ]]; then
LAST_RUN="$(stat -c %Y "$STAMP_FILE" 2>/dev/null || stat -f %m "$STAMP_FILE" 2>/dev/null || echo 0)"
CURRENT_TIME="$(date +%s)"
if (( CURRENT_TIME - LAST_RUN < 60 )); then
exit 0
fi
fi
echo ">> [Timeshift] Creating automatic pre-update system snapshot..."
if timeshift --create --scripted --tags O --comments "Automatic snapshot before system update (APT)" 2>&1; then
touch "$STAMP_FILE" 2>/dev/null || true
echo ">> [Timeshift] Pre-update snapshot created successfully."
else
echo ">> [Timeshift] Warning: Automatic snapshot could not be created (continuing update)."
fi
exit 0
EOF
chmod 755 "$hook_script"
# Create APT configuration hook
cat > "$apt_conf_file" <<'EOF'
// Automatic Timeshift snapshot before APT package operations / updates
DPkg::Pre-Invoke { "[ -x /usr/local/bin/timeshift-apt-hook ] && /usr/local/bin/timeshift-apt-hook || true"; };
EOF
chmod 644 "$apt_conf_file"
log_success "Timeshift APT update hook configured: $apt_conf_file"
}
# Ensure Timeshift systemd boot service and cron jobs are configured and enabled
ensure_timeshift_boot_service() {
local root_prefix="${ROOT_PREFIX:-}"
local service_file="${root_prefix}/etc/systemd/system/timeshift-boot.service"
local timeshift_bin
timeshift_bin="$(command -v timeshift || echo "/usr/bin/timeshift")"
mkdir -p "${root_prefix}/etc/systemd/system"
local needs_service_update=0
if [[ ! -f "$service_file" ]]; then
needs_service_update=1
fi
if [[ "$needs_service_update" -eq 1 ]]; then
log_info "Creating Timeshift boot snapshot service ($service_file)..."
cat > "$service_file" <<EOF
[Unit]
Description=Timeshift Boot Snapshot Service
Documentation=man:timeshift(1)
After=local-fs.target
ConditionPathExists=/etc/timeshift/timeshift.json
[Service]
Type=oneshot
ExecStart=${timeshift_bin} --check --scripted
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
chmod 644 "$service_file"
fi
if [[ -z "$root_prefix" ]] && command_exists systemctl; then
systemctl daemon-reload 2>/dev/null || true
systemctl enable timeshift-boot.service 2>/dev/null || true
fi
# Also install cron entries if cron directory exists
if [[ -d "${root_prefix}/etc/cron.d" ]]; then
local cron_boot="${root_prefix}/etc/cron.d/timeshift-boot"
local cron_hourly="${root_prefix}/etc/cron.d/timeshift-hourly"
if [[ ! -f "$cron_boot" ]]; then
cat > "$cron_boot" <<EOF
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""
@reboot root sleep 10m && ${timeshift_bin} --create --scripted --tags B
EOF
chmod 644 "$cron_boot"
fi
if [[ ! -f "$cron_hourly" ]]; then
cat > "$cron_hourly" <<EOF
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""
0 * * * * root ${timeshift_bin} --check --scripted
EOF
chmod 644 "$cron_hourly"
fi
fi
}
# Ensure Timeshift is configured for Btrfs mode on the root filesystem
ensure_timeshift_btrfs_config() {
local root_prefix="${ROOT_PREFIX:-}"
local root_uuid
root_uuid="$(get_root_btrfs_uuid)"
mkdir -p "${root_prefix}/etc/timeshift"
local config_file="${root_prefix}/etc/timeshift/timeshift.json"
local count_boot="${TIMESHIFT_COUNT_BOOT:-5}"
local schedule_boot="${TIMESHIFT_SCHEDULE_BOOT:-true}"
local needs_update=0
if [[ ! -f "$config_file" ]]; then
needs_update=1
elif grep -q '"btrfs_mode"[[:space:]]*:[[:space:]]*"false"' "$config_file" 2>/dev/null; then
needs_update=1
elif grep -q '"backup_device_uuid"[[:space:]]*:[[:space:]]*""' "$config_file" 2>/dev/null && [[ -n "$root_uuid" ]]; then
needs_update=1
elif ! grep -q "\"schedule_boot\"[[:space:]]*:[[:space:]]*\"${schedule_boot}\"" "$config_file" 2>/dev/null; then
needs_update=1
elif ! grep -q "\"count_boot\"[[:space:]]*:[[:space:]]*\"${count_boot}\"" "$config_file" 2>/dev/null; then
needs_update=1
fi
if [[ "$needs_update" -eq 1 ]]; then
log_info "Initializing Timeshift Btrfs configuration ($config_file)..."
backup_file_or_dir "$config_file"
cat > "$config_file" <<EOF
{
"backup_device_uuid" : "${root_uuid}",
"parent_device_uuid" : "",
"do_first_run" : "false",
"btrfs_mode" : "true",
"include_btrfs_home_for_backup" : "false",
"include_btrfs_home_for_restore" : "false",
"stop_cron_emails" : "true",
"schedule_monthly" : "false",
"schedule_weekly" : "false",
"schedule_daily" : "false",
"schedule_hourly" : "false",
"schedule_boot" : "${schedule_boot}",
"count_monthly" : "2",
"count_weekly" : "3",
"count_daily" : "5",
"count_hourly" : "6",
"count_boot" : "${count_boot}",
"snapshot_size" : "0",
"snapshot_count" : "0",
"exclude" : [
],
"exclude-apps" : [
]
}
EOF
chmod 644 "$config_file"
if [[ ! -e "${root_prefix}/etc/timeshift.json" ]]; then
ln -sf /etc/timeshift/timeshift.json "${root_prefix}/etc/timeshift.json" 2>/dev/null || true
fi
fi
ensure_timeshift_boot_service
ensure_timeshift_apt_hook
ensure_grub_btrfs
}
# Ensure grub-btrfs is installed and configured to generate GRUB snapshot boot entries
ensure_grub_btrfs() {
local root_prefix="${ROOT_PREFIX:-}"
local enable_grub_btrfs="${ENABLE_GRUB_BTRFS:-1}"
# Check if disabled in configuration
if [[ "$enable_grub_btrfs" != "1" && "$enable_grub_btrfs" != "true" ]]; then
log_info "GRUB Btrfs snapshot booting disabled in configuration."
return 0
fi
# Dry-run check
if [[ "${FLAG_DRY_RUN:-0}" -eq 1 ]]; then
log_info "[DRY-RUN] Would install and configure grub-btrfs for GRUB snapshot booting."
return 0
fi
# Check if root is on Btrfs
if ! is_root_btrfs; then
log_info "Root filesystem is not Btrfs. Skipping grub-btrfs setup."
return 0
fi
log_info "Configuring GRUB Btrfs snapshot support (grub-btrfs)..."
# Ensure required dependencies are installed
if ! command_exists inotifywait || ! command_exists git || ! command_exists make; then
log_info "Installing dependencies for grub-btrfs (inotify-tools, git, make)..."
DEBIAN_FRONTEND=noninteractive apt-get update -y >/dev/null 2>&1 || true
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends inotify-tools git make 2>/dev/null || true
fi
local repo_dir="${root_prefix}/usr/share/debian-gaming/grub/grub-btrfs"
mkdir -p "$(dirname "$repo_dir")"
if [[ ! -d "$repo_dir/.git" ]]; then
log_info "Cloning grub-btrfs repository..."
if ! git clone --depth 1 https://github.com/Antynea/grub-btrfs.git "$repo_dir" 2>/dev/null; then
log_warn "Failed to clone grub-btrfs repository. Snapshot boot menu may not be available."
return 0
fi
else
log_info "grub-btrfs repository already cloned; pulling latest updates..."
(cd "$repo_dir" && git pull 2>/dev/null) || log_warn "grub-btrfs git pull skipped."
fi
# Install grub.d script
mkdir -p "${root_prefix}/etc/grub.d"
if [[ -f "$repo_dir/41_snapshots-btrfs" ]]; then
cp -f "$repo_dir/41_snapshots-btrfs" "${root_prefix}/etc/grub.d/41_snapshots-btrfs"
chmod 755 "${root_prefix}/etc/grub.d/41_snapshots-btrfs"
fi
# Install default config
mkdir -p "${root_prefix}/etc/default/grub-btrfs"
if [[ -f "$repo_dir/config" && ! -f "${root_prefix}/etc/default/grub-btrfs/config" ]]; then
cp -f "$repo_dir/config" "${root_prefix}/etc/default/grub-btrfs/config"
chmod 644 "${root_prefix}/etc/default/grub-btrfs/config"
fi
# Install grub-btrfsd binary
mkdir -p "${root_prefix}/usr/bin"
if [[ -f "$repo_dir/grub-btrfsd" ]]; then
cp -f "$repo_dir/grub-btrfsd" "${root_prefix}/usr/bin/grub-btrfsd"
chmod 755 "${root_prefix}/usr/bin/grub-btrfsd"
fi
# Install and configure systemd service for automatic snapshot tracking with Timeshift
mkdir -p "${root_prefix}/etc/systemd/system"
local service_file="${root_prefix}/etc/systemd/system/grub-btrfsd.service"
cat > "$service_file" <<'EOF'
[Unit]
Description=Regenerate grub-btrfs.cfg on snapshot changes
After=local-fs.target
ConditionPathExists=/etc/default/grub-btrfs/config
[Service]
Type=simple
LogLevelMax=notice
Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin"
EnvironmentFile=-/etc/default/grub-btrfs/config
ExecStart=/usr/bin/grub-btrfsd --syslog --timeshift-auto
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
chmod 644 "$service_file"
if [[ -z "$root_prefix" ]] && command_exists systemctl; then
systemctl daemon-reload 2>/dev/null || true
systemctl enable grub-btrfsd.service 2>/dev/null || true
systemctl restart grub-btrfsd.service 2>/dev/null || true
fi
log_success "grub-btrfs installed and configured successfully."
}
# Create a Btrfs snapshot using Timeshift
create_timeshift_snapshot() {
local comment="${1:-Setup Snapshot}"
local tags="${2:-O}"
# Check if disabled via configuration
if [[ "${ENABLE_TIMESHIFT_SNAPSHOTS:-1}" != "1" && "${ENABLE_TIMESHIFT_SNAPSHOTS:-1}" != "true" ]]; then
log_info "Timeshift snapshots disabled in configuration. Skipping: '$comment'"
return 0
fi
# Dry-run check
if [[ "${FLAG_DRY_RUN:-0}" -eq 1 ]]; then
log_info "[DRY-RUN] Would create Timeshift Btrfs snapshot: '$comment' (Tag: $tags)"
return 0
fi
# Check if root is on Btrfs
if ! is_root_btrfs; then
log_info "Root filesystem is not Btrfs. Skipping Timeshift snapshot: '$comment'"
return 0
fi
# Ensure timeshift is installed
if ! command_exists timeshift; then
log_info "Timeshift not found. Attempting to install timeshift..."
DEBIAN_FRONTEND=noninteractive apt-get update -y >/dev/null 2>&1 || true
if ! DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends timeshift 2>/dev/null; then
log_warn "Timeshift is not available and could not be installed. Skipping snapshot: '$comment'"
return 0
fi
fi
# Ensure Timeshift configuration for Btrfs
ensure_timeshift_btrfs_config
log_substep "Creating Timeshift Btrfs snapshot: '$comment' (Tag: $tags)..."
local root_dev
root_dev="$(get_root_btrfs_device)"
if timeshift --create --scripted --comments "$comment" --tags "$tags" 2>/dev/null || \
([[ -n "$root_dev" ]] && timeshift --create --scripted --snapshot-device "$root_dev" --btrfs --comments "$comment" --tags "$tags" 2>/dev/null); then
log_success "Timeshift Btrfs snapshot created: '$comment'"
else
log_warn "Timeshift snapshot could not be created for '$comment' (non-fatal)."
fi
}
+273
View File
@@ -0,0 +1,273 @@
#!/usr/bin/env bash
# ==============================================================================
# lib/network.sh - Network interface configuration (Debian Installer style & Loopback)
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=lib/utils.sh
source "$SCRIPT_DIR/lib/utils.sh"
# Get a list of all physical LAN / Ethernet network interfaces on the system
get_lan_interfaces() {
local -a lan_ifaces=()
if [[ -d /sys/class/net ]]; then
for iface_path in /sys/class/net/*; do
[[ -e "$iface_path" ]] || continue
local iface
iface="$(basename "$iface_path")"
# Skip loopback interface
[[ "$iface" == "lo" ]] && continue
# Skip known virtual, bridge, container, tunnel and VPN interfaces
if [[ "$iface" =~ ^(docker[0-9]*|veth.*|virbr[0-9]*|br.*|bridge.*|tun[0-9]*|tap[0-9]*|wg[0-9]*|dummy[0-9]*|waydroid.*|tailscale.*|zt.*|bond.*|sit[0-9]*|ip6tnl.*|gre.*|erspan.*|vboxnet.*|vmnet.*)$ ]]; then
continue
fi
# Skip wireless / Wi-Fi interfaces
if [[ -e "$iface_path/wireless" || -e "$iface_path/phy80211" || "$iface" =~ ^(wl.*|wlan.*|wifi.*|ath.*)$ ]]; then
continue
fi
# Check if it is a physical device (has device link) or standard Ethernet type (type == 1)
local is_lan=0
local dev_type=""
if [[ -f "$iface_path/type" ]]; then
dev_type="$(cat "$iface_path/type" 2>/dev/null || echo "")"
fi
if [[ -e "$iface_path/device" && "$dev_type" == "1" ]]; then
is_lan=1
elif [[ "$iface" =~ ^(eth[0-9]+|en[a-zA-Z0-9]+)$ ]] && [[ "$dev_type" == "1" || -z "$dev_type" ]]; then
is_lan=1
elif [[ -e "$iface_path/device" ]]; then
is_lan=1
fi
if [[ "$is_lan" -eq 1 ]]; then
lan_ifaces+=("$iface")
fi
done
elif command_exists ip; then
# Fallback to ip link parsing if /sys/class/net is not directly readable
while IFS= read -r line; do
local iface
iface="$(echo "$line" | awk -F': ' '{print $2}' | cut -d'@' -f1)"
[[ -z "$iface" || "$iface" == "lo" ]] && continue
if [[ "$iface" =~ ^(eth[0-9]+|en[a-zA-Z0-9]+)$ ]]; then
lan_ifaces+=("$iface")
fi
done < <(ip -o link show 2>/dev/null || true)
fi
echo "${lan_ifaces[@]:-}"
}
# Check if a specific interface is already configured in /etc/network/interfaces or interfaces.d
is_interface_configured() {
local iface="$1"
local interfaces_file="/etc/network/interfaces"
local interfaces_dir="/etc/network/interfaces.d"
if [[ -f "$interfaces_file" ]]; then
if grep -E -q "^[[:space:]]*(iface|auto|allow-hotplug)[[:space:]]+${iface}([[:space:]]|$)" "$interfaces_file" 2>/dev/null; then
return 0
fi
fi
if [[ -d "$interfaces_dir" ]]; then
if grep -E -q -r "^[[:space:]]*(iface|auto|allow-hotplug)[[:space:]]+${iface}([[:space:]]|$)" "$interfaces_dir" 2>/dev/null; then
return 0
fi
fi
return 1
}
# Configure loopback interface in /etc/network/interfaces and /etc/hosts
configure_loopback_interface() {
local interfaces_file="/etc/network/interfaces"
local interfaces_dir="/etc/network/interfaces.d"
mkdir -p "/etc/network" "$interfaces_dir"
log_substep "Configuring loopback network interface (lo)..."
if [[ ! -f "$interfaces_file" ]]; then
cat <<EOF > "$interfaces_file"
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
EOF
chmod 0644 "$interfaces_file"
log_success "Created $interfaces_file with loopback configuration."
else
backup_file_or_dir "$interfaces_file"
# Ensure source /etc/network/interfaces.d/* is present
if ! grep -E -q "^[[:space:]]*source[[:space:]]+/etc/network/interfaces\.d/\*" "$interfaces_file"; then
sed -i '1i # The loopback network interface\nsource /etc/network/interfaces.d/*\n' "$interfaces_file"
fi
# Ensure auto lo and iface lo inet loopback are configured
if ! grep -E -q "^[[:space:]]*iface[[:space:]]+lo[[:space:]]+inet[[:space:]]+loopback" "$interfaces_file"; then
cat <<EOF >> "$interfaces_file"
# The loopback network interface
auto lo
iface lo inet loopback
EOF
log_success "Added loopback configuration to $interfaces_file."
fi
fi
# Ensure /etc/hosts has standard loopback mappings
if [[ -f /etc/hosts ]]; then
local host_name
host_name="$(hostname 2>/dev/null || cat /etc/hostname 2>/dev/null || echo "debian")"
if ! grep -q "127.0.0.1[[:space:]]\+localhost" /etc/hosts; then
echo "127.0.0.1 localhost" >> /etc/hosts
fi
if ! grep -q "::1[[:space:]]\+localhost" /etc/hosts; then
echo "::1 localhost ip6-localhost ip6-loopback" >> /etc/hosts
fi
if [[ -n "$host_name" ]] && ! grep -E -q "(127\.0\.1\.1|127\.0\.0\.1)[[:space:]]+.*$host_name" /etc/hosts; then
echo "127.0.1.1 $host_name" >> /etc/hosts
fi
fi
# Bring up loopback interface immediately
if command_exists ip; then
ip link set lo up 2>/dev/null || true
fi
if command_exists ifup; then
ifup lo 2>/dev/null || true
fi
log_success "Loopback interface (lo) configured and activated."
}
# Configure all detected physical LAN interfaces (Debian installer standard)
configure_lan_interfaces() {
local interfaces_file="/etc/network/interfaces"
local interfaces_dir="/etc/network/interfaces.d"
mkdir -p "/etc/network" "$interfaces_dir"
local -a lan_ifaces
read -r -a lan_ifaces <<< "$(get_lan_interfaces)"
if [[ ${#lan_ifaces[@]} -eq 0 ]]; then
log_info "No physical LAN interfaces detected at this time."
return 0
fi
log_substep "Found physical LAN interface(s): ${lan_ifaces[*]}"
# Backup interfaces file before modifications
if [[ -f "$interfaces_file" ]]; then
backup_file_or_dir "$interfaces_file"
fi
for iface in "${lan_ifaces[@]}"; do
[[ -z "$iface" ]] && continue
if is_interface_configured "$iface"; then
log_info "LAN interface '$iface' is already configured."
else
log_info "Configuring LAN interface '$iface' (Debian Installer style: DHCP & IPv6 Auto)..."
cat <<EOF >> "$interfaces_file"
# LAN network interface: $iface
allow-hotplug $iface
iface $iface inet dhcp
iface $iface inet6 auto
EOF
log_success "Added LAN interface '$iface' to $interfaces_file."
fi
# Ensure the interface is brought UP and usable
if command_exists ip; then
ip link set "$iface" up 2>/dev/null || true
fi
if command_exists ifup; then
ifup "$iface" 2>/dev/null || true
fi
done
log_success "All LAN network interfaces configured and activated."
}
# Configure NetworkManager to manage interfaces and work seamlessly with ifupdown
configure_network_manager() {
local nm_conf="/etc/NetworkManager/NetworkManager.conf"
local nm_dir="/etc/NetworkManager"
if [[ -d "$nm_dir" ]] || command_exists NetworkManager || command_exists nmcli; then
log_substep "Configuring NetworkManager integration (managed=true)..."
mkdir -p "$nm_dir"
if [[ ! -f "$nm_conf" ]]; then
cat <<EOF > "$nm_conf"
[main]
plugins=ifupdown,keyfile
[ifupdown]
managed=true
EOF
chmod 0644 "$nm_conf"
log_success "Created $nm_conf with managed=true."
else
backup_file_or_dir "$nm_conf"
# Set managed=true in [ifupdown] section
if grep -q "\[ifupdown\]" "$nm_conf"; then
sed -i '/\[ifupdown\]/,/^\[/{s/managed=false/managed=true/}' "$nm_conf"
if ! grep -A2 "\[ifupdown\]" "$nm_conf" | grep -q "managed="; then
sed -i '/\[ifupdown\]/a managed=true' "$nm_conf"
fi
else
cat <<EOF >> "$nm_conf"
[ifupdown]
managed=true
EOF
fi
log_success "Updated $nm_conf to managed=true."
fi
fi
}
# Enable networking and NetworkManager services
enable_network_services() {
if command_exists systemctl; then
log_substep "Enabling and activating network services..."
# Enable networking service (ifupdown)
systemctl enable networking.service 2>/dev/null || true
# Enable & start NetworkManager if available
if systemctl list-unit-files NetworkManager.service >/dev/null 2>&1 || [[ -f /lib/systemd/system/NetworkManager.service ]]; then
systemctl enable NetworkManager.service 2>/dev/null || true
systemctl start NetworkManager.service 2>/dev/null || true
log_success "NetworkManager service enabled and started."
fi
fi
}
# Central orchestration function for network configuration
configure_network_all() {
log_substep "Configuring complete network subsystem (Loopback, all LAN interfaces, NetworkManager)..."
configure_loopback_interface
configure_lan_interfaces
configure_network_manager
enable_network_services
log_success "Network configuration completed successfully."
}
Executable
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env bash
# ==============================================================================
# lib/tui.sh - Interactive Whiptail TUI dialogs and checklists
# ==============================================================================
set -euo pipefail
# All whiptail dialogs are executed via 'run_whiptail' (lib/utils.sh), which
# binds stdin and stdout to the controlling terminal (/dev/tty). Without this,
# keyboard input (ENTER, SPACE, arrow keys) is consumed by the shell instead of
# the dialog whenever the setup is started through a pipe (curl ... | bash).
# Check if whiptail is available
tui_check_whiptail() {
if ! command_exists whiptail; then
log_warn "whiptail is not installed. Attempting to install whiptail..."
DEBIAN_FRONTEND=noninteractive apt-get update -y && DEBIAN_FRONTEND=noninteractive apt-get install -y whiptail
fi
ensure_term
}
# Determine whether an interactive TUI can be displayed at all
tui_is_available() {
command_exists whiptail || return 1
has_tty || return 1
return 0
}
# Compute dialog geometry into TUI_HEIGHT / TUI_WIDTH / TUI_LIST_HEIGHT
# Usage: tui_calc_geometry <desired_height> <desired_width> [desired_list_height]
tui_calc_geometry() {
local want_height="$1"
local want_width="$2"
local want_list="${3:-0}"
local term_size term_lines term_cols
term_size="$(get_term_size)"
term_lines="${term_size%% *}"
term_cols="${term_size##* }"
local height="$want_height"
local width="$want_width"
if (( term_lines - 2 < height )); then
height=$(( term_lines - 2 ))
fi
if (( height < 8 )); then
height=8
fi
if (( term_cols - 4 < width )); then
width=$(( term_cols - 4 ))
fi
if (( width < 40 )); then
width=40
fi
local list_height="$want_list"
if (( want_list > 0 )); then
if (( height - 8 < list_height )); then
list_height=$(( height - 8 ))
fi
if (( list_height < 3 )); then
list_height=3
fi
fi
TUI_HEIGHT="$height"
TUI_WIDTH="$width"
TUI_LIST_HEIGHT="$list_height"
}
# Display welcome message
tui_welcome() {
tui_calc_geometry 14 70
run_whiptail --title "Debian Unstable Setup & Hyprland Installer" \
--msgbox "Willkommen beim Debian Unstable & Desktop Setup!\n\nDieses Skript führt dich durch die modulare Einrichtung deines Debian Sid Systems mit XanMod-Kernel, Hyprland und Optimierungen.\n\nDrücke ENTER um zur Modulauswahl zu gelangen." \
"$TUI_HEIGHT" "$TUI_WIDTH" || true
}
# Present stage checklist to user
# Sets TUI_SELECTION and returns 0 on success, 1 on cancel
tui_select_stages() {
local tmp_file
tmp_file="$(mktemp)"
tui_calc_geometry 20 74 10
if run_whiptail --output-fd 3 --title "Modulauswahl / Stages" \
--checklist "Wähle die gewünschten Installations-Phasen mit der LEERTASTE aus (ENTER = OK):" \
"$TUI_HEIGHT" "$TUI_WIDTH" "$TUI_LIST_HEIGHT" \
"01" "Debian Unstable (Deb822, Pinning, Upgrade)" ON \
"02" "Kernel & Hardware (XanMod, P-State, Microcode)" ON \
"03" "Bootloader & Theme (GRUB, Vimix, Plymouth)" ON \
"04" "Pakete (Base, Desktop, Gaming, Virtualisierung)" ON \
"05" "Coding & Nerd Fonts (JetBrainsMono, VictorMono)" ON \
"06" "System-Dienste (AppArmor, Docker, Libvirt, zram, Ollama)" ON \
"07" "Userland & Skel (Zsh, Skel-Templates, Dotfiles)" ON \
"08" "Flatpaks (Flathub Repository & Flatpaks)" ON \
"09" "Zusatz-Apps & MIME (Spotify, Waydroid, OpenDeck, MIME)" ON \
"10" "Hyprland Desktop (LinuxBeginnings Debian-Hyprland Installer)" ON \
"11" "Linutil (Chris Titus Tech System Toolbox)" ON \
3> "$tmp_file"; then
TUI_SELECTION="$(tr -d '"' < "$tmp_file")"
export TUI_SELECTION
rm -f "$tmp_file"
return 0
else
rm -f "$tmp_file"
TUI_SELECTION=""
export TUI_SELECTION
return 1
fi
}
# Prompt user for target user via Whiptail dialog
tui_prompt_target_user() {
local default_user="${1:-}"
local chosen=""
# Detect candidate user if not provided or root
if [[ -z "$default_user" || "$default_user" == "root" ]]; then
if [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then
default_user="$SUDO_USER"
elif [[ -n "${PKEXEC_UID:-}" ]]; then
default_user="$(id -nu "$PKEXEC_UID" 2>/dev/null || true)"
elif [[ "$(id -u)" -ne 0 ]]; then
default_user="$(id -un)"
else
default_user="$(awk -F: '$3 >= 1000 && $3 < 60000 && $1 != "nobody" {print $1; exit}' /etc/passwd 2>/dev/null || true)"
fi
fi
if [[ -n "$default_user" && "$default_user" != "root" ]]; then
tui_calc_geometry 10 65
if run_whiptail --title "Ziel-Benutzer bestätigen" \
--yes-button "Verwenden" \
--no-button "Anderer Benutzer" \
--yesno "Erkannter Ziel-Benutzer: $default_user\n\nMöchtest du diesen Benutzer für die Konfiguration (Dotfiles, Gruppen, Hyprland) verwenden?" \
"$TUI_HEIGHT" "$TUI_WIDTH"; then
chosen="$default_user"
fi
fi
local tmp_file
tmp_file="$(mktemp)"
while [[ -z "$chosen" ]]; do
tui_calc_geometry 10 60
if run_whiptail --output-fd 3 --title "Ziel-Benutzer eingeben" \
--inputbox "Bitte gib den Benutzernamen des Desktop-Benutzers ein:" \
"$TUI_HEIGHT" "$TUI_WIDTH" "$default_user" \
3> "$tmp_file"; then
local input_user
input_user="$(tr -d '[:space:]' < "$tmp_file")"
if [[ -z "$input_user" || "$input_user" == "root" ]]; then
run_whiptail --title "Ungültiger Benutzer" --msgbox "Ungültiger Benutzername (darf nicht leer oder root sein)." 8 55 || true
continue
fi
if ! id "$input_user" >/dev/null 2>&1; then
run_whiptail --title "Benutzer nicht gefunden" --msgbox "Benutzer '$input_user' existiert nicht im System." 8 55 || true
continue
fi
chosen="$input_user"
else
rm -f "$tmp_file"
log_info "Setup durch Benutzer abgebrochen."
exit 0
fi
done
rm -f "$tmp_file"
export TARGET_USER="$chosen"
}
# Confirmation dialog before running
tui_confirm_execution() {
local selected_stages="$1"
local target_user="$2"
tui_calc_geometry 14 70
run_whiptail --title "Installation starten" \
--yesno "Folgende Konfiguration wird ausgeführt:\n\n- Ziel-Benutzer: $target_user\n- Ausgewählte Stages: $selected_stages\n\nMöchtest du die Installation jetzt starten?" \
"$TUI_HEIGHT" "$TUI_WIDTH"
}
Executable
+460
View File
@@ -0,0 +1,460 @@
#!/usr/bin/env bash
# ==============================================================================
# lib/utils.sh - Common utilities, logging, error handling & user detection
# ==============================================================================
set -euo pipefail
# ANSI Color Codes
export CLR_RESET='\033[0m'
export CLR_BOLD='\033[1m'
export CLR_DIM='\033[2m'
export CLR_RED='\033[0;31m'
export CLR_GREEN='\033[0;32m'
export CLR_YELLOW='\033[0;33m'
export CLR_BLUE='\033[0;34m'
export CLR_MAGENTA='\033[0;35m'
export CLR_CYAN='\033[0;36m'
export CLR_WHITE='\033[0;37m'
# Disable colors if not running in a terminal
if [[ ! -t 1 ]]; then
CLR_RESET=""
CLR_BOLD=""
CLR_DIM=""
CLR_RED=""
CLR_GREEN=""
CLR_YELLOW=""
CLR_BLUE=""
CLR_MAGENTA=""
CLR_CYAN=""
CLR_WHITE=""
fi
# Logging functions
log_info() {
printf "${CLR_BLUE}[INFO]${CLR_RESET} %s\n" "$*"
}
log_success() {
printf "${CLR_GREEN}[✓]${CLR_RESET} %s\n" "$*"
}
log_warn() {
printf "${CLR_YELLOW}[WARN]${CLR_RESET} %s\n" "$*" >&2
}
log_error() {
printf "${CLR_RED}[ERROR]${CLR_RESET} %s\n" "$*" >&2
}
log_step() {
printf "\n${CLR_BOLD}${CLR_CYAN}==>${CLR_RESET} ${CLR_BOLD}%s${CLR_RESET}\n" "$*"
}
log_substep() {
printf " ${CLR_CYAN}->${CLR_RESET} %s\n" "$*"
}
# Error trap handler
setup_err_trap() {
# Required so the ERR trap also fires for failures inside sourced
# lib/*.sh functions (errtrace) and nested function calls (functrace),
# not just for top-level commands in the stage script itself.
set -o errtrace
set -o functrace
trap 'error_handler $? $LINENO "$BASH_COMMAND"' ERR
}
# Re-arms 'set -e' for the *next* command only, via a self-removing DEBUG
# trap. Bash normally terminates the script right after an ERR trap when
# errexit is set, no matter what the trap does - the only way to make the
# script actually resume past the failed line is to have errexit disabled
# at the moment the trap returns. Must be the very last statement executed
# on the "resume" path (no trailing 'return'/'break'/...): any further
# command run inside error_handler itself would consume the DEBUG trap's
# one-shot reset before control ever gets back to the failed line.
resume_after_error() {
set +e
trap 'set -e; trap - DEBUG' DEBUG
}
# Ask the user what to do about a failed command.
# Echoes one of: r (retry), i (ignore), a (abort). Defaults to "a" when
# not running interactively (piped install, CI, DEBIAN_FRONTEND=noninteractive,
# AUTO_CONFIRM=1) or when the prompt can't be read, so unattended installs
# keep failing hard exactly like before this feature existed.
ask_retry_ignore_abort() {
local is_interactive=0
if { [[ -t 0 ]] || has_tty; } && [[ "${DEBIAN_FRONTEND:-}" != "noninteractive" && "${CI:-}" != "1" && "${AUTO_CONFIRM:-}" != "1" ]]; then
is_interactive=1
fi
if [[ "$is_interactive" -ne 1 ]]; then
echo "a"
return 0
fi
local tty_in="/dev/tty"
local tty_out="/dev/tty"
if ! has_tty; then
tty_in="/dev/stdin"
tty_out="/dev/stderr"
fi
local prompt answer=""
prompt="$(printf "%b[W]iederholen%b / %b[i]gnorieren%b / %b[a]bbrechen%b (Standard: a): " \
"$CLR_BOLD" "$CLR_RESET" "$CLR_BOLD" "$CLR_RESET" "$CLR_BOLD" "$CLR_RESET")"
read -r -p "$prompt" answer < "$tty_in" > "$tty_out" 2>&1 || answer="a"
answer="$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< "$answer")"
case "$answer" in
[Ww]*) echo "r" ;;
[Ii]*) echo "i" ;;
*) echo "a" ;;
esac
}
error_handler() {
local exit_code="$1"
local line_no="$2"
local bash_command="$3"
log_error "Command failed with exit code $exit_code at line $line_no: '$bash_command'"
local choice
choice="$(ask_retry_ignore_abort)"
case "$choice" in
r)
# Bare shell keywords (return/exit/break/continue) can't be
# meaningfully re-run via eval - they'd just unwind the current
# function instead of redoing any actual work. Treat these like
# "ignore" instead of silently aborting on a nonsensical retry.
if [[ "$bash_command" =~ ^(return|exit|break|continue)([[:space:]]|$) ]]; then
log_warn "'$bash_command' kann nicht wiederholt werden - Fehler wird ignoriert."
resume_after_error
else
log_info "Wiederhole: $bash_command"
if eval "$bash_command"; then
log_success "Wiederholung erfolgreich, Installation wird fortgesetzt."
resume_after_error
else
error_handler "$?" "$line_no" "$bash_command"
fi
fi
;;
i)
log_warn "Fehler wird ignoriert, Installation wird fortgesetzt: $bash_command"
resume_after_error
;;
*)
log_error "Installation abgebrochen."
exit "$exit_code"
;;
esac
}
# Root permission check
require_root() {
if [[ "$(id -u)" -ne 0 ]]; then
log_error "This script must be run as root (or via sudo)!"
exit 1
fi
}
# Check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# ------------------------------------------------------------------------------
# Terminal / TTY helpers (required for interactive whiptail dialogs)
# ------------------------------------------------------------------------------
# Check whether a usable controlling terminal is available
has_tty() {
[[ -c /dev/tty ]] || return 1
{ : < /dev/tty; } 2>/dev/null || return 1
return 0
}
# Ensure TERM is set to a value newt/whiptail is able to render
ensure_term() {
case "${TERM:-}" in
""|dumb|unknown)
if [[ -f /usr/share/terminfo/x/xterm-256color || -f /lib/terminfo/x/xterm-256color ]]; then
export TERM="xterm-256color"
else
export TERM="linux"
fi
;;
esac
}
# Report the current terminal size as "<lines> <columns>"
get_term_size() {
local size=""
if has_tty; then
size="$(stty size < /dev/tty 2>/dev/null || true)"
fi
if [[ -z "$size" ]]; then
size="$(stty size 2>/dev/null || true)"
fi
if [[ ! "$size" =~ ^[0-9]+[[:space:]]+[0-9]+$ ]]; then
size="${LINES:-24} ${COLUMNS:-80}"
fi
echo "$size"
}
# Run whiptail with stdin and stdout bound to the controlling terminal.
# This is required because the setup may be started through a pipe
# (e.g. 'curl ... | bash'), where stdin is not the terminal and all
# keystrokes would otherwise be swallowed by the shell instead of the dialog.
# Dialog results must be requested via '--output-fd 3'.
run_whiptail() {
ensure_term
if has_tty; then
whiptail "$@" < /dev/tty > /dev/tty
else
whiptail "$@"
fi
}
# Ask a yes/no question on the CLI. Returns 0 for yes, 1 for no.
# On read failure (e.g. closed stdin), falls back to default_answer.
# Usage: confirm_yes_no "<prompt>" "<y|n default answer>" "$tty_in" "$tty_out"
confirm_yes_no() {
local prompt="$1"
local default_answer="$2"
local tty_in="$3"
local tty_out="$4"
local answer=""
read -r -p "$prompt" answer < "$tty_in" > "$tty_out" 2>&1 || answer="$default_answer"
answer="$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< "$answer")"
if [[ -z "$answer" ]]; then
answer="$default_answer"
fi
[[ "$answer" =~ ^[YyJj] ]]
}
# Determine and prompt for the non-root target user
prompt_target_user() {
if [[ -n "${TARGET_USER:-}" ]]; then
echo "$TARGET_USER"
return 0
fi
local candidate=""
if [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != "root" ]]; then
candidate="$SUDO_USER"
elif [[ -n "${PKEXEC_UID:-}" ]]; then
candidate="$(id -nu "$PKEXEC_UID" 2>/dev/null || true)"
elif [[ "$(id -u)" -ne 0 ]]; then
candidate="$(id -un)"
fi
# If candidate is still empty or root, try to detect the first normal user with UID >= 1000
if [[ -z "$candidate" || "$candidate" == "root" ]]; then
candidate="$(awk -F: '$3 >= 1000 && $3 < 60000 && $1 != "nobody" {print $1; exit}' /etc/passwd 2>/dev/null || true)"
fi
local chosen=""
local is_interactive=0
if { [[ -t 0 ]] || has_tty; } && [[ "${DEBIAN_FRONTEND:-}" != "noninteractive" && "${CI:-}" != "1" && "${AUTO_CONFIRM:-}" != "1" ]]; then
is_interactive=1
fi
if [[ "$is_interactive" -eq 1 ]]; then
local tty_in="/dev/tty"
local tty_out="/dev/tty"
if ! has_tty; then
tty_in="/dev/stdin"
tty_out="/dev/stderr"
fi
if [[ -n "$candidate" && "$candidate" != "root" ]]; then
printf "\n%bTarget User Detection:%b\n" "${CLR_CYAN}" "${CLR_RESET}" > "$tty_out"
printf "Detected target user: %b%s%b\n" "${CLR_BOLD}" "$candidate" "${CLR_RESET}" > "$tty_out"
if confirm_yes_no "Use target user '$candidate'? [Y/n]: " "y" "$tty_in" "$tty_out"; then
chosen="$candidate"
fi
fi
while [[ -z "$chosen" ]]; do
local input_user=""
read -r -p "Please enter the target desktop username: " input_user < "$tty_in" > "$tty_out" 2>&1 || true
input_user="$(echo "$input_user" | tr -d '[:space:]')"
if [[ -z "$input_user" ]]; then
printf "%bUsername cannot be empty.%b\n" "${CLR_YELLOW}" "${CLR_RESET}" > "$tty_out"
continue
fi
if [[ "$input_user" == "root" ]]; then
printf "%bRoot cannot be used as target desktop user.%b\n" "${CLR_YELLOW}" "${CLR_RESET}" > "$tty_out"
continue
fi
if ! id "$input_user" >/dev/null 2>&1; then
printf "%bUser '%s' does not exist on this system.%b\n" "${CLR_YELLOW}" "$input_user" "${CLR_RESET}" > "$tty_out"
continue
fi
chosen="$input_user"
done
else
chosen="$candidate"
fi
if [[ -z "$chosen" || "$chosen" == "root" ]]; then
log_error "Could not determine a valid non-root desktop target user."
return 1
fi
if ! id "$chosen" >/dev/null 2>&1; then
log_error "Target user '$chosen' does not exist."
return 1
fi
export TARGET_USER="$chosen"
echo "$chosen"
}
# Get the target user (memoized / exported in TARGET_USER)
get_target_user() {
prompt_target_user
}
# Get home directory of target user
get_target_home() {
local user
user="$(get_target_user)"
local user_home
user_home="$(getent passwd "$user" | cut -d: -f6)"
if [[ -z "$user_home" || ! -d "$user_home" ]]; then
user_home="/home/$user"
fi
echo "$user_home"
}
# Prompt for Ollama AI models storage path
prompt_ollama_models_path() {
if [[ -n "${OLLAMA_MODELS:-}" ]]; then
echo "$OLLAMA_MODELS"
return 0
fi
# Ollama's own default storage location (used by the official install
# script / systemd service, which runs as the "ollama" user).
local ollama_default_path="/usr/share/ollama/.ollama/models"
# Suggested custom path, only ever pre-filled once the user has
# explicitly declined the Ollama default above.
local custom_path_suggestion="${OLLAMA_MODELS_DEFAULT:-/mnt/Data/Software/ollama/models}"
local chosen=""
local is_interactive=0
if { [[ -t 0 ]] || has_tty; } && [[ "${DEBIAN_FRONTEND:-}" != "noninteractive" && "${CI:-}" != "1" && "${AUTO_CONFIRM:-}" != "1" ]]; then
is_interactive=1
fi
if [[ "$is_interactive" -eq 1 ]]; then
local tty_in="/dev/tty"
local tty_out="/dev/tty"
if ! has_tty; then
tty_in="/dev/stdin"
tty_out="/dev/stderr"
fi
# If whiptail is available and running on an active terminal, first ask
# whether Ollama's own default path should be used, and only show the
# free-text path dialog (pre-filled with the custom suggestion) if not.
if command_exists whiptail && has_tty; then
local yesno_status=0
run_whiptail --title "Ollama KI-Modelle Speicherort" \
--yes-button "Standard verwenden" --no-button "Eigenen Pfad angeben" \
--yesno "Standard-Speicherort für Ollama-Modelle:\n\n$ollama_default_path\n\nMöchtest du diesen Speicherort verwenden?" \
12 70 || yesno_status=$?
if [[ "$yesno_status" -eq 0 || "$yesno_status" -eq 255 ]]; then
# Yes, or ESC/Cancel (255) - use the Ollama default,
# consistent with the inputbox fallback below where an
# empty or cancelled dialog also keeps its own default
# instead of asking again.
chosen="$ollama_default_path"
fi
if [[ -z "$chosen" ]]; then
local tui_tmp
tui_tmp="$(mktemp)"
if run_whiptail --output-fd 3 --title "Ollama KI-Modelle Speicherort" \
--inputbox "Bitte gib den Speicherort für die Ollama KI-Modelle an:" \
10 70 "$custom_path_suggestion" \
3> "$tui_tmp"; then
chosen="$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' < "$tui_tmp")"
fi
rm -f "$tui_tmp"
[[ -z "$chosen" ]] && chosen="$custom_path_suggestion"
fi
fi
# CLI fallback if whiptail was not used or failed
if [[ -z "$chosen" ]]; then
printf "\n%bOllama KI-Modelle Speicherort:%b\n" "${CLR_CYAN}" "${CLR_RESET}" > "$tty_out"
printf "Standard-Pfad: %b%s%b\n" "${CLR_BOLD}" "$ollama_default_path" "${CLR_RESET}" > "$tty_out"
if confirm_yes_no "Standard-Speicherort verwenden? [J/n]: " "j" "$tty_in" "$tty_out"; then
chosen="$ollama_default_path"
else
local input_path=""
read -r -p "Speicherort für Ollama-Modelle eingeben [$custom_path_suggestion]: " input_path < "$tty_in" > "$tty_out" 2>&1 || true
input_path="$(echo "$input_path" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
if [[ -n "$input_path" ]]; then
chosen="$input_path"
else
chosen="$custom_path_suggestion"
fi
fi
fi
else
chosen="$ollama_default_path"
fi
export OLLAMA_MODELS="$chosen"
echo "$chosen"
}
# Run a command as the target user
run_as_target_user() {
local user
user="$(get_target_user)"
if [[ "$(id -un)" == "$user" ]]; then
"$@"
else
su -l "$user" -s /bin/bash -c "$(printf "%q " "$@")"
fi
}
run_as_user() {
run_as_target_user "$@"
}
# Create a safe temporary directory with auto-cleanup
create_temp_dir() {
local prefix="${1:-setup-temp}"
local tmp_dir
tmp_dir="$(mktemp -d "/tmp/${prefix}.XXXXXX")"
echo "$tmp_dir"
}
# Safe backup function
backup_file_or_dir() {
local target="$1"
local timestamp
timestamp="$(date +%Y%m%d_%H%M%S)"
if [[ -e "$target" ]]; then
local backup_path="${target}.backup_${timestamp}"
if cp -r "$target" "$backup_path" 2>/dev/null; then
log_info "Created backup: $backup_path"
else
log_warn "Could not create backup of $target (permission denied)."
fi
fi
}
backup_file() {
backup_file_or_dir "$@"
}
Executable
+281
View File
@@ -0,0 +1,281 @@
#!/usr/bin/env bash
# ==============================================================================
# setup.sh - Central Orchestrator for Debian Unstable Setup & Hyprland Installer
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Source Libraries & Config
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/apt.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
source "$SCRIPT_DIR/lib/network.sh"
source "$SCRIPT_DIR/lib/tui.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
# Reconnect stdin/stdout to the controlling terminal when the script was
# started through a pipe (e.g. 'curl ... | bash'). Otherwise keystrokes are
# consumed by the shell and never reach the interactive whiptail dialogs.
if has_tty; then
if [[ ! -t 0 ]]; then
exec < /dev/tty
fi
if [[ ! -t 1 ]]; then
exec > /dev/tty
fi
fi
ensure_term
# Show help text
show_help() {
cat <<EOF
Usage: ./setup.sh [OPTIONS]
Debian Unstable Setup & Desktop Customization Framework
Note: setup.sh elevates itself via sudo once needed, after any interactive
prompts have been answered. Run it as your normal desktop user - no need to
prefix it with 'sudo' yourself (though doing so still works).
Options:
-a, --all Run all setup stages sequentially (00 through 11)
-s, --stages <list> Comma-separated list of stages to run (e.g. --stages 01,02,04)
-u, --user <username> Specify target desktop user (defaults to \$SUDO_USER)
-d, --dry-run Simulate stage execution without modifying the system
-h, --help Show this help message and exit
Available Stages:
00: Pre-flight Checks (System, Privileges, Internet)
01: Debian Unstable Migration (Deb822, Pinning, apt-listbugs, dist-upgrade)
02: Kernel & Hardware Tuning (XanMod, AMD/Intel P-State, auto-cpufreq)
03: Bootloader & Splash (GRUB configuration, Vimix Theme, Plymouth Solar)
04: Package Installation (Base, Desktop, Gaming, Virtualization, Multimedia)
05: Font Installation (JetBrainsMono, FantasqueSans, VictorMono)
06: System Services (AppArmor, Docker, Libvirt, zram, Ollama)
07: Skel & User Environment (Zsh, Templates, Dotfiles Sync)
08: Flatpak Applications (Flathub, Flatpak package list)
09: Standalone Applications & MIME (Spotify, Waydroid, OpenDeck, MIME types)
10: Hyprland Desktop (LinuxBeginnings Auto-Installer)
11: Linutil (Chris Titus Tech System Toolbox)
Examples:
./setup.sh # Interactive TUI mode
./setup.sh --all # Full automated install
./setup.sh --stages 04,05 # Install only packages and fonts
./setup.sh --stages 01 --dry-run # Dry-run stage 01
EOF
}
# CLI Flags
FLAG_ALL=0
FLAG_STAGES=""
FLAG_DRY_RUN=0
export FLAG_DRY_RUN
CLI_USER=""
# Parse CLI arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-a|--all)
FLAG_ALL=1
shift
;;
-s|--stages)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
FLAG_STAGES="$2"
shift 2
else
log_error "Option '$1' requires a comma-separated list of stages."
exit 1
fi
;;
-u|--user)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
CLI_USER="$2"
shift 2
else
log_error "Option '$1' requires a username."
exit 1
fi
;;
-d|--dry-run)
FLAG_DRY_RUN=1
shift
;;
-h|--help)
show_help
exit 0
;;
*)
log_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
if [[ -n "$CLI_USER" ]]; then
export TARGET_USER="$CLI_USER"
fi
# NOTE: Root privileges are intentionally NOT required here. All interactive
# prompts (whiptail TUI, target user, Ollama path) must run BEFORE escalating
# to sudo - see the privilege escalation block below for why.
# Determine stages to run
SELECTED_STAGES=()
if [[ "$FLAG_ALL" -eq 1 ]]; then
SELECTED_STAGES=(01 02 03 04 05 06 07 08 09 10 11)
elif [[ -n "$FLAG_STAGES" ]]; then
IFS=',' read -r -a raw_stages <<< "$FLAG_STAGES"
for st in "${raw_stages[@]}"; do
# Format single digit numbers to two digits (e.g. 1 -> 01)
st="$(echo "$st" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
if [[ "$st" =~ ^[0-9]$ ]]; then
st="0$st"
fi
SELECTED_STAGES+=("$st")
done
else
# Interactive TUI Mode
if has_tty; then
tui_check_whiptail
tui_welcome
if ! tui_select_stages; then
log_info "Setup aborted by user."
exit 0
fi
if [[ -z "${TUI_SELECTION:-}" ]]; then
log_warn "No stages selected. Exiting."
exit 0
fi
read -r -a SELECTED_STAGES <<< "$TUI_SELECTION"
DETECTED_USER="${TARGET_USER:-${SUDO_USER:-$(logname 2>/dev/null || id -un 2>/dev/null || true)}}"
if [[ "$DETECTED_USER" == "root" ]]; then
DETECTED_USER=""
fi
tui_prompt_target_user "$DETECTED_USER"
if ! tui_confirm_execution "${SELECTED_STAGES[*]}" "$TARGET_USER"; then
log_info "Installation aborted by user."
exit 0
fi
else
log_warn "No controlling terminal available - interactive TUI cannot be displayed."
log_info "Non-interactive shell and no parameters provided. Defaulting to --all."
SELECTED_STAGES=(01 02 03 04 05 06 07 08 09 10 11)
fi
fi
# Ensure TARGET_USER is determined and confirmed for all stages
if [[ -z "${TARGET_USER:-}" ]]; then
TARGET_USER="$(get_target_user)"
export TARGET_USER
fi
# Pre-resolve the Ollama models path here (while still unprivileged and
# directly attached to the terminal) if stage 06 will run, so stage
# 06-services.sh never has to prompt again after privilege escalation.
if [[ "$FLAG_DRY_RUN" -eq 0 ]] && [[ -z "${OLLAMA_MODELS:-}" ]]; then
for st in "${SELECTED_STAGES[@]}"; do
if [[ "$st" == "06" ]]; then
OLLAMA_MODELS="$(prompt_ollama_models_path)"
export OLLAMA_MODELS
break
fi
done
fi
# Escalate to root via sudo now that every interactive prompt (whiptail TUI,
# target user, Ollama path) has already been answered while directly attached
# to the terminal. sudo run from a non-interactive shell (e.g. 'curl | bash')
# does not reliably hand the controlling terminal's foreground process group
# to the command it execs, which leaves whiptail/read unable to receive any
# keystrokes. Running all interactive dialogs before this point, and passing
# the already-resolved choices through as flags/env vars, avoids ever needing
# terminal input again after the sudo boundary.
if [[ "$FLAG_DRY_RUN" -eq 0 ]] && [[ "$(id -u)" -ne 0 ]]; then
if ! command_exists sudo; then
log_error "sudo is required to run setup.sh. Please install sudo or run as root."
exit 1
fi
log_info "Elevating privileges via sudo to continue installation..."
joined_stages="$(IFS=,; echo "${SELECTED_STAGES[*]}")"
sudo_env_args=("TARGET_USER=$TARGET_USER")
if [[ -n "${OLLAMA_MODELS:-}" ]]; then
sudo_env_args+=("OLLAMA_MODELS=$OLLAMA_MODELS")
fi
exec sudo "${sudo_env_args[@]}" bash "$SCRIPT_DIR/setup.sh" --stages "$joined_stages" --user "$TARGET_USER"
fi
if [[ "$FLAG_DRY_RUN" -eq 0 ]]; then
require_root
fi
# Map stage identifier to script file
get_stage_script() {
local stage_id="$1"
local match
match="$(find "$SCRIPT_DIR/stages" -maxdepth 1 -name "${stage_id}-*.sh" -type f | head -n1)"
echo "$match"
}
# Always run preflight check first unless dry-run
if [[ "$FLAG_DRY_RUN" -eq 0 ]]; then
PREFLIGHT_SCRIPT="$(get_stage_script "00")"
if [[ -n "$PREFLIGHT_SCRIPT" && -f "$PREFLIGHT_SCRIPT" ]]; then
bash "$PREFLIGHT_SCRIPT"
fi
fi
# Banner
log_step "Starting Debian Unstable Setup Execution"
log_info "Target User: $(get_target_user)"
log_info "Planned Stages: ${SELECTED_STAGES[*]}"
if [[ "$FLAG_DRY_RUN" -eq 1 ]]; then
log_warn "DRY-RUN MODE: No changes will be made to the system."
fi
# Create pre-setup baseline Timeshift snapshot if on Btrfs
create_timeshift_snapshot "Pre-Setup Baseline: Before executing stages (${SELECTED_STAGES[*]})" "B"
# Execute Selected Stages
for stage in "${SELECTED_STAGES[@]}"; do
# Skip 00 if it was manually added since it already ran
if [[ "$stage" == "00" ]]; then
continue
fi
SCRIPT="$(get_stage_script "$stage")"
if [[ -z "$SCRIPT" || ! -f "$SCRIPT" ]]; then
log_warn "Stage script for '$stage' not found in $SCRIPT_DIR/stages! Skipping."
continue
fi
STAGE_NAME="$(basename "$SCRIPT" .sh)"
log_step "Executing Stage: $STAGE_NAME"
if [[ "$FLAG_DRY_RUN" -eq 1 ]]; then
log_info "[DRY-RUN] Would execute: bash $SCRIPT"
else
bash "$SCRIPT"
log_success "Completed Stage: $STAGE_NAME"
fi
done
# Create final completion Timeshift snapshot if on Btrfs
create_timeshift_snapshot "Post-Setup Final: All stages completed successfully (${SELECTED_STAGES[*]})" "O"
log_step "All selected setup stages completed successfully!"
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/00-preflight.sh - System pre-flight checks, permissions & internet connectivity
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
source "$SCRIPT_DIR/lib/network.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 00: Pre-flight System Checks..."
# 1. Check Root Privileges
log_substep "Checking root privileges..."
require_root
log_success "Running with root privileges."
# 2. Check Target Desktop User
log_substep "Detecting non-root target user..."
TARGET_USER="$(get_target_user)"
TARGET_HOME="$(get_target_home)"
if [[ -z "$TARGET_USER" || "$TARGET_USER" == "root" ]]; then
log_error "Could not determine target user. Run via 'sudo ./setup.sh' as the desktop user or set TARGET_USER=<user>."
exit 1
fi
log_success "Target user identified: $TARGET_USER (Home: $TARGET_HOME)"
# 3. Configure and Activate Network Interfaces (Loopback & LAN)
log_substep "Initializing and activating network interfaces (Loopback & LAN)..."
configure_loopback_interface
configure_lan_interfaces
# 4. Check Internet Connectivity
log_substep "Checking internet connectivity..."
INTERNET_OK=0
for host in "deb.debian.org" "1.1.1.1" "8.8.8.8"; do
if ping -c 1 -W 3 "$host" >/dev/null 2>&1 || curl -s --head --connect-timeout 3 "http://$host" >/dev/null 2>&1; then
INTERNET_OK=1
break
fi
done
if [[ "$INTERNET_OK" -ne 1 ]]; then
log_error "No active internet connection detected. Please connect to the internet and try again."
exit 1
fi
log_success "Internet connection verified."
# 5. Check Operating System
log_substep "Verifying operating system..."
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
source /etc/os-release
log_info "Detected OS: ${NAME:-Debian} ${VERSION_ID:-} (${VERSION_CODENAME:-sid})"
if [[ "${ID:-}" != "debian" && "${ID_LIKE:-}" != *"debian"* ]]; then
log_warn "This setup script is optimized for Debian GNU/Linux. Current ID is '${ID:-unknown}'."
fi
else
log_warn "/etc/os-release not found. Proceeding with caution."
fi
# 6. Check Disk Space
log_substep "Checking available disk space..."
AVAILABLE_KB=$(df --output=avail / | tail -n1)
if [[ "$AVAILABLE_KB" -lt 5242880 ]]; then # Less than 5 GB
log_warn "Less than 5 GB of free space available on root partition ($(( AVAILABLE_KB / 1024 )) MB free)."
else
log_success "Sufficient disk space available ($(( AVAILABLE_KB / 1024 / 1024 )) GB free)."
fi
# 7. Check & Setup Btrfs Subvolumes (@, @home)
log_substep "Checking Btrfs root volume & subvolume layout..."
check_and_setup_btrfs_subvolumes
# 8. Create Timeshift Btrfs Snapshot after preflight & subvolume setup
create_timeshift_snapshot "Stage 00: Pre-flight checks & Btrfs baseline" "B"
log_success "Stage 00: Pre-flight checks passed successfully."
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/01-apt-unstable.sh - Migration to Debian Unstable (Deb822), Pinning & Upgrade
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/apt.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 01: Debian Unstable Migration & Package Sources Configuration"
require_root
# 1. Install prerequisites for APT HTTPS & Keyrings
log_substep "Installing APT prerequisites (curl, gnupg, ca-certificates)..."
DEBIAN_FRONTEND=noninteractive apt-get update -y
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
curl \
gnupg \
gpg \
ca-certificates \
apt-transport-https \
debian-archive-keyring
# 2. Enable 32-bit (i386) Multiarch Architecture
log_substep "Enabling 32-bit (i386) multiarch architecture..."
apt_enable_i386
# 3. Ensure Keyrings directory exists and install repository keyrings
apt_ensure_keyrings_dir
log_substep "Installing custom repository keyrings..."
apt_add_keyring_from_url "https://gitea.creative-dragonslayer.de/api/packages/Linuxapps/debian/repository.key" "gitea-Linuxapps.asc" || log_warn "Could not fetch gitea-Linuxapps.asc keyring."
apt_add_keyring_from_url "https://gitea.creative-dragonslayer.de/api/packages/Mirror/debian/repository.key" "gitea-Mirror.asc" || log_warn "Could not fetch gitea-Mirror.asc keyring."
# 4. Migrate /etc/apt/sources.list to Deb822 format
log_substep "Migrating APT sources to Deb822 format..."
if [[ -f /etc/apt/sources.list && ! -f /etc/apt/sources.list.bak_pre_unstable ]]; then
cp /etc/apt/sources.list /etc/apt/sources.list.bak_pre_unstable
# Comment out active lines in legacy sources.list to avoid duplicate source warnings
sed -i 's/^[[:space:]]*deb/# deb/' /etc/apt/sources.list
fi
# Deploy Deb822 sources
log_substep "Deploying Deb822 APT sources..."
if compgen -G "$SCRIPT_DIR/data/apt/sources.list.d/*.sources" > /dev/null; then
for src_file in "$SCRIPT_DIR"/data/apt/sources.list.d/*.sources; do
if [[ "$(basename "$src_file")" != "xanmod.sources" ]]; then
apt_install_sources_file "$src_file" "$(basename "$src_file")"
fi
done
fi
# 5. Deploy APT Preferences / Pinning
log_substep "Configuring APT Pinning preferences..."
mkdir -p /etc/apt/preferences.d
if compgen -G "$SCRIPT_DIR/data/apt/preferences.d/*.pref" > /dev/null; then
for pref_file in "$SCRIPT_DIR"/data/apt/preferences.d/*.pref; do
apt_install_preference_file "$pref_file" "$(basename "$pref_file")"
done
fi
# 6. Install apt-listbugs and apt-listchanges to safeguard Unstable upgrades
log_substep "Installing protection tools (apt-listbugs, apt-listchanges)..."
apt_update
DEBIAN_FRONTEND=noninteractive apt-get install -y apt-listbugs apt-listchanges
# 7. Perform Full Dist-Upgrade
log_substep "Performing full distribution upgrade to Debian Sid..."
create_timeshift_snapshot "Stage 01: Pre-dist-upgrade to Debian Sid" "B"
apt_dist_upgrade
create_timeshift_snapshot "Stage 01: Post-dist-upgrade to Debian Sid" "O"
log_success "Stage 01: Debian Unstable migration and upgrade completed successfully!"
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/02-kernel-hardware.sh - XanMod Kernel, Microcode, auto-cpufreq & Hardware Tuning
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/apt.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 02: Kernel & Hardware Tuning"
require_root
# 1. Setup XanMod Kernel Repository
log_substep "Configuring XanMod Kernel repository..."
apt_ensure_keyrings_dir
apt_add_keyring_from_url "https://dl.xanmod.org/archive.key" "xanmod-archive-keyring.gpg"
if [[ -f "$SCRIPT_DIR/data/apt/sources.list.d/xanmod.sources" ]]; then
apt_install_sources_file "$SCRIPT_DIR/data/apt/sources.list.d/xanmod.sources" "xanmod.sources"
fi
apt_update
# 2. Determine XanMod Kernel Package
log_substep "Detecting CPU microarchitecture level and XanMod branch..."
create_timeshift_snapshot "Stage 02: Pre-XanMod kernel installation" "B"
BRANCH="${XANMOD_BRANCH:-main}"
log_info "Configured XanMod branch: $BRANCH"
BRANCH_SUFFIX=""
if [[ "$BRANCH" != "main" && -n "$BRANCH" ]]; then
BRANCH_SUFFIX="-$BRANCH"
fi
# Detect CPU x86-64 microarchitecture level
ARCH_SUFFIX="-x64v2"
if grep -q "avx2" /proc/cpuinfo 2>/dev/null; then
ARCH_SUFFIX="-x64v3"
log_info "CPU supports x86-64-v3 (AVX2 detected)."
else
log_info "CPU does not support AVX2. Using x86-64-v2."
fi
KERNEL_PKG="linux-xanmod${BRANCH_SUFFIX}${ARCH_SUFFIX}"
FALLBACK_PKG="linux-xanmod${BRANCH_SUFFIX}"
log_substep "Installing XanMod kernel package ($KERNEL_PKG)..."
if ! DEBIAN_FRONTEND=noninteractive apt-get install -y "$KERNEL_PKG"; then
log_warn "Failed to install $KERNEL_PKG, trying fallback package $FALLBACK_PKG..."
DEBIAN_FRONTEND=noninteractive apt-get install -y "$FALLBACK_PKG" || log_warn "XanMod installation failed, standard kernel will remain active."
fi
# 3. CPU Microcode Detection and Installation
log_substep "Detecting CPU vendor for microcode installation..."
CPU_VENDOR=$(lscpu 2>/dev/null | grep -oP 'Vendor ID:\s*\K.*' | tr -d ' ' || true)
case "$CPU_VENDOR" in
"AuthenticAMD")
log_info "AMD CPU detected ($CPU_VENDOR) -> Installing amd64-microcode"
DEBIAN_FRONTEND=noninteractive apt-get install -y amd64-microcode
;;
"GenuineIntel")
log_info "Intel CPU detected ($CPU_VENDOR) -> Installing intel-microcode"
DEBIAN_FRONTEND=noninteractive apt-get install -y intel-microcode
;;
*)
log_warn "Unknown CPU vendor '$CPU_VENDOR'. Skipping vendor-specific microcode."
;;
esac
# 4. Install & Enable auto-cpufreq from source repository
log_substep "Installing and configuring auto-cpufreq..."
if command_exists auto-cpufreq; then
log_info "auto-cpufreq is already installed."
else
log_info "Cloning and building auto-cpufreq from GitHub repository..."
# Ensure git and python3 build essentials are available
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends git python3 python3-pip python3-setuptools 2>/dev/null || true
TEMP_DIR="$(create_temp_dir "auto-cpufreq")"
if git clone --depth=1 https://github.com/AdnanHodzic/auto-cpufreq.git "$TEMP_DIR" 2>/dev/null; then
(
cd "$TEMP_DIR"
./auto-cpufreq-installer --install || ./auto-cpufreq-installer --install --non-interactive || true
)
rm -rf "$TEMP_DIR"
else
log_warn "Failed to clone auto-cpufreq repository from GitHub."
fi
fi
if command_exists auto-cpufreq; then
auto-cpufreq --install 2>/dev/null || true
if command_exists systemctl; then
systemctl enable --now auto-cpufreq 2>/dev/null || log_warn "Could not enable auto-cpufreq systemd service."
fi
log_success "auto-cpufreq installed and service enabled."
else
log_warn "auto-cpufreq installation could not be completed."
fi
# 5. Environment configuration (Raytracing & Upscaling)
log_substep "Deploying graphics and performance environment configurations..."
mkdir -p /etc/environment.d
if compgen -G "$SCRIPT_DIR/data/etc/environment.d/*.conf" > /dev/null; then
for env_file in "$SCRIPT_DIR"/data/etc/environment.d/*.conf; do
cp "$env_file" /etc/environment.d/
log_info "Installed environment config: $(basename "$env_file")"
done
fi
# 6. Persistent Shader Cache Location (Mesa & DXVK) - optional relocation
if [[ -n "${SHADER_CACHE_DIR:-}" ]]; then
log_substep "Configuring custom Mesa/DXVK shader cache location..."
TARGET_USER="${TARGET_USER:-$(prompt_target_user)}"
mkdir -p "$SHADER_CACHE_DIR"
chown -R "$TARGET_USER:$TARGET_USER" "$SHADER_CACHE_DIR"
cat <<EOF > /etc/environment.d/99-shader-cache.conf
# Persistent Mesa (RADV/OpenGL) & DXVK (Wine/Proton) shader/pipeline cache,
# relocated off the system disk to avoid re-compilation stutter after reboots.
MESA_SHADER_CACHE_DIR=$SHADER_CACHE_DIR
DXVK_STATE_CACHE_PATH=$SHADER_CACHE_DIR
EOF
chmod 0644 /etc/environment.d/99-shader-cache.conf
log_success "Shader cache directory set to $SHADER_CACHE_DIR"
else
log_info "SHADER_CACHE_DIR not set - keeping Mesa's and DXVK's own default shader cache locations."
fi
create_timeshift_snapshot "Stage 02: Post-kernel and hardware tuning" "O"
log_success "Stage 02: Kernel and Hardware Tuning completed successfully!"
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/03-bootloader.sh - GRUB configuration, CPU P-State, Vimix Theme & Plymouth
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 03: Bootloader & Splash Screen Configuration"
require_root
GRUB_CFG="/etc/default/grub"
GRUB_TIMEOUT="${GRUB_TIMEOUT:-5}"
GRUB_TIMEOUT_STYLE="${GRUB_TIMEOUT_STYLE:-menu}"
GRUB_CMDLINE_LINUX_DEFAULT_BASE="quiet splash apparmor=1 usbcore.autosuspend=-1 vt.global_cursor_default=0 loglevel=3 rd.luks.options=discard plymouth.ignore-serial-consoles threadirqs"
GRUB_CMDLINE_LINUX="rcutree.rcu_idle_gp_delay=1"
GRUB_THEME_DIR="/usr/share/debian-gaming/grub/grub2-themes"
# 1. CPU P-State Detection
log_substep "Detecting CPU vendor for P-State parameter..."
CPU_VENDOR=$(lscpu 2>/dev/null | grep -oP 'Vendor ID:\s*\K.*' | tr -d ' ' || true)
CPU_MODEL=$(lscpu 2>/dev/null | grep -oP 'Model name:\s*\K.*' | head -c 30 || true)
log_info "Detected CPU: $CPU_MODEL ($CPU_VENDOR)"
CPU_PARAM=""
case "$CPU_VENDOR" in
"AuthenticAMD")
CPU_PARAM="amd_pstate=active"
log_info "AMD CPU detected -> Adding amd_pstate=active"
;;
"GenuineIntel")
CPU_PARAM="intel_pstate=active"
log_info "Intel CPU detected -> Adding intel_pstate=active"
;;
*)
log_warn "Unknown CPU Vendor '$CPU_VENDOR' - no CPU pstate parameter added."
;;
esac
if [[ -n "$CPU_PARAM" ]]; then
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT_BASE $CPU_PARAM"
else
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT_BASE"
fi
# 2. Configure /etc/default/grub
if [[ -f "$GRUB_CFG" ]]; then
log_substep "Updating $GRUB_CFG..."
backup_file_or_dir "$GRUB_CFG"
# Set parameters with sed
sed -i "s|^GRUB_TIMEOUT=.*|GRUB_TIMEOUT=$GRUB_TIMEOUT|" "$GRUB_CFG"
sed -i "s|^GRUB_TIMEOUT_STYLE=.*|GRUB_TIMEOUT_STYLE=$GRUB_TIMEOUT_STYLE|" "$GRUB_CFG"
sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$GRUB_CMDLINE_LINUX_DEFAULT\"|" "$GRUB_CFG"
sed -i "s|^GRUB_CMDLINE_LINUX=.*|GRUB_CMDLINE_LINUX=\"$GRUB_CMDLINE_LINUX\"|" "$GRUB_CFG"
# Ensure entries exist if sed didn't find them
grep -q '^GRUB_TIMEOUT=' "$GRUB_CFG" || echo "GRUB_TIMEOUT=$GRUB_TIMEOUT" >> "$GRUB_CFG"
grep -q '^GRUB_TIMEOUT_STYLE=' "$GRUB_CFG" || echo "GRUB_TIMEOUT_STYLE=$GRUB_TIMEOUT_STYLE" >> "$GRUB_CFG"
grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' "$GRUB_CFG" || echo "GRUB_CMDLINE_LINUX_DEFAULT=\"$GRUB_CMDLINE_LINUX_DEFAULT\"" >> "$GRUB_CFG"
grep -q '^GRUB_CMDLINE_LINUX=' "$GRUB_CFG" || echo "GRUB_CMDLINE_LINUX=\"$GRUB_CMDLINE_LINUX\"" >> "$GRUB_CFG"
else
log_warn "$GRUB_CFG not found. Is GRUB installed?"
fi
# 3. Install & Configure Plymouth
log_substep "Installing and configuring Plymouth splash theme..."
if DEBIAN_FRONTEND=noninteractive apt-get install -y plymouth plymouth-themes 2>/dev/null; then
PLYMOUTH_THEME="${PLYMOUTH_THEME:-solar}"
if command_exists plymouth-set-default-theme; then
plymouth-set-default-theme -R "$PLYMOUTH_THEME" 2>/dev/null || log_warn "Could not set Plymouth theme to $PLYMOUTH_THEME"
log_success "Plymouth configured with theme: $PLYMOUTH_THEME"
fi
fi
# 4. Install Vimix GRUB Theme
log_substep "Installing Vimix GRUB theme..."
DEBIAN_FRONTEND=noninteractive apt-get install -y git 2>/dev/null || true
mkdir -p "$GRUB_THEME_DIR"
if [[ ! -d "$GRUB_THEME_DIR/.git" ]]; then
if git clone --depth 1 https://github.com/vinceliuice/grub2-themes.git "$GRUB_THEME_DIR" 2>/dev/null; then
"$GRUB_THEME_DIR/install.sh" -b -t "${GRUB_THEME:-vimix}" 2>/dev/null || log_warn "Vimix theme installer encountered an issue."
log_success "Vimix GRUB theme installed."
else
log_warn "Failed to clone grub2-themes repository. Skipping theme."
fi
else
log_info "GRUB Theme repository already cloned; updating..."
(cd "$GRUB_THEME_DIR" && git pull 2>/dev/null && ./install.sh -b -t "${GRUB_THEME:-vimix}" 2>/dev/null) || log_warn "Vimix theme update skipped."
fi
# 5. Configure GRUB Btrfs Snapshot Booting (grub-btrfs)
log_substep "Configuring GRUB Btrfs snapshot booting support..."
if is_root_btrfs; then
ensure_grub_btrfs
log_success "GRUB Btrfs snapshot booting configured."
else
log_info "Root filesystem is not Btrfs. Skipping grub-btrfs setup."
fi
# 6. Update GRUB & Initramfs
log_substep "Running update-grub and update-initramfs..."
if command_exists update-grub; then
update-grub
fi
if command_exists update-initramfs; then
update-initramfs -u 2>/dev/null || true
fi
log_success "Stage 03: Bootloader and Splash configuration completed successfully!"
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/04-packages.sh - Installation of categorised system and desktop packages
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/apt.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 04: Thematic Package Installation"
require_root
PACKAGES_DIR="$SCRIPT_DIR/config/packages"
if [[ ! -d "$PACKAGES_DIR" ]]; then
log_error "Package configuration directory $PACKAGES_DIR not found!"
exit 1
fi
create_timeshift_snapshot "Stage 04: Pre-thematic package installation" "B"
# List of APT package lists to process (excluding flatpaks which are handled in stage 08)
APT_LISTS=(
"01-base.list"
"02-desktop.list"
"03-gaming.list"
"04-virtualization.list"
"05-multimedia.list"
)
log_substep "Ensuring 32-bit (i386) multiarch architecture is enabled..."
apt_enable_i386
log_substep "Updating package lists before installation..."
apt_update
for list_name in "${APT_LISTS[@]}"; do
list_path="$PACKAGES_DIR/$list_name"
if [[ -f "$list_path" ]]; then
log_step "Installing package category: $list_name"
apt_install_package_list_file "$list_path" || log_warn "Some packages from $list_name could not be installed."
else
log_warn "Package list file $list_name not found in $PACKAGES_DIR."
fi
done
create_timeshift_snapshot "Stage 04: Post-thematic package installation" "O"
log_success "Stage 04: Thematic package installation completed successfully!"
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/05-fonts.sh - Download and clean installation of Coding & Nerd Fonts
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
setup_err_trap
log_step "Running Stage 05: Coding & Nerd Fonts Installation"
require_root
FONT_DIR="/usr/share/fonts"
TEMP_DIR="$(create_temp_dir "fonts-setup")"
# Ensure cleanup of temp directory on exit
cleanup() {
if [[ -d "$TEMP_DIR" ]]; then
log_info "Cleaning up temporary font download directory: $TEMP_DIR"
rm -rf "$TEMP_DIR"
fi
}
trap cleanup EXIT
mkdir -p "$FONT_DIR"
# 1. JetBrains Mono Nerd Font
log_substep "Downloading and installing JetBrainsMono Nerd Font..."
JB_ARCHIVE="$TEMP_DIR/JetBrainsMono.tar.xz"
JB_DEST="$FONT_DIR/JetBrainsMonoNerd"
if curl -fsSL "https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.tar.xz" -o "$JB_ARCHIVE"; then
mkdir -p "$JB_DEST"
tar -xJkf "$JB_ARCHIVE" -C "$JB_DEST" 2>/dev/null || tar -xJf "$JB_ARCHIVE" -C "$JB_DEST"
log_success "JetBrainsMono Nerd Font installed to $JB_DEST"
else
log_warn "Failed to download JetBrainsMono Nerd Font."
fi
# 2. Fantasque Sans Mono Nerd Font
log_substep "Downloading and installing Fantasque Sans Mono Nerd Font..."
FANTASQUE_ARCHIVE="$TEMP_DIR/FantasqueSansMono.zip"
FANTASQUE_DEST="$FONT_DIR/FantasqueSansMonoNerd"
if curl -fsSL "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.3.0/FantasqueSansMono.zip" -o "$FANTASQUE_ARCHIVE"; then
mkdir -p "$FANTASQUE_DEST"
unzip -o -q "$FANTASQUE_ARCHIVE" -d "$FANTASQUE_DEST"
log_success "FantasqueSansMono Nerd Font installed to $FANTASQUE_DEST"
else
log_warn "Failed to download FantasqueSansMono Nerd Font."
fi
# 3. Victor Mono Font
log_substep "Downloading and installing Victor Mono Font..."
VICTOR_ARCHIVE="$TEMP_DIR/VictorMonoAll.zip"
VICTOR_DEST="$FONT_DIR/VictorMono"
if curl -fsSL "https://rubjo.github.io/victor-mono/VictorMonoAll.zip" -o "$VICTOR_ARCHIVE"; then
mkdir -p "$VICTOR_DEST"
unzip -o -q "$VICTOR_ARCHIVE" -d "$VICTOR_DEST"
log_success "Victor Mono Font installed to $VICTOR_DEST"
else
log_warn "Failed to download Victor Mono Font."
fi
# 4. Refresh Font Cache
log_substep "Updating font cache..."
if command_exists fc-cache; then
fc-cache -f
log_success "Font cache refreshed."
fi
log_success "Stage 05: Fonts installation completed successfully!"
+227
View File
@@ -0,0 +1,227 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/06-services.sh - System services activation (AppArmor, Docker, Libvirt, zram, Ollama)
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/apt.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
source "$SCRIPT_DIR/lib/network.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 06: System Services Configuration & User Privileges"
require_root
TARGET_USER="$(get_target_user)"
# 1. AppArmor Service
log_substep "Enabling and starting AppArmor service..."
if command_exists systemctl; then
systemctl enable apparmor 2>/dev/null || true
systemctl start apparmor 2>/dev/null || true
log_success "AppArmor service enabled."
fi
# 2. zram-tools Configuration
log_substep "Configuring zram swap service..."
if command_exists systemctl; then
systemctl enable --now zramswap.service 2>/dev/null || true
log_success "zram service enabled."
fi
# 3. Docker Service & Repository
log_substep "Setting up Docker service & repository..."
apt_ensure_keyrings_dir
apt_add_keyring_from_url "https://download.docker.com/linux/debian/gpg" "docker.asc"
DEBIAN_CODENAME="trixie"
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
source /etc/os-release
DEBIAN_CODENAME="${VERSION_CODENAME:-trixie}"
# Docker uses 'bookworm' or 'trixie' upstream repo suite for Debian testing/unstable if sid is not explicitly provided
if [[ "$DEBIAN_CODENAME" == "sid" ]]; then
DEBIAN_CODENAME="trixie"
fi
fi
ARCH="$(dpkg --print-architecture)"
cat <<EOF > /etc/apt/sources.list.d/docker.sources
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $DEBIAN_CODENAME
Components: stable
Architectures: $ARCH
Signed-By: /etc/apt/keyrings/docker.asc
EOF
chmod 0644 /etc/apt/sources.list.d/docker.sources
apt_update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin 2>/dev/null || log_warn "Could not install all Docker packages."
if command_exists systemctl; then
systemctl enable --now docker.service 2>/dev/null || true
fi
# 4. Libvirt / KVM Virtualization
log_substep "Configuring Virtualization (Libvirt / KVM)..."
HAS_VIRT=$(grep -Eoc '(vmx|svm)' /proc/cpuinfo 2>/dev/null || echo 0)
if [[ "$HAS_VIRT" -gt 0 ]]; then
log_info "Hardware virtualization support detected."
if command_exists systemctl; then
systemctl enable --now libvirtd.service 2>/dev/null || true
fi
if command_exists virsh; then
virsh net-start default 2>/dev/null || true
virsh net-autostart default 2>/dev/null || true
fi
# Add target user to libvirt and kvm groups
groupadd -f libvirt
groupadd -f kvm
usermod -aG libvirt,kvm "$TARGET_USER"
log_success "Target user $TARGET_USER added to libvirt & kvm groups."
else
log_info "No hardware virtualization extensions (VT-x/AMD-V) detected in /proc/cpuinfo."
fi
# 5. Ollama AI Service & Configuration
log_substep "Configuring Ollama AI Service..."
OLLAMA_MODELS_DIR="$(prompt_ollama_models_path)"
log_info "Ollama models directory set to: $OLLAMA_MODELS_DIR"
mkdir -p "$OLLAMA_MODELS_DIR"
log_substep "Installing / Updating Ollama..."
if curl -fsSL https://ollama.com/install.sh | sh; then
log_success "Ollama installation completed."
else
log_warn "Ollama installation script returned a non-zero exit code."
fi
# Ensure permissions on models directory for ollama user
if id ollama >/dev/null 2>&1; then
chown -R ollama:ollama "$OLLAMA_MODELS_DIR" 2>/dev/null || true
chmod -R 775 "$OLLAMA_MODELS_DIR" 2>/dev/null || true
fi
# Configure systemd drop-in override for Ollama service
log_substep "Configuring systemd override for Ollama service..."
mkdir -p /etc/systemd/system/ollama.service.d
cat <<EOF > /etc/systemd/system/ollama.service.d/override.conf
[Service]
Environment="OLLAMA_MODELS=$OLLAMA_MODELS_DIR"
Environment="OLLAMA_FLASH_ATTENTION=${OLLAMA_FLASH_ATTENTION:-1}"
Environment="OLLAMA_KV_CACHE_TYPE=${OLLAMA_KV_CACHE_TYPE:-q8_0}"
Environment="OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-30m}"
EOF
chmod 0644 /etc/systemd/system/ollama.service.d/override.conf
if command_exists systemctl; then
systemctl daemon-reload 2>/dev/null || true
systemctl enable --now ollama.service 2>/dev/null || true
systemctl restart ollama.service 2>/dev/null || true
log_success "Ollama systemd service configured and enabled."
fi
# 6. Timeshift Boot Snapshot Service, APT Update Hook & GRUB Btrfs Daemon (if on Btrfs)
log_substep "Configuring Timeshift Boot Snapshot Service, APT Update Hook and GRUB Btrfs Snapshot Daemon..."
if command_exists timeshift && is_root_btrfs; then
ensure_timeshift_btrfs_config
ensure_grub_btrfs
log_success "Timeshift and GRUB Btrfs snapshot services configured and enabled."
elif is_root_btrfs; then
ensure_grub_btrfs
log_info "Timeshift will be configured when installed; grub-btrfs configured."
fi
# 7. Network Configuration & Services (Loopback, LAN, NetworkManager)
log_substep "Configuring and activating network interfaces (Loopback, all LAN interfaces, NetworkManager)..."
configure_network_all
# 8. User Group Memberships
log_substep "Updating user group memberships for $TARGET_USER..."
groupadd -f sudo
groupadd -f docker
groupadd -f netdev
groupadd -f ollama 2>/dev/null || true
usermod -aG sudo,docker,netdev "$TARGET_USER"
if getent group ollama >/dev/null 2>&1; then
usermod -aG ollama "$TARGET_USER" 2>/dev/null || true
fi
# "render" (GPU compute/Vulkan access) is created by Debian's udev sysusers
# config and is always present; "gamemode" only exists once the gamemode
# package is installed (stage 04), so it is added conditionally.
if getent group render >/dev/null 2>&1; then
usermod -aG render "$TARGET_USER" 2>/dev/null || true
fi
if getent group gamemode >/dev/null 2>&1; then
usermod -aG gamemode "$TARGET_USER" 2>/dev/null || true
fi
log_success "Target user $TARGET_USER added to sudo, docker, netdev, ollama, render and gamemode groups."
# 9. GameMode Performance Daemon & CoreCtrl Configuration
log_substep "Deploying GameMode performance configuration..."
if [[ -f "$SCRIPT_DIR/data/etc/gamemode.ini" ]]; then
backup_file_or_dir "/etc/gamemode.ini"
cp "$SCRIPT_DIR/data/etc/gamemode.ini" /etc/gamemode.ini
chmod 0644 /etc/gamemode.ini
log_success "GameMode configuration deployed to /etc/gamemode.ini."
fi
log_substep "Configuring passwordless CoreCtrl access for administrative users..."
if [[ -f "$SCRIPT_DIR/data/etc/polkit-1/rules.d/90-corectrl.rules" ]]; then
mkdir -p /etc/polkit-1/rules.d
cp "$SCRIPT_DIR/data/etc/polkit-1/rules.d/90-corectrl.rules" /etc/polkit-1/rules.d/90-corectrl.rules
chmod 0644 /etc/polkit-1/rules.d/90-corectrl.rules
log_success "CoreCtrl PolicyKit rule installed for the 'sudo' group."
fi
# 10. systemd-oomd Out-of-Memory Protection
log_substep "Enabling systemd-oomd out-of-memory protection..."
if command_exists systemctl; then
systemctl enable --now systemd-oomd.service 2>/dev/null || log_warn "Could not enable systemd-oomd.service."
log_success "systemd-oomd enabled (protects against freezes under heavy memory/swap pressure)."
fi
# 11. Sched-ext (scx) Gaming Scheduler
log_substep "Configuring sched-ext (scx) gaming scheduler..."
apt_ensure_keyrings_dir
apt_add_keyring_from_url "https://dl.xanmod.org/archive.key" "xanmod-archive-keyring.gpg" || true
if [[ -f "$SCRIPT_DIR/data/apt/sources.list.d/xanmod.sources" ]]; then
apt_install_sources_file "$SCRIPT_DIR/data/apt/sources.list.d/xanmod.sources" "xanmod.sources"
fi
apt_update
if DEBIAN_FRONTEND=noninteractive apt-get install -y scx-scheds 2>/dev/null; then
if [[ -f /etc/default/scx ]]; then
# scx_lavd (Latency-criticality Aware Virtual Deadline) is purpose-built
# for gaming/interactive desktop workloads; --autopilot lets it balance
# performance vs. powersave automatically based on system load.
sed -i 's|^SCX_SCHEDULER=.*|SCX_SCHEDULER=scx_lavd|' /etc/default/scx
grep -q '^SCX_SCHEDULER=' /etc/default/scx || echo "SCX_SCHEDULER=scx_lavd" >> /etc/default/scx
sed -i "s|^#\?SCX_FLAGS=.*|SCX_FLAGS='--autopilot'|" /etc/default/scx
grep -q '^SCX_FLAGS=' /etc/default/scx || echo "SCX_FLAGS='--autopilot'" >> /etc/default/scx
fi
if command_exists systemctl; then
systemctl daemon-reload 2>/dev/null || true
systemctl enable --now scx.service 2>/dev/null || log_warn "scx.service could not be started - a reboot into a sched_ext-capable kernel (e.g. XanMod) may be required."
fi
log_success "sched-ext gaming scheduler (scx_lavd) configured and enabled."
else
log_warn "Could not install scx-scheds. Skipping sched-ext scheduler configuration."
fi
log_success "Stage 06: System services configuration completed successfully!"
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/07-skel-and-user.sh - /etc/skel templates, Zsh setup, user environment sync & chsh
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
setup_err_trap
log_step "Running Stage 07: User Environment, Skel Templates & Shell Configuration"
require_root
TARGET_USER="$(get_target_user)"
TARGET_HOME="$(get_target_home)"
log_info "Configuring userland environment for target user: $TARGET_USER ($TARGET_HOME)"
# 1. Deploy System Profile Scripts (/etc/profile.d)
log_substep "Deploying system profile scripts to /etc/profile.d/..."
mkdir -p /etc/profile.d
if [[ -d "$SCRIPT_DIR/data/etc/profile.d" ]]; then
for profile_script in "$SCRIPT_DIR"/data/etc/profile.d/*.sh; do
[[ -f "$profile_script" ]] || continue
cp "$profile_script" /etc/profile.d/
chmod 0755 "/etc/profile.d/$(basename "$profile_script")"
log_info "Installed profile script: $(basename "$profile_script")"
done
fi
# Ensure Zsh profiles source /etc/profile
mkdir -p /etc/zsh
grep -q '^source /etc/profile' /etc/zsh/zprofile 2>/dev/null || echo 'source /etc/profile' >> /etc/zsh/zprofile
# 2. Provision /etc/skel for Future New Users
log_substep "Provisioning /etc/skel with default templates and configs..."
mkdir -p /etc/skel/Templates /etc/skel/.junie/skills
if [[ -d "$SCRIPT_DIR/data/skel/Templates" ]]; then
cp -r "$SCRIPT_DIR"/data/skel/Templates/* /etc/skel/Templates/ 2>/dev/null || true
fi
if [[ -f "$SCRIPT_DIR/data/skel/.zshrc" ]]; then
cp "$SCRIPT_DIR/data/skel/.zshrc" /etc/skel/.zshrc
fi
if [[ -d "$SCRIPT_DIR/data/skel/.config" ]]; then
mkdir -p /etc/skel/.config
cp -r "$SCRIPT_DIR"/data/skel/.config/* /etc/skel/.config/ 2>/dev/null || true
fi
# Provision Oh-My-Zsh template in /etc/skel so newly created users receive it automatically
if command_exists git; then
if [[ ! -d /etc/skel/.oh-my-zsh ]]; then
log_info "Provisioning Oh-My-Zsh template in /etc/skel/.oh-my-zsh..."
git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git /etc/skel/.oh-my-zsh 2>/dev/null || log_warn "Could not clone Oh-My-Zsh into /etc/skel."
fi
if [[ -d /etc/skel/.oh-my-zsh ]]; then
mkdir -p /etc/skel/.oh-my-zsh/custom/plugins
[[ -d /etc/skel/.oh-my-zsh/custom/plugins/zsh-autosuggestions ]] || \
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions /etc/skel/.oh-my-zsh/custom/plugins/zsh-autosuggestions 2>/dev/null || true
[[ -d /etc/skel/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting ]] || \
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting /etc/skel/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting 2>/dev/null || true
fi
fi
chown -R root:root /etc/skel
# 3. Synchronize User Environment for Target User
log_substep "Synchronizing Dotfiles & Templates into $TARGET_HOME..."
mkdir -p "$TARGET_HOME/Templates" "$TARGET_HOME/.config" "$TARGET_HOME/.junie/skills"
# Backup existing .zshrc if present
if [[ -f "$TARGET_HOME/.zshrc" ]]; then
backup_file_or_dir "$TARGET_HOME/.zshrc"
fi
if [[ -f "$SCRIPT_DIR/data/skel/.zshrc" ]]; then
cp "$SCRIPT_DIR/data/skel/.zshrc" "$TARGET_HOME/.zshrc"
fi
if [[ -d "$SCRIPT_DIR/data/skel/Templates" ]]; then
cp -r "$SCRIPT_DIR"/data/skel/Templates/* "$TARGET_HOME/Templates/" 2>/dev/null || true
fi
# Backup existing Hyprland config if present
if [[ -f "$TARGET_HOME/.config/hypr/hyprland.conf" ]]; then
backup_file_or_dir "$TARGET_HOME/.config/hypr/hyprland.conf"
fi
if [[ -d "$SCRIPT_DIR/data/skel/.config" ]]; then
cp -r "$SCRIPT_DIR"/data/skel/.config/* "$TARGET_HOME/.config/" 2>/dev/null || true
fi
# 4. Install Oh-My-Zsh for Target User (if not already installed)
if [[ ! -d "$TARGET_HOME/.oh-my-zsh" ]]; then
log_substep "Installing Oh-My-Zsh repository for $TARGET_USER..."
if [[ -d /etc/skel/.oh-my-zsh ]]; then
cp -r /etc/skel/.oh-my-zsh "$TARGET_HOME/.oh-my-zsh"
elif command_exists git; then
run_as_target_user git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git "$TARGET_HOME/.oh-my-zsh" 2>/dev/null || log_warn "Could not clone Oh-My-Zsh repository."
fi
fi
if [[ -d "$TARGET_HOME/.oh-my-zsh" ]]; then
mkdir -p "$TARGET_HOME/.oh-my-zsh/custom/plugins"
if [[ ! -d "$TARGET_HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions" ]] && command_exists git; then
run_as_target_user git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$TARGET_HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions" 2>/dev/null || true
fi
if [[ ! -d "$TARGET_HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting" ]] && command_exists git; then
run_as_target_user git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting "$TARGET_HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting" 2>/dev/null || true
fi
fi
# Fix ownership
chown -R "$TARGET_USER:$TARGET_USER" "$TARGET_HOME/.zshrc" "$TARGET_HOME/Templates" "$TARGET_HOME/.config" "$TARGET_HOME/.junie"
if [[ -d "$TARGET_HOME/.oh-my-zsh" ]]; then
chown -R "$TARGET_USER:$TARGET_USER" "$TARGET_HOME/.oh-my-zsh"
fi
# 5. Set Default Shell to Zsh using standard chsh
log_substep "Setting default shell to Zsh for $TARGET_USER..."
ZSH_BIN="$(command -v zsh || echo "/usr/bin/zsh")"
if [[ -x "$ZSH_BIN" ]]; then
# Ensure zsh is listed in /etc/shells
grep -q "^$ZSH_BIN$" /etc/shells 2>/dev/null || echo "$ZSH_BIN" >> /etc/shells
CURRENT_SHELL="$(getent passwd "$TARGET_USER" | cut -d: -f7)"
if [[ "$CURRENT_SHELL" != "$ZSH_BIN" ]]; then
chsh -s "$ZSH_BIN" "$TARGET_USER"
log_success "Default shell for $TARGET_USER set to $ZSH_BIN"
else
log_info "Default shell for $TARGET_USER is already $ZSH_BIN"
fi
# Configure default shell for newly created users
if command_exists useradd; then
useradd -D -s "$ZSH_BIN" 2>/dev/null || true
fi
if [[ -f /etc/adduser.conf ]]; then
sed -i -E 's|^#?\s*DSHELL=.*|DSHELL='"$ZSH_BIN"'|' /etc/adduser.conf 2>/dev/null || true
fi
else
log_warn "Zsh binary not found at $ZSH_BIN. Skipping chsh."
fi
log_success "Stage 07: Skel & userland configuration completed successfully!"
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/08-flatpaks.sh - Flathub repository setup & Flatpak package installation
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/apt.sh"
setup_err_trap
log_step "Running Stage 08: Flatpaks & Flathub Repository Setup"
require_root
TARGET_USER="$(get_target_user)"
# 1. Flathub Repository Setup
log_substep "Configuring Flathub remote repository..."
if command_exists flatpak; then
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo || log_warn "Could not add Flathub remote."
log_success "Flathub repository enabled."
else
log_warn "flatpak command not found. Skipping Flatpak installation."
fi
# 2. Install Flatpaks from config/packages/06-flatpaks.list
FLATPAK_LIST="$SCRIPT_DIR/config/packages/06-flatpaks.list"
if command_exists flatpak && [[ -f "$FLATPAK_LIST" ]]; then
log_substep "Installing Flatpak applications from $FLATPAK_LIST..."
while IFS= read -r app_id || [[ -n "$app_id" ]]; do
app_id="$(echo "$app_id" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
[[ -z "$app_id" || "$app_id" =~ ^# ]] && continue
log_info "Installing Flatpak: $app_id"
flatpak install -y flathub "$app_id" 2>/dev/null || log_warn "Failed to install Flatpak: $app_id"
done < "$FLATPAK_LIST"
fi
log_success "Stage 08: Flatpaks and Flathub repository setup completed successfully!"
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/09-apps.sh - Spotify, Waydroid, OpenDeck, custom desktop apps & MIME associations
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/apt.sh"
setup_err_trap
log_step "Running Stage 09: Standalone Applications, Integrations & MIME Associations"
require_root
TARGET_USER="$(get_target_user)"
# 1. Spotify Client Installation (Debian APT repo)
log_substep "Configuring Spotify repository and client..."
if apt_add_keyring_from_url "https://download.spotify.com/debian/pubkey_5384CE82BA52C83A.asc" "spotify.gpg"; then
cat <<EOF > /etc/apt/sources.list.d/spotify.sources
Types: deb
URIs: http://repository.spotify.com
Suites: stable
Components: non-free
Signed-By: /etc/apt/keyrings/spotify.gpg
EOF
chmod 0644 /etc/apt/sources.list.d/spotify.sources
apt_update
DEBIAN_FRONTEND=noninteractive apt-get install -y spotify-client 2>/dev/null || log_warn "Could not install spotify-client via APT."
fi
# 2. Deploy Custom Desktop Applications
if [[ -d "$SCRIPT_DIR/data/usr/share/applications" ]]; then
log_substep "Deploying custom desktop entries..."
mkdir -p /usr/share/applications
cp -r "$SCRIPT_DIR"/data/usr/share/applications/* /usr/share/applications/ 2>/dev/null || true
fi
# 3. Waydroid Container Setup
log_substep "Checking Waydroid installation..."
if ! command_exists waydroid; then
log_info "Installing Waydroid repository and package..."
if curl -fsSL https://repo.waydro.id | bash 2>/dev/null; then
DEBIAN_FRONTEND=noninteractive apt-get install -y waydroid 2>/dev/null || log_warn "Failed to install waydroid package."
fi
fi
if command_exists systemctl && command_exists waydroid; then
systemctl enable --now waydroid-container 2>/dev/null || true
log_success "Waydroid container service enabled."
fi
# 4. OpenDeck Installation
log_substep "Installing / Updating OpenDeck..."
if curl -sSL https://raw.githubusercontent.com/nekename/OpenDeck/main/install_opendeck.sh | bash; then
log_success "OpenDeck installation completed."
else
log_warn "OpenDeck installation script returned a non-zero exit code."
fi
# 5. Set Default Desktop MIME Types for Target User
log_substep "Setting default XDG MIME handlers for $TARGET_USER..."
run_as_target_user xdg-mime default org.gnome.Loupe.desktop image/jpeg 2>/dev/null || true
run_as_target_user xdg-mime default org.gnome.Loupe.desktop image/png 2>/dev/null || true
run_as_target_user xdg-mime default io.bassi.Amberol.desktop audio/mpeg 2>/dev/null || true
run_as_target_user xdg-mime default io.bassi.Amberol.desktop audio/x-wav 2>/dev/null || true
run_as_target_user xdg-mime default io.bassi.Amberol.desktop audio/flac 2>/dev/null || true
run_as_target_user xdg-mime default io.bassi.Amberol.desktop audio/ogg 2>/dev/null || true
run_as_target_user xdg-mime default org.gnome.TextEditor.desktop text/plain 2>/dev/null || true
run_as_target_user xdg-mime default org.gnome.TextEditor.desktop text/x-log 2>/dev/null || true
run_as_target_user xdg-mime default org.gnome.TextEditor.desktop text/markdown 2>/dev/null || true
run_as_target_user xdg-mime default eu.betterbird.Betterbird.desktop x-scheme-handler/mailto 2>/dev/null || true
log_success "Stage 09: Standalone Applications, Integrations and MIME associations completed successfully!"
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/10-hyprland.sh - LinuxBeginnings Debian-Hyprland auto-installer & desktop setup
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=lib/utils.sh
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 10: Hyprland Desktop (LinuxBeginnings Debian-Hyprland Installer)"
require_root
TARGET_USER="$(get_target_user)"
TARGET_HOME="$(get_target_home)"
log_info "Configuring Hyprland Desktop for target user: $TARGET_USER ($TARGET_HOME)"
# 1. Execute LinuxBeginnings Debian-Hyprland installer
log_substep "Downloading and executing LinuxBeginnings Debian-Hyprland installer..."
create_timeshift_snapshot "Stage 10: Pre-Hyprland desktop installation" "B"
if command_exists curl; then
log_info "Running Debian-Hyprland installer as target user '$TARGET_USER'..."
if run_as_target_user bash -c 'sh <(curl -L https://raw.githubusercontent.com/LinuxBeginnings/Debian-Hyprland/main/auto-install.sh)'; then
log_success "LinuxBeginnings Debian-Hyprland installation completed successfully."
else
log_warn "LinuxBeginnings installer exited with non-zero status. Check logs if needed."
fi
else
log_error "curl is required to download Debian-Hyprland installer."
exit 1
fi
# 2. Install first-login-setup system-wide (shared by all users, not copied
# into individual home directories) and enable its systemd --user service
# globally, exactly as 'systemctl --global enable' would apply to every user.
log_substep "Installing first-login-setup system-wide to /usr/local/lib/first-login-setup..."
if [[ -d "$SCRIPT_DIR/data/usr/local/lib/first-login-setup" ]]; then
mkdir -p /usr/local/lib/first-login-setup
cp "$SCRIPT_DIR"/data/usr/local/lib/first-login-setup/*.sh /usr/local/lib/first-login-setup/
chmod 0755 /usr/local/lib/first-login-setup/*.sh
chown -R root:root /usr/local/lib/first-login-setup
fi
if [[ -f "$SCRIPT_DIR/data/etc/systemd/user/first-login-setup.service" ]]; then
mkdir -p /etc/systemd/user
cp "$SCRIPT_DIR/data/etc/systemd/user/first-login-setup.service" /etc/systemd/user/first-login-setup.service
if command_exists systemctl; then
systemctl --global enable first-login-setup.service 2>/dev/null || log_warn "Could not globally enable first-login-setup.service via systemctl."
else
# Fallback: replicate what 'systemctl --global enable' would do.
mkdir -p /etc/systemd/user/default.target.wants
ln -sfn "../first-login-setup.service" /etc/systemd/user/default.target.wants/first-login-setup.service
fi
fi
# 3. Ensure rudimentary Hyprland config is deployed to /etc/skel
log_substep "Deploying rudimentary Hyprland configuration to /etc/skel..."
mkdir -p /etc/skel/.config/hypr
if [[ -f "$SCRIPT_DIR/data/skel/.config/hypr/hyprland.conf" ]]; then
cp "$SCRIPT_DIR/data/skel/.config/hypr/hyprland.conf" /etc/skel/.config/hypr/hyprland.conf
fi
chown -R root:root /etc/skel/.config
# 4. Deploy rudimentary Hyprland config to target user
log_substep "Deploying rudimentary Hyprland configuration to $TARGET_HOME/.config/hypr..."
mkdir -p "$TARGET_HOME/.config/hypr"
if [[ -f "$TARGET_HOME/.config/hypr/hyprland.conf" ]]; then
backup_file_or_dir "$TARGET_HOME/.config/hypr/hyprland.conf"
fi
if [[ -f "$SCRIPT_DIR/data/skel/.config/hypr/hyprland.conf" ]]; then
cp "$SCRIPT_DIR/data/skel/.config/hypr/hyprland.conf" "$TARGET_HOME/.config/hypr/hyprland.conf"
fi
chown -R "$TARGET_USER:$TARGET_USER" "$TARGET_HOME/.config/hypr"
log_success "Rudimentary Hyprland configuration deployed:"
log_info " - SUPER+ENTER: Kitty Terminal"
log_info " - SUPER+Q: Close Active Window"
log_info " - Ersteinrichtung (Dotfiles, Oh-My-Zsh, JetBrains Junie, Claude Code & Skills) startet automatisch beim"
log_info " nächsten Login jedes Benutzers über den systemweiten systemd --user Service"
log_info " 'first-login-setup.service' (unabhängig vom gewählten Compositor, NICHT über"
log_info " hyprland.conf). Läuft nur beim ersten Login bzw. nach 'Später' erneut."
log_info " Manueller Aufruf jederzeit möglich mit: /usr/local/lib/first-login-setup/first-login-setup.sh --force"
create_timeshift_snapshot "Stage 10: Post-Hyprland desktop setup" "O"
log_success "Stage 10: Hyprland Desktop installation & configuration completed successfully!"
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# ==============================================================================
# stages/11-linutil.sh - Linutil (Chris Titus Tech System Toolbox), final install step
# ==============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/config/setup.conf"
fi
setup_err_trap
log_step "Running Stage 11: Linutil (Chris Titus Tech System Toolbox)"
require_root
TARGET_USER="$(get_target_user)"
log_info "Launching Linutil as target user '$TARGET_USER'..."
create_timeshift_snapshot "Stage 11: Pre-Linutil" "B"
if command_exists curl; then
if has_tty; then
# Linutil is an interactive TUI - run it as the target user (it
# elevates via sudo itself where needed), attached to the controlling
# terminal so its menu can actually receive keystrokes.
if run_as_target_user bash -c 'sh <(curl -fsSL https://christitus.com/linux)' < /dev/tty > /dev/tty; then
log_success "Linutil finished."
else
log_warn "Linutil exited with a non-zero status. Check logs if needed."
fi
else
log_warn "No controlling terminal available - Linutil's interactive menu cannot be displayed. Skipping."
log_info "Run it manually later with: curl -fsSL https://christitus.com/linux | sh"
fi
else
log_error "curl is required to run Linutil."
exit 1
fi
create_timeshift_snapshot "Stage 11: Post-Linutil" "O"
log_success "Stage 11: Linutil completed successfully!"