Compare commits
2 Commits
2be85739b5
...
5d7c97409b
| Author | SHA1 | Date |
|---|---|---|
|
|
5d7c97409b | |
|
|
9289f01965 |
|
|
@ -84,31 +84,175 @@ Install via `tui-install.sh` at first install, or add later:
|
|||
bash ~/Dotfiles/setup/install-modules.sh
|
||||
```
|
||||
|
||||
> This table is generated from `setup/modules.conf`. Run `setup/generate-modules.sh` to regenerate.
|
||||
|
||||
### AI & Machine Learning
|
||||
|
||||
| ID | Package | Description |
|
||||
|----|---------|-------------|
|
||||
| `ollama` | ollama | Local LLM runner with REST API server |
|
||||
| `llama-cpp` | llama.cpp | Standalone inference CLI + server |
|
||||
| `open-webui` | open-webui | Browser UI for Ollama / OpenAI-compatible backends |
|
||||
| `claude` | claude (npm) | Anthropic Claude Code CLI |
|
||||
<!-- BEGIN GENERATED MODULES: ai -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `ollama` | local LLM runner and API server |
|
||||
| `llama-cpp` | standalone LLM inference CLI and server |
|
||||
| `open-webui` | browser UI for Ollama and LLM backends |
|
||||
| `claude` | Anthropic Claude Code CLI via npm |
|
||||
<!-- END GENERATED MODULES: ai -->
|
||||
|
||||
### Networking & Security
|
||||
|
||||
| ID | Packages | Description |
|
||||
|----|---------|-------------|
|
||||
| `networking-cli` | nmap · nethogs · mitmproxy · httpie | Network analysis and HTTP tooling |
|
||||
| `disk-recovery` | ddrescue · f3 | Disk imaging and flash drive testing |
|
||||
| `ssh-server` | openssh | SSH daemon with key-auth enforcement |
|
||||
| `wireshark` | wireshark-qt | Packet capture and analysis GUI |
|
||||
<!-- BEGIN GENERATED MODULES: networking -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `networking-cli` | nmap, nethogs, mitmproxy, httpie |
|
||||
| `disk-recovery` | ddrescue and f3 disk recovery tools |
|
||||
| `himalaya` | terminal email client (AUR) |
|
||||
| `mail-notmuch` | isync, msmtp, notmuch, alot mail stack |
|
||||
| `caldav-sync` | vdirsyncer and khal CalDAV calendar sync |
|
||||
| `ssh-server` | openssh with key-auth and systemd unit enabled |
|
||||
| `wireshark` | network packet analyser GUI |
|
||||
| `anti-malware` | ClamAV, rkhunter, chkrootkit |
|
||||
<!-- END GENERATED MODULES: networking -->
|
||||
|
||||
### Development
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: dev -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `gnuplot` | scientific plotting tool |
|
||||
| `blender-povray` | 3D modelling and ray-tracing (Blender + POV-Ray) |
|
||||
| `toot` | Mastodon CLI client (AUR) |
|
||||
| `db-clients` | pgcli and mycli interactive database CLIs |
|
||||
| `mysql` | MariaDB server with initial setup |
|
||||
| `productivity` | taskwarrior, watson, jrnl — task management and time tracking |
|
||||
| `python` | pyright, pipx, pynvim Python tooling |
|
||||
| `k8s` | kubectl and podman-desktop Kubernetes tools |
|
||||
| `docker` | docker and docker-compose |
|
||||
| `podman` | rootless containers with buildah |
|
||||
| `cockpit` | web UI for machines and containers |
|
||||
<!-- END GENERATED MODULES: dev -->
|
||||
|
||||
### System Utilities
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: system -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `tlp` | laptop battery optimisation |
|
||||
| `butter` | btrfs snapshot backup manager (AUR) |
|
||||
| `localsend` | LAN file transfer, AirDrop-like (AUR) |
|
||||
| `croc` | cross-platform encrypted file transfer |
|
||||
| `opendeck` | Stream Deck controller — ydotool + OpenDeck (Flatpak) |
|
||||
| `localtunnel` | expose localhost over a public URL |
|
||||
| `timeshift` | system snapshot and backup with autosnap |
|
||||
| `zfs` | zfs-dkms kernel module |
|
||||
| `wprs` | Wayland proxy for remote sessions (wprs-git, AUR) |
|
||||
| `plymouth-custom` | boot splash with a user-supplied image |
|
||||
<!-- END GENERATED MODULES: system -->
|
||||
|
||||
### Gaming
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: gaming -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `steam` | Steam gaming platform |
|
||||
| `vesktop` | Discord client with Vencord theme |
|
||||
| `spotify` | Spotify launcher with Spicetify theming |
|
||||
| `prism` | PrismLauncher Minecraft launcher (Flatpak) |
|
||||
| `vintagestory` | Vintage Story survival game (AUR) |
|
||||
| `openarena` | open-source Quake III Arena |
|
||||
| `tetris` | bastet and vitetris terminal Tetris |
|
||||
| `doom` | Chocolate Doom with Freedoom data |
|
||||
| `sauerbraten` | Sauerbraten open-source FPS (Cube 2) |
|
||||
| `stuntrally` | Stunt Rally racing game (Flatpak) |
|
||||
<!-- END GENERATED MODULES: gaming -->
|
||||
|
||||
### Notes & Office
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: notes -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `onlyoffice` | office suite — Docs, Sheets, Slides (AUR) |
|
||||
| `xournal` | note-taking and PDF annotator |
|
||||
| `rnote` | handwriting and note-taking with stylus support (Flatpak) |
|
||||
| `obsidian` | knowledge base and Markdown note-taking (Flatpak) |
|
||||
| `tangent-notes` | networked Markdown note-taking (Flatpak) |
|
||||
<!-- END GENERATED MODULES: notes -->
|
||||
|
||||
### Media
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: media -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `ffmpeg` | GStreamer codecs and ffmpegthumbnailer |
|
||||
| `sox` | command-line audio processing toolkit |
|
||||
| `imagemagick` | image manipulation suite |
|
||||
| `yt-dlp` | YouTube and media downloader |
|
||||
<!-- END GENERATED MODULES: media -->
|
||||
|
||||
### Graphic Design
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: graphics -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `gimp` | GNU Image Manipulation Program |
|
||||
| `inkscape` | vector graphics editor |
|
||||
| `krita` | digital painting and illustration |
|
||||
<!-- END GENERATED MODULES: graphics -->
|
||||
|
||||
### Video Editing
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: video -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `kdenlive` | KDE non-linear video editor |
|
||||
| `openshot` | cross-platform video editor |
|
||||
| `shotcut` | cross-platform video editor |
|
||||
<!-- END GENERATED MODULES: video -->
|
||||
|
||||
### Audio Production
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: audio -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `ardour` | professional DAW |
|
||||
| `audacity` | multi-track audio editor |
|
||||
| `lmms` | Linux MultiMedia Studio music production |
|
||||
| `mixxx` | DJ mixing software |
|
||||
| `cecilia` | audio synthesis and signal processing (AUR) |
|
||||
<!-- END GENERATED MODULES: audio -->
|
||||
|
||||
### Browsers
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: browsers -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `chromium` | open-source Chromium browser (official) |
|
||||
| `firefox-browser` | Mozilla Firefox (official) |
|
||||
| `zen-browser` | privacy-focused Firefox fork (AUR) |
|
||||
| `nyxt` | keyboard-driven hackable browser (AUR) |
|
||||
| `librewolf` | hardened Firefox fork (AUR) |
|
||||
| `min-browser` | minimal Electron browser (AUR) |
|
||||
<!-- END GENERATED MODULES: browsers -->
|
||||
|
||||
### IDEs & Editors
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: editors -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `vscodium` | telemetry-free VS Code build (AUR) |
|
||||
| `zed-ide` | high-performance Rust IDE (official) |
|
||||
| `geany` | lightweight IDE with plugins (official) |
|
||||
| `codeblocks` | C/C++ IDE (official) |
|
||||
| `kate` | KDE advanced text editor (official) |
|
||||
<!-- END GENERATED MODULES: editors -->
|
||||
|
||||
### Virtualisation & Remote Desktop
|
||||
|
||||
| ID | Packages | Description |
|
||||
|----|---------|-------------|
|
||||
| `qemu` | qemu-full · libvirt · virt-manager · virt-viewer · dnsmasq · bridge-utils · edk2-ovmf · swtpm · vde2 | Full QEMU/KVM stack with virt-manager GUI; enables libvirtd, auto-starts default NAT network, adds user to `libvirt` and `kvm` groups |
|
||||
| `rdp-client` | remmina · freerdp · libvncserver | Remmina remote desktop client with RDP (FreeRDP) and VNC support |
|
||||
| `lamco-rdp-server` | lamco-rdp-server (AUR) | Native Wayland RDP server written in Rust with H.264/VA-API encoding; runs as a systemd user service |
|
||||
<!-- BEGIN GENERATED MODULES: virt -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `rdp-client` | Remmina with FreeRDP and VNC plugins |
|
||||
| `lamco-rdp-server` | native Wayland RDP server (AUR, Rust) |
|
||||
| `qemu` | full QEMU/KVM stack with virt-manager |
|
||||
<!-- END GENERATED MODULES: virt -->
|
||||
|
||||
**lamco-rdp-server notes:**
|
||||
- Enabled as a user service: `systemctl --user enable lamco-rdp-server.service`
|
||||
|
|
@ -116,122 +260,15 @@ bash ~/Dotfiles/setup/install-modules.sh
|
|||
- Optional GUI tray: `lamco-rdp-server-gui`
|
||||
- Requires an `xdg-desktop-portal` matching your compositor (`-hyprland`, `-wlr`, `-gnome`, `-kde`)
|
||||
|
||||
### Development
|
||||
|
||||
| ID | Packages | Description |
|
||||
|----|---------|-------------|
|
||||
| `python` | pyright · pipx · pynvim | Python LSP, isolated tool runner, Neovim integration |
|
||||
| `docker` | docker · docker-compose | Container runtime |
|
||||
| `podman` | podman · buildah · podman-compose | Rootless containers |
|
||||
| `cockpit` | cockpit · machines · podman | Web-based system management UI |
|
||||
| `k8s` | kubectl · podman-desktop | Kubernetes CLI and desktop client |
|
||||
| `db-clients` | pgcli · mycli | Enhanced interactive database CLIs |
|
||||
| `mysql` | mariadb | MariaDB server with initial setup |
|
||||
|
||||
### IDEs & Editors
|
||||
|
||||
| ID | Package | Description |
|
||||
|----|---------|-------------|
|
||||
| `vscodium` | vscodium-bin (AUR) | VS Code without telemetry |
|
||||
| `zed-ide` | zed | High-performance Rust IDE |
|
||||
| `geany` | geany · geany-plugins | Lightweight IDE |
|
||||
| `codeblocks` | codeblocks | C/C++ IDE |
|
||||
| `kate` | kate | KDE advanced text editor |
|
||||
|
||||
### Browsers
|
||||
|
||||
| ID | Package | Description |
|
||||
|----|---------|-------------|
|
||||
| `chromium` | chromium | Open-source Chromium |
|
||||
| `firefox-browser` | firefox | Mozilla Firefox |
|
||||
| `zen-browser` | zen-browser-bin (AUR) | Privacy-focused Firefox fork |
|
||||
| `nyxt` | nyxt (AUR) | Keyboard-driven, hackable browser |
|
||||
| `librewolf` | librewolf-bin (AUR) | Hardened Firefox fork |
|
||||
| `min-browser` | min (AUR) | Minimal Electron browser |
|
||||
|
||||
### Gaming
|
||||
|
||||
| ID | Package | Description |
|
||||
|----|---------|-------------|
|
||||
| `steam` | steam | Steam gaming platform |
|
||||
| `vesktop` | vesktop (AUR) | Discord client with Vencord built-in |
|
||||
| `spotify` | spotify (AUR) + spicetify | Music player with CyberQueer theme |
|
||||
| `prism` | prismlauncher (Flatpak) | Minecraft launcher |
|
||||
| `vintagestory` | vintagestory (AUR) | Survival / voxel game |
|
||||
|
||||
### Media & Creative
|
||||
|
||||
| ID | Packages | Description |
|
||||
|----|---------|-------------|
|
||||
| `ffmpeg` | gst-plugin-pipewire · gst-plugins-good · ffmpegthumbnailer | GStreamer codecs + thumbnailer |
|
||||
| `sox` | sox | Command-line audio processing |
|
||||
| `imagemagick` | imagemagick | Image manipulation suite |
|
||||
| `yt-dlp` | yt-dlp | YouTube / media downloader |
|
||||
| `blender` | blender | 3D creation suite |
|
||||
| `gnuplot` | gnuplot | Scientific plotting |
|
||||
| `povray` | povray | Ray-tracing renderer |
|
||||
|
||||
#### Graphic Design
|
||||
|
||||
| ID | Package | Description |
|
||||
|----|---------|-------------|
|
||||
| `gimp` | gimp | GNU Image Manipulation Program |
|
||||
| `inkscape` | inkscape | Vector graphics editor |
|
||||
| `krita` | krita | Digital painting and illustration |
|
||||
|
||||
#### Video Editing
|
||||
|
||||
| ID | Package | Description |
|
||||
|----|---------|-------------|
|
||||
| `kdenlive` | kdenlive | KDE non-linear video editor |
|
||||
| `openshot` | openshot | Cross-platform video editor |
|
||||
| `shotcut` | shotcut | Cross-platform video editor |
|
||||
|
||||
#### Audio Production
|
||||
|
||||
| ID | Package | Description |
|
||||
|----|---------|-------------|
|
||||
| `audacity` | audacity | Multi-track audio editor |
|
||||
| `lmms` | lmms | Linux MultiMedia Studio (music production) |
|
||||
| `ardour` | ardour | Professional DAW |
|
||||
| `mixxx` | mixxx | DJ mixing software |
|
||||
| `cecilia` | cecilia (AUR) | Audio synthesis and signal processing |
|
||||
|
||||
### Productivity
|
||||
|
||||
| ID | Packages | Description |
|
||||
|----|---------|-------------|
|
||||
| `productivity` | taskwarrior · watson · jrnl | Task management, time tracking, journaling |
|
||||
| `himalaya` | himalaya (AUR) | Terminal email client |
|
||||
| `toot` | toot (AUR) | Mastodon CLI client |
|
||||
| `xournal` | xournalpp | Note-taking and PDF annotator |
|
||||
| `rnote` | Rnote (Flatpak) | Handwriting and note-taking with stylus support |
|
||||
| `obsidian` | Obsidian (Flatpak) | Knowledge base and Markdown note-taking |
|
||||
| `tangent-notes` | Tangent Notes (Flatpak) | Networked Markdown note-taking |
|
||||
|
||||
### System Utilities
|
||||
|
||||
| ID | Packages | Description |
|
||||
|----|---------|-------------|
|
||||
| `plymouth` | plymouth · librsvg | Boot splash (bundled skull logo + spinner) — same as the core component |
|
||||
| `plymouth-custom` | plymouth · librsvg or imagemagick | Boot splash with a user-supplied image; prompts for a PNG or SVG path |
|
||||
| `tlp` | tlp · tlp-rdw | Laptop battery optimisation |
|
||||
| `zfs` | zfs-dkms | ZFS kernel module |
|
||||
| `wprs` | wprs-git (AUR) | Wayland proxy for remote sessions |
|
||||
| `butter` | butter (AUR) | Btrfs snapshot backup manager |
|
||||
| `localsend` | localsend (AUR) | LAN file transfer (AirDrop-like) |
|
||||
| `croc` | croc | Cross-platform encrypted file transfer |
|
||||
| `opendeck` | ydotool (pacman) · OpenDeck (Flatpak) | Stream Deck controller; ydotoold + OpenDeck added to Hyprland autostart |
|
||||
| `localtunnel` | localtunnel (npm) | Expose localhost over a public URL |
|
||||
| `onlyoffice` | onlyoffice-bin (AUR) | Office suite (Docs, Sheets, Slides) |
|
||||
|
||||
### Identity & Infrastructure
|
||||
|
||||
<!-- BEGIN GENERATED MODULES: infra -->
|
||||
| ID | Description |
|
||||
|----|-------------|
|
||||
| `freeipa-client` | sssd + ipa-client-install + auto-enrollment (see [FreeIPA](freeipa-ansible.md)) |
|
||||
| `freeipa-server` | Interactive FreeIPA server setup + client generator |
|
||||
| `freeipa-image` | OCI / LXC / Proxmox LXC image builder + Keycloak |
|
||||
| `freeipa-client` | sssd and ipa-client-install with auto-enrollment |
|
||||
| `freeipa-server` | interactive FreeIPA server setup with client generator |
|
||||
| `freeipa-image` | OCI/LXC/Proxmox image builder with Keycloak |
|
||||
<!-- END GENERATED MODULES: infra -->
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -216,89 +216,92 @@ if [[ "$AF_RUN_TUI" == "true" ]]; then
|
|||
3>&1 1>&2 2>&3) || AF_DE="none"
|
||||
|
||||
# ── Apps ──────────────────────────────────────────────────────────────────
|
||||
# BEGIN GENERATED MODULES: module-checklist
|
||||
AF_APPS=$(dialog --backtitle "$BACKTITLE" \
|
||||
--title " Applications " \
|
||||
--checklist "Optional applications — installed after base components:" 40 76 32 \
|
||||
"ollama" "Ollama local LLM runner + API server" off \
|
||||
"llama-cpp" "llama.cpp standalone inference CLI + server" off \
|
||||
"open-webui" "Open WebUI browser UI for Ollama / LLM backends" off \
|
||||
"claude" "Claude Code Anthropic CLI via npm" off \
|
||||
"networking-cli" "Networking CLI nmap · nethogs · mitmproxy · httpie" off \
|
||||
"disk-recovery" "Disk Recovery ddrescue · f3" off \
|
||||
"himalaya" "Himalaya terminal email client (AUR)" off \
|
||||
"mail-notmuch" "Mail (notmuch) isync · msmtp · notmuch · alot stack" off \
|
||||
"caldav-sync" "CalDAV Sync vdirsyncer · khal calendar sync" off \
|
||||
"gnuplot" "Gnuplot scientific plotting" off \
|
||||
"blender-povray" "Blender + POV-Ray 3D modelling & ray-tracing" off \
|
||||
"toot" "toot Mastodon CLI client (AUR)" off \
|
||||
"db-clients" "DB Clients pgcli · mycli" off \
|
||||
"mysql" "MySQL / MariaDB mariadb server + setup" off \
|
||||
"productivity" "Productivity taskwarrior · watson · jrnl" off \
|
||||
"yt-dlp" "yt-dlp YouTube / media downloader" off \
|
||||
"sox" "SoX audio processing toolkit" off \
|
||||
"imagemagick" "ImageMagick image manipulation" off \
|
||||
"ffmpeg" "FFmpeg extras thumbnailer · GStreamer codecs" off \
|
||||
"localtunnel" "LocalTunnel expose localhost via tunnel" off \
|
||||
"butter" "butter btrfs snapshot backup (AUR)" off \
|
||||
"tlp" "TLP laptop power management" off \
|
||||
"steam" "Steam gaming platform" off \
|
||||
"vesktop" "Vesktop Discord + Vencord theme" off \
|
||||
"spotify" "Spotify launcher + Spicetify theming" off \
|
||||
"prism" "PrismLauncher Minecraft launcher (Flatpak)" off \
|
||||
"vintagestory" "Vintage Story survival game (AUR)" off \
|
||||
"openarena" "OpenArena open-source Quake III Arena" off \
|
||||
"tetris" "Tetris CLI bastet · vitetris" off \
|
||||
"doom" "Doom Chocolate Doom + Freedoom data" off \
|
||||
"sauerbraten" "Sauerbraten open-source FPS (Cube 2)" off \
|
||||
"stuntrally" "Stunt Rally rally racing game (Flatpak)" off \
|
||||
"localsend" "LocalSend LAN file transfer (AUR)" off \
|
||||
"croc" "croc cross-platform file transfer" off \
|
||||
"opendeck" "OpenDeck Stream Deck controller (Flatpak+ydotool)" off \
|
||||
"onlyoffice" "OnlyOffice office suite (AUR)" off \
|
||||
"xournal" "Xournal++ note-taking & PDF annotator" off \
|
||||
"rnote" "Rnote handwriting & note-taking (Flatpak)" off \
|
||||
"obsidian" "Obsidian knowledge base & Markdown notes (Flatpak)" off \
|
||||
"tangent-notes" "Tangent Notes networked Markdown notes (Flatpak)" off \
|
||||
"gimp" "GIMP GNU image manipulation program" off \
|
||||
"inkscape" "Inkscape vector graphics editor" off \
|
||||
"krita" "Krita digital painting application" off \
|
||||
"ardour" "Ardour professional DAW" off \
|
||||
"audacity" "Audacity multi-track audio editor" off \
|
||||
"lmms" "LMMS Linux MultiMedia Studio DAW" off \
|
||||
"mixxx" "Mixxx DJ mixing software" off \
|
||||
"cecilia" "Cecilia audio signal processing (AUR)" off \
|
||||
"kdenlive" "Kdenlive KDE non-linear video editor" off \
|
||||
"openshot" "OpenShot easy video editor" off \
|
||||
"shotcut" "Shotcut cross-platform video editor" off \
|
||||
"anti-malware" "Anti-Malware ClamAV · rkhunter · chkrootkit" off \
|
||||
"timeshift" "Timeshift system snapshot / backup + autosnap" off \
|
||||
"wireshark" "Wireshark network packet analyser (GUI)" off \
|
||||
"k8s" "Kubernetes tools kubectl · podman-desktop" off \
|
||||
"docker" "Docker docker · docker-compose" off \
|
||||
"podman" "Podman rootless containers · buildah" off \
|
||||
"cockpit" "Cockpit web UI · machines · podman" off \
|
||||
"ssh-server" "SSH server openssh · key-auth · enabled" off \
|
||||
"freeipa-client" "FreeIPA Client sssd + ipa-client-install + enrollment" off \
|
||||
"freeipa-server" "FreeIPA Server interactive server setup + client gen" off \
|
||||
"freeipa-image" "FreeIPA Image OCI/LXC/Proxmox LXC builder + Keycloak" off \
|
||||
"python" "Python tools pyright · pipx · pynvim" off \
|
||||
"zfs" "ZFS zfs-dkms kernel module" off \
|
||||
"wprs" "WPRS wprs-git (AUR)" off \
|
||||
"chromium" "Chromium open-source browser (official)" off \
|
||||
"firefox-browser" "Firefox Mozilla browser (official)" off \
|
||||
"zen-browser" "Zen Browser Firefox-based privacy browser (AUR)" off \
|
||||
"nyxt" "Nyxt keyboard-driven browser (AUR)" off \
|
||||
"librewolf" "LibreWolf hardened Firefox fork (AUR)" off \
|
||||
"min-browser" "Min minimal Electron browser (AUR)" off \
|
||||
"vscodium" "VSCodium telemetry-free VS Code (AUR)" off \
|
||||
"zed-ide" "Zed high-performance Rust IDE (official)" off \
|
||||
"geany" "Geany lightweight IDE + plugins (official)" off \
|
||||
"codeblocks" "Code::Blocks C/C++ IDE (official)" off \
|
||||
"kate" "Kate KDE advanced text editor (official)" off \
|
||||
"rdp-client" "RDP Client Remmina + FreeRDP + VNC plugins" off \
|
||||
"lamco-rdp-server" "Lamco RDP Server native Wayland RDP server (AUR, Rust)" off \
|
||||
"qemu" "QEMU/KVM full virt stack + virt-manager GUI" off \
|
||||
--checklist "Optional applications — installed after base components:" 40 76 80 \
|
||||
"ollama" "ollama local LLM runner and API server" off \
|
||||
"llama-cpp" "llama-cpp standalone LLM inference CLI and server" off \
|
||||
"open-webui" "open-webui browser UI for Ollama and LLM backends" off \
|
||||
"claude" "claude Anthropic Claude Code CLI via npm" off \
|
||||
"networking-cli" "networking-cli nmap, nethogs, mitmproxy, httpie" off \
|
||||
"disk-recovery" "disk-recovery ddrescue and f3 disk recovery tools" off \
|
||||
"himalaya" "himalaya terminal email client (AUR)" off \
|
||||
"mail-notmuch" "mail-notmuch isync, msmtp, notmuch, alot mail stack" off \
|
||||
"caldav-sync" "caldav-sync vdirsyncer and khal CalDAV calendar sync" off \
|
||||
"ssh-server" "ssh-server openssh with key-auth and systemd unit enabled" off \
|
||||
"wireshark" "wireshark network packet analyser GUI" off \
|
||||
"anti-malware" "anti-malware ClamAV, rkhunter, chkrootkit" off \
|
||||
"gnuplot" "gnuplot scientific plotting tool" off \
|
||||
"blender-povray" "blender-povray 3D modelling and ray-tracing (Blender + POV-Ray)" off \
|
||||
"toot" "toot Mastodon CLI client (AUR)" off \
|
||||
"db-clients" "db-clients pgcli and mycli interactive database CLIs" off \
|
||||
"mysql" "mysql MariaDB server with initial setup" off \
|
||||
"productivity" "productivity taskwarrior, watson, jrnl — task management and time tracking" off \
|
||||
"python" "python pyright, pipx, pynvim Python tooling" on \
|
||||
"k8s" "k8s kubectl and podman-desktop Kubernetes tools" off \
|
||||
"docker" "docker docker and docker-compose" off \
|
||||
"podman" "podman rootless containers with buildah" off \
|
||||
"cockpit" "cockpit web UI for machines and containers" off \
|
||||
"tlp" "tlp laptop battery optimisation" off \
|
||||
"butter" "butter btrfs snapshot backup manager (AUR)" off \
|
||||
"localsend" "localsend LAN file transfer, AirDrop-like (AUR)" off \
|
||||
"croc" "croc cross-platform encrypted file transfer" off \
|
||||
"opendeck" "opendeck Stream Deck controller — ydotool + OpenDeck (Flatpak)" off \
|
||||
"localtunnel" "localtunnel expose localhost over a public URL" off \
|
||||
"timeshift" "timeshift system snapshot and backup with autosnap" off \
|
||||
"zfs" "zfs zfs-dkms kernel module" off \
|
||||
"wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \
|
||||
"plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \
|
||||
"steam" "steam Steam gaming platform" off \
|
||||
"vesktop" "vesktop Discord client with Vencord theme" off \
|
||||
"spotify" "spotify Spotify launcher with Spicetify theming" off \
|
||||
"prism" "prism PrismLauncher Minecraft launcher (Flatpak)" off \
|
||||
"vintagestory" "vintagestory Vintage Story survival game (AUR)" off \
|
||||
"openarena" "openarena open-source Quake III Arena" off \
|
||||
"tetris" "tetris bastet and vitetris terminal Tetris" off \
|
||||
"doom" "doom Chocolate Doom with Freedoom data" off \
|
||||
"sauerbraten" "sauerbraten Sauerbraten open-source FPS (Cube 2)" off \
|
||||
"stuntrally" "stuntrally Stunt Rally racing game (Flatpak)" off \
|
||||
"onlyoffice" "onlyoffice office suite — Docs, Sheets, Slides (AUR)" on \
|
||||
"xournal" "xournal note-taking and PDF annotator" off \
|
||||
"rnote" "rnote handwriting and note-taking with stylus support (Flatpak)" off \
|
||||
"obsidian" "obsidian knowledge base and Markdown note-taking (Flatpak)" off \
|
||||
"tangent-notes" "tangent-notes networked Markdown note-taking (Flatpak)" off \
|
||||
"ffmpeg" "ffmpeg GStreamer codecs and ffmpegthumbnailer" off \
|
||||
"sox" "sox command-line audio processing toolkit" off \
|
||||
"imagemagick" "imagemagick image manipulation suite" off \
|
||||
"yt-dlp" "yt-dlp YouTube and media downloader" off \
|
||||
"gimp" "gimp GNU Image Manipulation Program" off \
|
||||
"inkscape" "inkscape vector graphics editor" off \
|
||||
"krita" "krita digital painting and illustration" off \
|
||||
"kdenlive" "kdenlive KDE non-linear video editor" off \
|
||||
"openshot" "openshot cross-platform video editor" off \
|
||||
"shotcut" "shotcut cross-platform video editor" off \
|
||||
"ardour" "ardour professional DAW" off \
|
||||
"audacity" "audacity multi-track audio editor" off \
|
||||
"lmms" "lmms Linux MultiMedia Studio music production" off \
|
||||
"mixxx" "mixxx DJ mixing software" off \
|
||||
"cecilia" "cecilia audio synthesis and signal processing (AUR)" off \
|
||||
"chromium" "chromium open-source Chromium browser (official)" off \
|
||||
"firefox-browser" "firefox-browser Mozilla Firefox (official)" on \
|
||||
"zen-browser" "zen-browser privacy-focused Firefox fork (AUR)" off \
|
||||
"nyxt" "nyxt keyboard-driven hackable browser (AUR)" off \
|
||||
"librewolf" "librewolf hardened Firefox fork (AUR)" off \
|
||||
"min-browser" "min-browser minimal Electron browser (AUR)" off \
|
||||
"vscodium" "vscodium telemetry-free VS Code build (AUR)" off \
|
||||
"zed-ide" "zed-ide high-performance Rust IDE (official)" off \
|
||||
"geany" "geany lightweight IDE with plugins (official)" off \
|
||||
"codeblocks" "codeblocks C/C++ IDE (official)" off \
|
||||
"kate" "kate KDE advanced text editor (official)" off \
|
||||
"rdp-client" "rdp-client Remmina with FreeRDP and VNC plugins" off \
|
||||
"lamco-rdp-server" "lamco-rdp-server native Wayland RDP server (AUR, Rust)" off \
|
||||
"qemu" "qemu full QEMU/KVM stack with virt-manager" off \
|
||||
"freeipa-client" "freeipa-client sssd and ipa-client-install with auto-enrollment" off \
|
||||
"freeipa-server" "freeipa-server interactive FreeIPA server setup with client generator" off \
|
||||
"freeipa-image" "freeipa-image OCI/LXC/Proxmox image builder with Keycloak" off \
|
||||
3>&1 1>&2 2>&3) || AF_APPS=""
|
||||
# END GENERATED MODULES: module-checklist
|
||||
|
||||
# ── Shell RC preference ───────────────────────────────────────────────────
|
||||
AF_SHELL_RC=$(dialog --backtitle "$BACKTITLE" \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,234 @@
|
|||
#!/bin/bash
|
||||
# generate-modules.sh — regenerate all sentinel regions from modules.conf
|
||||
#
|
||||
# Usage:
|
||||
# ./generate-modules.sh — apply changes in-place
|
||||
# ./generate-modules.sh --dry-run — print a unified diff, make no changes
|
||||
#
|
||||
# Sentinel format in target files:
|
||||
# bash/sh: # BEGIN GENERATED MODULES: <tag> / # END GENERATED MODULES: <tag>
|
||||
# markdown: <!-- BEGIN GENERATED MODULES: <tag> --> / <!-- END GENERATED MODULES: <tag> -->
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONF="$SCRIPT_DIR/modules.conf"
|
||||
TUI="$SCRIPT_DIR/tui-install.sh"
|
||||
AF="$SCRIPT_DIR/generate-answerfile.sh"
|
||||
DOCS="$SCRIPT_DIR/../docs/md/modules.md"
|
||||
|
||||
DRY_RUN=false
|
||||
[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=true
|
||||
|
||||
# ── Parse modules.conf ────────────────────────────────────────────────────────
|
||||
declare -a M_IDS M_CATS M_DESCS M_DEFAULTS M_EXCLUDES
|
||||
skipped=()
|
||||
|
||||
while IFS='|' read -r id cat desc def excl; do
|
||||
# Strip leading/trailing whitespace from each field
|
||||
id="${id#"${id%%[![:space:]]*}"}"; id="${id%"${id##*[![:space:]]}"}"
|
||||
[[ "$id" =~ ^# || -z "$id" ]] && continue
|
||||
M_IDS+=("$id")
|
||||
M_CATS+=("$cat")
|
||||
M_DESCS+=("$desc")
|
||||
M_DEFAULTS+=("${def:-off}")
|
||||
M_EXCLUDES+=("${excl:-}")
|
||||
done < "$CONF"
|
||||
|
||||
# Identify incomplete entries (missing category or description) — skip them.
|
||||
declare -a ACTIVE_IDS
|
||||
for i in "${!M_IDS[@]}"; do
|
||||
if [[ -z "${M_CATS[$i]}" || -z "${M_DESCS[$i]}" ]]; then
|
||||
skipped+=("${M_IDS[$i]}")
|
||||
else
|
||||
ACTIVE_IDS+=("$i")
|
||||
fi
|
||||
done
|
||||
|
||||
if (( ${#skipped[@]} > 0 )); then
|
||||
printf '[warn] skipping %d stub(s) with empty category/description:\n' "${#skipped[@]}" >&2
|
||||
printf ' %s\n' "${skipped[@]}" >&2
|
||||
fi
|
||||
|
||||
# ── Build generated sections ──────────────────────────────────────────────────
|
||||
|
||||
# -- module-counters (tui-install.sh: count_steps function body) --------------
|
||||
gen_counters=""
|
||||
for i in "${ACTIVE_IDS[@]}"; do
|
||||
id="${M_IDS[$i]}"
|
||||
gen_counters+=" [[ \"\$a\" == *\"${id}\"* ]] && TOTAL=\$(( TOTAL + 1 ))\n"
|
||||
done
|
||||
|
||||
# -- module-checklist (tui-install.sh and generate-answerfile.sh) -------------
|
||||
# Builds the full SELECTED_APPS=$(dialog ...) call including open/close.
|
||||
build_checklist_tui() {
|
||||
local out
|
||||
out=' SELECTED_APPS=$(dialog --backtitle "$BACKTITLE" \\\n'
|
||||
out+=' --title " Applications " \\\n'
|
||||
out+=' --checklist "Optional applications — installed after base components:" "$_APP_H" 76 "$_APP_LIST_H" \\\n'
|
||||
for i in "${ACTIVE_IDS[@]}"; do
|
||||
local id="${M_IDS[$i]}" desc="${M_DESCS[$i]}" def="${M_DEFAULTS[$i]}"
|
||||
local padded
|
||||
padded=$(printf '%-20s' "$id")
|
||||
out+=" \"${id}\" \"${padded} ${desc}\" ${def} \\\\\n"
|
||||
done
|
||||
out+=' 3>&1 1>&2 2>&3) || SELECTED_APPS=""\n'
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
build_checklist_af() {
|
||||
local count="${#ACTIVE_IDS[@]}"
|
||||
local out
|
||||
out=" AF_APPS=\$(dialog --backtitle \"\$BACKTITLE\" \\\\\n"
|
||||
out+=" --title \" Applications \" \\\\\n"
|
||||
out+=" --checklist \"Optional applications — installed after base components:\" 40 76 ${count} \\\\\n"
|
||||
for i in "${ACTIVE_IDS[@]}"; do
|
||||
local id="${M_IDS[$i]}" desc="${M_DESCS[$i]}" def="${M_DEFAULTS[$i]}"
|
||||
local padded
|
||||
padded=$(printf '%-20s' "$id")
|
||||
out+=" \"${id}\" \"${padded} ${desc}\" ${def} \\\\\n"
|
||||
done
|
||||
out+=' 3>&1 1>&2 2>&3) || AF_APPS=""\n'
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
gen_checklist_tui=$(build_checklist_tui)
|
||||
gen_checklist_af=$(build_checklist_af)
|
||||
|
||||
# -- module-summary (tui-install.sh: confirmation dialog) ---------------------
|
||||
gen_summary=""
|
||||
for i in "${ACTIVE_IDS[@]}"; do
|
||||
id="${M_IDS[$i]}"
|
||||
gen_summary+=" [[ \"\$SELECTED_APPS\" == *\"${id}\"* ]] && SUMMARY+=\" ✦ ${id}\\\\n\"\n"
|
||||
done
|
||||
|
||||
# -- module-conflicts (tui-install.sh: before dispatch) -----------------------
|
||||
gen_conflicts=""
|
||||
for i in "${ACTIVE_IDS[@]}"; do
|
||||
id="${M_IDS[$i]}"
|
||||
excl="${M_EXCLUDES[$i]}"
|
||||
[[ -z "$excl" ]] && continue
|
||||
IFS=',' read -ra excl_list <<< "$excl"
|
||||
for eid in "${excl_list[@]}"; do
|
||||
eid="${eid#"${eid%%[![:space:]]*}"}"; eid="${eid%"${eid##*[![:space:]]}"}"
|
||||
gen_conflicts+="if [[ \"\$SELECTED_APPS\" == *\"${id}\"* && \"\$SELECTED_APPS\" == *\"${eid}\"* ]]; then\n"
|
||||
gen_conflicts+=" warn \"${id} and ${eid} are mutually exclusive — skipping ${eid}\"\n"
|
||||
gen_conflicts+=" SELECTED_APPS=\"\${SELECTED_APPS/${eid}/}\"\n"
|
||||
gen_conflicts+="fi\n"
|
||||
done
|
||||
done
|
||||
|
||||
# -- module-dispatch (tui-install.sh: installation section) -------------------
|
||||
gen_dispatch=""
|
||||
for i in "${ACTIVE_IDS[@]}"; do
|
||||
id="${M_IDS[$i]}"
|
||||
gen_dispatch+="[[ \"\$SELECTED_APPS\" == *\"${id}\"* ]] && run_module \"${id}\" \"\$APPS/${id}.sh\"\n"
|
||||
done
|
||||
|
||||
# -- per-category doc tables (docs/md/modules.md) -----------------------------
|
||||
declare -A gen_docs_cat
|
||||
for i in "${ACTIVE_IDS[@]}"; do
|
||||
id="${M_IDS[$i]}"
|
||||
cat="${M_CATS[$i]}"
|
||||
desc="${M_DESCS[$i]}"
|
||||
gen_docs_cat[$cat]+="| \`${id}\` | ${desc} |\n"
|
||||
done
|
||||
|
||||
build_doc_table() {
|
||||
local cat="$1"
|
||||
local rows="${gen_docs_cat[$cat]:-}"
|
||||
if [[ -z "$rows" ]]; then
|
||||
printf ''
|
||||
return
|
||||
fi
|
||||
printf '| ID | Description |\n|----|-------------|\n'
|
||||
printf '%b' "$rows"
|
||||
}
|
||||
|
||||
# ── Splice helper (uses python3 for safe multiline replacement) ───────────────
|
||||
splice() {
|
||||
local file="$1" tag="$2" content="$3" style="${4:-bash}"
|
||||
local tmpfile
|
||||
tmpfile=$(mktemp)
|
||||
printf '%b' "$content" > "$tmpfile"
|
||||
|
||||
if $DRY_RUN; then
|
||||
python3 - "$file" "$tag" "$tmpfile" "$style" "dry" <<'PYEOF'
|
||||
import sys, re, difflib
|
||||
filepath, tag, tmpfile, style, _ = sys.argv[1:]
|
||||
with open(tmpfile) as f:
|
||||
new_content = f.read()
|
||||
if style == 'md':
|
||||
begin = f'<!-- BEGIN GENERATED MODULES: {tag} -->'
|
||||
end = f'<!-- END GENERATED MODULES: {tag} -->'
|
||||
else:
|
||||
begin = f'# BEGIN GENERATED MODULES: {tag}'
|
||||
end = f'# END GENERATED MODULES: {tag}'
|
||||
with open(filepath) as f:
|
||||
original = f.read()
|
||||
pattern = re.compile(re.escape(begin) + r'\n.*?' + re.escape(end), re.DOTALL)
|
||||
if not pattern.search(original):
|
||||
print(f'ERROR: sentinel not found in {filepath}: {begin}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
replacement = begin + '\n' + new_content + end
|
||||
updated = pattern.sub(lambda m: replacement, original)
|
||||
if updated == original:
|
||||
print(f' (no change) {filepath} [{tag}]', file=sys.stderr)
|
||||
sys.exit(0)
|
||||
diff = difflib.unified_diff(
|
||||
original.splitlines(keepends=True),
|
||||
updated.splitlines(keepends=True),
|
||||
fromfile=f'{filepath}',
|
||||
tofile=f'{filepath} (generated)',
|
||||
)
|
||||
sys.stdout.writelines(diff)
|
||||
PYEOF
|
||||
else
|
||||
python3 - "$file" "$tag" "$tmpfile" "$style" <<'PYEOF'
|
||||
import sys, re
|
||||
filepath, tag, tmpfile, style = sys.argv[1:]
|
||||
with open(tmpfile) as f:
|
||||
new_content = f.read()
|
||||
if style == 'md':
|
||||
begin = f'<!-- BEGIN GENERATED MODULES: {tag} -->'
|
||||
end = f'<!-- END GENERATED MODULES: {tag} -->'
|
||||
else:
|
||||
begin = f'# BEGIN GENERATED MODULES: {tag}'
|
||||
end = f'# END GENERATED MODULES: {tag}'
|
||||
with open(filepath) as f:
|
||||
original = f.read()
|
||||
pattern = re.compile(re.escape(begin) + r'\n.*?' + re.escape(end), re.DOTALL)
|
||||
if not pattern.search(original):
|
||||
print(f'ERROR: sentinel not found in {filepath}: {begin}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
replacement = begin + '\n' + new_content + end
|
||||
updated = pattern.sub(lambda m: replacement, original)
|
||||
if updated == original:
|
||||
print(f' (no change) {filepath} [{tag}]', file=sys.stderr)
|
||||
sys.exit(0)
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(updated)
|
||||
print(f' (updated) {filepath} [{tag}]', file=sys.stderr)
|
||||
PYEOF
|
||||
fi
|
||||
rm -f "$tmpfile"
|
||||
}
|
||||
|
||||
# ── Apply all regions ─────────────────────────────────────────────────────────
|
||||
echo "==> tui-install.sh"
|
||||
splice "$TUI" "module-counters" "$gen_counters"
|
||||
splice "$TUI" "module-checklist" "$gen_checklist_tui"
|
||||
splice "$TUI" "module-summary" "$gen_summary"
|
||||
splice "$TUI" "module-conflicts" "$gen_conflicts"
|
||||
splice "$TUI" "module-dispatch" "$gen_dispatch"
|
||||
|
||||
echo "==> generate-answerfile.sh"
|
||||
splice "$AF" "module-checklist" "$gen_checklist_af"
|
||||
|
||||
echo "==> docs/md/modules.md"
|
||||
for cat in ai networking dev system gaming notes media graphics video audio browsers editors virt productivity infra; do
|
||||
table=$(build_doc_table "$cat")
|
||||
[[ -z "$table" ]] && continue
|
||||
splice "$DOCS" "$cat" "${table}"$'\n' md
|
||||
done
|
||||
|
||||
echo "Done."
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
# modules.conf — optional app module registry
|
||||
# Format: id|category|description|default|excludes
|
||||
# Run setup/sync-modules.sh to add stubs for newly created app scripts.
|
||||
# Run setup/generate-modules.sh to regenerate installer + docs from this file.
|
||||
#
|
||||
# Categories:
|
||||
# ai networking dev system gaming notes media graphics video audio
|
||||
# browsers editors virt productivity infra
|
||||
#
|
||||
# default: on / off (pre-ticked in TUI and answerfile checklists)
|
||||
# excludes: comma-separated IDs that must not run alongside this one
|
||||
|
||||
# ── AI & Machine Learning ─────────────────────────────────────────────────────
|
||||
ollama|ai|local LLM runner and API server|off|
|
||||
llama-cpp|ai|standalone LLM inference CLI and server|off|
|
||||
open-webui|ai|browser UI for Ollama and LLM backends|off|
|
||||
claude|ai|Anthropic Claude Code CLI via npm|off|
|
||||
|
||||
# ── Networking & Security ─────────────────────────────────────────────────────
|
||||
networking-cli|networking|nmap, nethogs, mitmproxy, httpie|off|
|
||||
disk-recovery|networking|ddrescue and f3 disk recovery tools|off|
|
||||
himalaya|networking|terminal email client (AUR)|off|
|
||||
mail-notmuch|networking|isync, msmtp, notmuch, alot mail stack|off|
|
||||
caldav-sync|networking|vdirsyncer and khal CalDAV calendar sync|off|
|
||||
ssh-server|networking|openssh with key-auth and systemd unit enabled|off|
|
||||
wireshark|networking|network packet analyser GUI|off|
|
||||
anti-malware|networking|ClamAV, rkhunter, chkrootkit|off|
|
||||
|
||||
# ── Development ───────────────────────────────────────────────────────────────
|
||||
gnuplot|dev|scientific plotting tool|off|
|
||||
blender-povray|dev|3D modelling and ray-tracing (Blender + POV-Ray)|off|
|
||||
toot|dev|Mastodon CLI client (AUR)|off|
|
||||
db-clients|dev|pgcli and mycli interactive database CLIs|off|
|
||||
mysql|dev|MariaDB server with initial setup|off|
|
||||
productivity|dev|taskwarrior, watson, jrnl — task management and time tracking|off|
|
||||
python|dev|pyright, pipx, pynvim Python tooling|on|
|
||||
k8s|dev|kubectl and podman-desktop Kubernetes tools|off|
|
||||
docker|dev|docker and docker-compose|off|
|
||||
podman|dev|rootless containers with buildah|off|
|
||||
cockpit|dev|web UI for machines and containers|off|
|
||||
|
||||
# ── System Utilities ──────────────────────────────────────────────────────────
|
||||
tlp|system|laptop battery optimisation|off|
|
||||
butter|system|btrfs snapshot backup manager (AUR)|off|
|
||||
localsend|system|LAN file transfer, AirDrop-like (AUR)|off|
|
||||
croc|system|cross-platform encrypted file transfer|off|
|
||||
opendeck|system|Stream Deck controller — ydotool + OpenDeck (Flatpak)|off|
|
||||
localtunnel|system|expose localhost over a public URL|off|
|
||||
timeshift|system|system snapshot and backup with autosnap|off|
|
||||
zfs|system|zfs-dkms kernel module|off|
|
||||
wprs|system|Wayland proxy for remote sessions (wprs-git, AUR)|off|
|
||||
plymouth-custom|system|boot splash with a user-supplied image|off|plymouth
|
||||
|
||||
# ── Gaming ────────────────────────────────────────────────────────────────────
|
||||
steam|gaming|Steam gaming platform|off|
|
||||
vesktop|gaming|Discord client with Vencord theme|off|
|
||||
spotify|gaming|Spotify launcher with Spicetify theming|off|
|
||||
prism|gaming|PrismLauncher Minecraft launcher (Flatpak)|off|
|
||||
vintagestory|gaming|Vintage Story survival game (AUR)|off|
|
||||
openarena|gaming|open-source Quake III Arena|off|
|
||||
tetris|gaming|bastet and vitetris terminal Tetris|off|
|
||||
doom|gaming|Chocolate Doom with Freedoom data|off|
|
||||
sauerbraten|gaming|Sauerbraten open-source FPS (Cube 2)|off|
|
||||
stuntrally|gaming|Stunt Rally racing game (Flatpak)|off|
|
||||
|
||||
# ── Notes & Office ────────────────────────────────────────────────────────────
|
||||
onlyoffice|notes|office suite — Docs, Sheets, Slides (AUR)|on|
|
||||
xournal|notes|note-taking and PDF annotator|off|
|
||||
rnote|notes|handwriting and note-taking with stylus support (Flatpak)|off|
|
||||
obsidian|notes|knowledge base and Markdown note-taking (Flatpak)|off|
|
||||
tangent-notes|notes|networked Markdown note-taking (Flatpak)|off|
|
||||
|
||||
# ── Media & Creative ──────────────────────────────────────────────────────────
|
||||
ffmpeg|media|GStreamer codecs and ffmpegthumbnailer|off|
|
||||
sox|media|command-line audio processing toolkit|off|
|
||||
imagemagick|media|image manipulation suite|off|
|
||||
yt-dlp|media|YouTube and media downloader|off|
|
||||
|
||||
# ── Graphic Design ────────────────────────────────────────────────────────────
|
||||
gimp|graphics|GNU Image Manipulation Program|off|
|
||||
inkscape|graphics|vector graphics editor|off|
|
||||
krita|graphics|digital painting and illustration|off|
|
||||
|
||||
# ── Video Editing ─────────────────────────────────────────────────────────────
|
||||
kdenlive|video|KDE non-linear video editor|off|
|
||||
openshot|video|cross-platform video editor|off|
|
||||
shotcut|video|cross-platform video editor|off|
|
||||
|
||||
# ── Audio Production ──────────────────────────────────────────────────────────
|
||||
ardour|audio|professional DAW|off|
|
||||
audacity|audio|multi-track audio editor|off|
|
||||
lmms|audio|Linux MultiMedia Studio music production|off|
|
||||
mixxx|audio|DJ mixing software|off|
|
||||
cecilia|audio|audio synthesis and signal processing (AUR)|off|
|
||||
|
||||
# ── Browsers ─────────────────────────────────────────────────────────────────
|
||||
chromium|browsers|open-source Chromium browser (official)|off|
|
||||
firefox-browser|browsers|Mozilla Firefox (official)|on|
|
||||
zen-browser|browsers|privacy-focused Firefox fork (AUR)|off|
|
||||
nyxt|browsers|keyboard-driven hackable browser (AUR)|off|
|
||||
librewolf|browsers|hardened Firefox fork (AUR)|off|
|
||||
min-browser|browsers|minimal Electron browser (AUR)|off|
|
||||
|
||||
# ── IDEs & Editors ────────────────────────────────────────────────────────────
|
||||
vscodium|editors|telemetry-free VS Code build (AUR)|off|
|
||||
zed-ide|editors|high-performance Rust IDE (official)|off|
|
||||
geany|editors|lightweight IDE with plugins (official)|off|
|
||||
codeblocks|editors|C/C++ IDE (official)|off|
|
||||
kate|editors|KDE advanced text editor (official)|off|
|
||||
|
||||
# ── Virtualisation & Remote Desktop ───────────────────────────────────────────
|
||||
rdp-client|virt|Remmina with FreeRDP and VNC plugins|off|
|
||||
lamco-rdp-server|virt|native Wayland RDP server (AUR, Rust)|off|
|
||||
qemu|virt|full QEMU/KVM stack with virt-manager|off|
|
||||
|
||||
# ── Identity & Infrastructure ─────────────────────────────────────────────────
|
||||
freeipa-client|infra|sssd and ipa-client-install with auto-enrollment|off|
|
||||
freeipa-server|infra|interactive FreeIPA server setup with client generator|off|
|
||||
freeipa-image|infra|OCI/LXC/Proxmox image builder with Keycloak|off|
|
||||
|
|
@ -5,41 +5,40 @@
|
|||
# leaving the group removes it on the next run (every 30 min via systemd timer).
|
||||
#
|
||||
# Host-group naming conventions (device policies — applied to the whole machine):
|
||||
# policy-daemon-enable-<unit> Ensure <unit> is enabled and running (systemctl enable --now).
|
||||
# Leaving the group reverts: service is disabled and stopped.
|
||||
# policy-daemon-disable-<unit> Ensure <unit> is disabled and stopped (systemctl disable --now).
|
||||
# Leaving the group reverts: service is re-enabled and started.
|
||||
# <unit> may omit the .service suffix; all systemd unit types work.
|
||||
# If a unit appears in both enable and disable groups it is skipped.
|
||||
# policy-timeshift-backup Enforce a daily Timeshift snapshot (requires timeshift installed)
|
||||
# policy-security-scan Enforce daily ClamAV + rkhunter + chkrootkit scans
|
||||
# policy-scan-notify (see User-group section below — treated as a user group)
|
||||
# no_local_users Lock passwords for root and all local users (UID >= 1000) so
|
||||
# that only FreeIPA domain accounts with centrally-managed sudo
|
||||
# rules can authenticate and gain elevated privileges.
|
||||
# Leaving the group reverts: every account locked by this policy
|
||||
# is unlocked on the next run.
|
||||
# local_sudo_<username> Grant <username> full sudo on this specific device by adding
|
||||
# them to the local sudoers drop-in. Leaving the group removes
|
||||
# the drop-in on the next run.
|
||||
# dev_daemon-enable-<unit> Ensure <unit> is enabled and running (systemctl enable --now).
|
||||
# Leaving the group reverts: service is disabled and stopped.
|
||||
# dev_daemon-disable-<unit> Ensure <unit> is disabled and stopped (systemctl disable --now).
|
||||
# Leaving the group reverts: service is re-enabled and started.
|
||||
# <unit> may omit the .service suffix; all systemd unit types work.
|
||||
# If a unit appears in both enable and disable groups it is skipped.
|
||||
# dev_timeshift-backup Enforce a daily Timeshift snapshot (requires timeshift installed)
|
||||
# dev_security-scan Enforce daily ClamAV + rkhunter + chkrootkit scans
|
||||
# dev_no-local-users Lock passwords for root and all local users (UID >= 1000) so
|
||||
# that only FreeIPA domain accounts with centrally-managed sudo
|
||||
# rules can authenticate and gain elevated privileges.
|
||||
# Leaving the group reverts: every account locked by this policy
|
||||
# is unlocked on the next run.
|
||||
# dev_local-sudo-<username> Grant <username> full sudo on this specific device by adding
|
||||
# them to the local sudoers drop-in. Leaving the group removes
|
||||
# the drop-in on the next run.
|
||||
#
|
||||
# User-group naming conventions (per-user policies — follow the user across devices):
|
||||
# policy-block-binary-<name> Prevent members of this FreeIPA user group from running <name>
|
||||
# on any enrolled host. Use __ in place of . to support Flatpak
|
||||
# app IDs (e.g. policy-block-binary-org__gimp__Gimp blocks the
|
||||
# Flatpak org.gimp.Gimp). Enforced via a PATH-priority wrapper
|
||||
# that checks group membership at runtime via SSSD/id(1).
|
||||
# Removing the user group from FreeIPA reverts the wrapper.
|
||||
# policy-scan-notify Members receive scan alert notifications on every enrolled device
|
||||
# they log into. The fetch-alerts timer is installed fleet-wide
|
||||
# when the group exists; the notification daemon starts on login
|
||||
# only for group members (checked via id(1) / SSSD).
|
||||
# Deleting the IPA user group removes the timer and profile.d
|
||||
# snippet on the next enforcer run.
|
||||
# usr_block-binary-<name> Prevent members of this FreeIPA user group from running <name>
|
||||
# on any enrolled host. Use __ in place of . to support Flatpak
|
||||
# app IDs (e.g. usr_block-binary-org__gimp__Gimp blocks the
|
||||
# Flatpak org.gimp.Gimp). Enforced via a PATH-priority wrapper
|
||||
# that checks group membership at runtime via SSSD/id(1).
|
||||
# Removing the user group from FreeIPA reverts the wrapper.
|
||||
# usr_scan-notify Members receive scan alert notifications on every enrolled device
|
||||
# they log into. The fetch-alerts timer is installed fleet-wide
|
||||
# when the group exists; the notification daemon starts on login
|
||||
# only for group members (checked via id(1) / SSSD).
|
||||
# Deleting the IPA user group removes the timer and profile.d
|
||||
# snippet on the next enforcer run.
|
||||
#
|
||||
# Notes:
|
||||
# - Install scan tools first: add the host to ansipa-module-anti-malware.
|
||||
# - Configure Timeshift (type + target device) before enabling policy-timeshift-backup.
|
||||
# - Install scan tools first: add the host to dev_mod_anti-malware.
|
||||
# - Configure Timeshift (type + target device) before enabling dev_timeshift-backup.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
|
@ -79,40 +78,40 @@ if [[ -n "$RAW_GROUPS" ]]; then
|
|||
for g in "${GRP_ARRAY[@]}"; do
|
||||
g="${g// /}"
|
||||
case "$g" in
|
||||
policy-daemon-enable-*) ACTIVE_DAEMON_ENABLE+=("${g#policy-daemon-enable-}") ;;
|
||||
policy-daemon-disable-*) ACTIVE_DAEMON_DISABLE+=("${g#policy-daemon-disable-}") ;;
|
||||
policy-timeshift-backup) WANT_TIMESHIFT_BACKUP=true ;;
|
||||
policy-security-scan) WANT_SECURITY_SCAN=true ;;
|
||||
no_local_users) WANT_NO_LOCAL_USERS=true ;;
|
||||
local_sudo_*) ACTIVE_LOCAL_SUDO_USERS+=("${g#local_sudo_}") ;;
|
||||
dev_daemon-enable-*) ACTIVE_DAEMON_ENABLE+=("${g#dev_daemon-enable-}") ;;
|
||||
dev_daemon-disable-*) ACTIVE_DAEMON_DISABLE+=("${g#dev_daemon-disable-}") ;;
|
||||
dev_timeshift-backup) WANT_TIMESHIFT_BACKUP=true ;;
|
||||
dev_security-scan) WANT_SECURITY_SCAN=true ;;
|
||||
dev_no-local-users) WANT_NO_LOCAL_USERS=true ;;
|
||||
dev_local-sudo-*) ACTIVE_LOCAL_SUDO_USERS+=("${g#dev_local-sudo-}") ;;
|
||||
esac
|
||||
done
|
||||
done <<< "$RAW_GROUPS"
|
||||
fi
|
||||
|
||||
# ── Fetch user-group-based binary block policies from FreeIPA ─────────────────
|
||||
# policy-block-binary-<name> groups are FreeIPA *user* groups — membership follows
|
||||
# usr_block-binary-<name> groups are FreeIPA *user* groups — membership follows
|
||||
# the user to every enrolled host rather than being tied to a device.
|
||||
ACTIVE_BLOCK_BINARIES=()
|
||||
ACTIVE_BLOCK_IPA_GROUPS=()
|
||||
|
||||
_BLOCK_LIST=$(ipa group-find --pkey-only 2>/dev/null \
|
||||
| awk '/Group name:/ {print $NF}' \
|
||||
| grep "^policy-block-binary-" | sort -u || true)
|
||||
| grep "^usr_block-binary-" | sort -u || true)
|
||||
|
||||
while IFS= read -r _grp; do
|
||||
[[ -z "$_grp" ]] && continue
|
||||
_raw="${_grp#policy-block-binary-}"
|
||||
_raw="${_grp#usr_block-binary-}"
|
||||
ACTIVE_BLOCK_BINARIES+=("${_raw//__/.}")
|
||||
ACTIVE_BLOCK_IPA_GROUPS+=("$_grp")
|
||||
done <<< "$_BLOCK_LIST"
|
||||
unset _BLOCK_LIST _grp _raw
|
||||
|
||||
# ── Fetch user-group-based scan-notify policy from FreeIPA ────────────────────
|
||||
# policy-scan-notify is a FreeIPA *user* group — membership follows the user to
|
||||
# usr_scan-notify is a FreeIPA *user* group — membership follows the user to
|
||||
# every enrolled host. Install the fetch-alerts timer on any device where the
|
||||
# group exists; the profile.d snippet gates daemon start on runtime membership.
|
||||
if ipa group-show policy-scan-notify >/dev/null 2>&1; then
|
||||
if ipa group-show usr_scan-notify >/dev/null 2>&1; then
|
||||
WANT_SCAN_NOTIFY=true
|
||||
fi
|
||||
|
||||
|
|
@ -134,7 +133,7 @@ _in_block_list() {
|
|||
|
||||
# ── Binary blocking (user-based) ──────────────────────────────────────────────
|
||||
# A PATH-priority wrapper is installed in /usr/local/bin/ for every binary named
|
||||
# by a policy-block-binary-* FreeIPA *user* group. The wrapper checks the
|
||||
# by a usr_block-binary-* FreeIPA *user* group. The wrapper checks the
|
||||
# caller's group membership at runtime (via id + SSSD) and only blocks members;
|
||||
# non-members are transparently passed through to the real binary.
|
||||
# __ in the group suffix decodes to . so Flatpak app IDs are fully supported.
|
||||
|
|
@ -195,11 +194,11 @@ TIMESHIFT_CRON="$CRON_DIR/ansipa-timeshift-backup"
|
|||
if [[ "$WANT_TIMESHIFT_BACKUP" == true ]]; then
|
||||
if [[ ! -f "$TIMESHIFT_CRON" ]]; then
|
||||
if ! command -v timeshift &>/dev/null; then
|
||||
warn "timeshift not found — add host to ansipa-module-timeshift first. Cron will be installed anyway."
|
||||
warn "timeshift not found — add host to dev_mod_timeshift first. Cron will be installed anyway."
|
||||
fi
|
||||
log "Enabling daily Timeshift backups"
|
||||
cat > "$TIMESHIFT_CRON" <<'CRON'
|
||||
# ansipa-policy-timeshift-backup: managed by ansipa-enforce-policies — do not edit manually.
|
||||
# ansipa-dev_timeshift-backup: managed by ansipa-enforce-policies — do not edit manually.
|
||||
# Timeshift must be configured on this host (type + target device) before snapshots work.
|
||||
0 3 * * * root /usr/bin/timeshift --create --comments "ansipa-daily" --tags D 2>&1 | logger -t timeshift-backup
|
||||
CRON
|
||||
|
|
@ -208,7 +207,7 @@ CRON
|
|||
else
|
||||
if [[ -f "$TIMESHIFT_CRON" ]]; then
|
||||
rm -f "$TIMESHIFT_CRON"
|
||||
log "Removed Timeshift backup cron (host left policy-timeshift-backup group)"
|
||||
log "Removed Timeshift backup cron (host left dev_timeshift-backup group)"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
@ -263,8 +262,8 @@ SCAN
|
|||
if [[ ! -f "$SCAN_CRON" ]]; then
|
||||
log "Enabling daily security scans (ClamAV / rkhunter / chkrootkit)"
|
||||
cat > "$SCAN_CRON" <<'CRON'
|
||||
# ansipa-policy-security-scan: managed by ansipa-enforce-policies — do not edit manually.
|
||||
# Install scan tools by adding the host to the ansipa-module-anti-malware group.
|
||||
# ansipa-dev_security-scan: managed by ansipa-enforce-policies — do not edit manually.
|
||||
# Install scan tools by adding the host to the dev_mod_anti-malware group.
|
||||
0 2 * * * root /usr/local/bin/ansipa-security-scan.sh
|
||||
CRON
|
||||
chmod 644 "$SCAN_CRON"
|
||||
|
|
@ -273,12 +272,12 @@ else
|
|||
if [[ -f "$SCAN_CRON" ]]; then
|
||||
rm -f "$SCAN_CRON"
|
||||
rm -f "$SCAN_SCRIPT"
|
||||
log "Removed security scan policy (host left policy-security-scan group)"
|
||||
log "Removed security scan policy (host left dev_security-scan group)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Scan notification daemon ──────────────────────────────────────────────────
|
||||
# policy-scan-notify is a FreeIPA *user* group (not a host group). The fetch-
|
||||
# usr_scan-notify is a FreeIPA *user* group (not a host group). The fetch-
|
||||
# alerts timer runs fleet-wide on any host where the group exists; the profile.d
|
||||
# snippet starts the notification daemon on login only for group members
|
||||
# (checked via id(1) / SSSD so no IPA query is needed at login time).
|
||||
|
|
@ -335,11 +334,11 @@ UNIT
|
|||
log "Installing /etc/profile.d/ansipa-notify.sh"
|
||||
cat > "$NOTIFY_PROFILED" <<'PROFILED'
|
||||
# ansipa-notify: launch the scan alert notification daemon on login for
|
||||
# members of the policy-scan-notify FreeIPA user group.
|
||||
# members of the usr_scan-notify FreeIPA user group.
|
||||
# Managed by ansipa-enforce-policies — do not edit manually.
|
||||
_NOTIFY_DAEMON=/usr/local/bin/ansipa-scan-notify.sh
|
||||
if [[ -x "$_NOTIFY_DAEMON" ]] && \
|
||||
id -nG 2>/dev/null | grep -qw "policy-scan-notify" && \
|
||||
id -nG 2>/dev/null | grep -qw "usr_scan-notify" && \
|
||||
! pgrep -u "$(id -u)" -f "ansipa-scan-notify" >/dev/null 2>&1; then
|
||||
"$_NOTIFY_DAEMON" &
|
||||
disown
|
||||
|
|
@ -353,7 +352,7 @@ else
|
|||
systemctl disable --now ansipa-fetch-alerts.timer 2>/dev/null || true
|
||||
rm -f "$FETCH_SVC" "$FETCH_TIMER"
|
||||
systemctl daemon-reload
|
||||
log "Removed ansipa-fetch-alerts timer (policy-scan-notify user group no longer exists)"
|
||||
log "Removed ansipa-fetch-alerts timer (usr_scan-notify user group no longer exists)"
|
||||
fi
|
||||
if [[ -f "$NOTIFY_PROFILED" ]]; then
|
||||
rm -f "$NOTIFY_PROFILED"
|
||||
|
|
@ -362,9 +361,9 @@ else
|
|||
fi
|
||||
|
||||
# ── Daemon enable / disable ───────────────────────────────────────────────────
|
||||
# policy-daemon-enable-<unit>: ensure the unit is enabled and running.
|
||||
# dev_daemon-enable-<unit>: ensure the unit is enabled and running.
|
||||
# Leaving the group reverts: unit is disabled and stopped.
|
||||
# policy-daemon-disable-<unit>: ensure the unit is disabled and stopped.
|
||||
# dev_daemon-disable-<unit>: ensure the unit is disabled and stopped.
|
||||
# Leaving the group reverts: unit is re-enabled and started.
|
||||
# <unit> may omit the .service suffix; systemd accepts both forms.
|
||||
# Conflicts (unit in both lists): logged as a warning, unit is left untouched.
|
||||
|
|
@ -448,7 +447,7 @@ else
|
|||
fi
|
||||
|
||||
# ── Per-device local sudo grants ──────────────────────────────────────────────
|
||||
# local_sudo_<username>: write a sudoers drop-in granting <username> full sudo on
|
||||
# dev_local-sudo-<username>: write a sudoers drop-in granting <username> full sudo on
|
||||
# this specific device. The drop-in is removed when the host leaves the group.
|
||||
|
||||
LOCAL_SUDO_DIR="/etc/sudoers.d"
|
||||
|
|
@ -465,7 +464,7 @@ for _USER in "${ACTIVE_LOCAL_SUDO_USERS[@]}"; do
|
|||
grep -qxF "$_USER" "$LOCAL_SUDO_STATE" 2>/dev/null || echo "$_USER" >> "$LOCAL_SUDO_STATE"
|
||||
done
|
||||
|
||||
# Revoke sudo for users no longer in any active local_sudo_* group.
|
||||
# Revoke sudo for users no longer in any active dev_local-sudo-* group.
|
||||
while IFS= read -r _OLD_USER; do
|
||||
[[ -z "$_OLD_USER" ]] && continue
|
||||
_still_active=false
|
||||
|
|
@ -476,7 +475,7 @@ while IFS= read -r _OLD_USER; do
|
|||
_DROPIN="$LOCAL_SUDO_DIR/ansipa-local-sudo-${_OLD_USER}"
|
||||
if [[ -f "$_DROPIN" ]]; then
|
||||
rm -f "$_DROPIN"
|
||||
log "Revoked local sudo for $_OLD_USER (host left local_sudo_$_OLD_USER group)"
|
||||
log "Revoked local sudo for $_OLD_USER (host left dev_local-sudo-$_OLD_USER group)"
|
||||
fi
|
||||
fi
|
||||
done < "$LOCAL_SUDO_STATE"
|
||||
|
|
@ -490,7 +489,7 @@ fi
|
|||
unset _USER _DROPIN _OLD_USER _still_active _U
|
||||
|
||||
# ── No-local-users policy ──────────────────────────────────────────────────────
|
||||
# no_local_users: lock the passwords of root and all local users (UID >= 1000)
|
||||
# dev_no-local-users: lock the passwords of root and all local users (UID >= 1000)
|
||||
# so that only FreeIPA domain accounts with centrally-managed sudo rules can
|
||||
# authenticate and gain elevated privileges.
|
||||
# Leaving the group reverts: every account locked by this policy is unlocked.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# ansipa-fetch-alerts.sh — fetch security alerts from the server SMB share.
|
||||
# Runs as root every 10 minutes via ansipa-fetch-alerts.timer (policy-scan-notify).
|
||||
# Runs as root every 10 minutes via ansipa-fetch-alerts.timer (usr_scan-notify).
|
||||
#
|
||||
# For each alert on the server that hasn't been acknowledged yet:
|
||||
# - Downloads it to ~/administration/<hostname>/ for every active login session.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[Unit]
|
||||
Description=Install Flatpaks based on FreeIPA fp_install_* groups
|
||||
Description=Install Flatpaks based on FreeIPA dev_fp_* groups
|
||||
After=network-online.target sssd.service
|
||||
Wants=network-online.target
|
||||
|
||||
|
|
|
|||
|
|
@ -2,18 +2,18 @@
|
|||
# ansipa-install-flatpaks.sh — install Flatpak apps based on FreeIPA group membership.
|
||||
#
|
||||
# IPA group naming convention (dots encoded as double underscores):
|
||||
# fp_install_org__mozilla__firefox → installs org.mozilla.firefox
|
||||
# fp_install_com__spotify__Client → installs com.spotify.Client
|
||||
# fp_install_io__missioncenter__MissionCenter → installs io.missioncenter.MissionCenter
|
||||
# dev_fp_org__mozilla__firefox → installs org.mozilla.firefox
|
||||
# dev_fp_com__spotify__Client → installs com.spotify.Client
|
||||
# dev_fp_io__missioncenter__MissionCenter → installs io.missioncenter.MissionCenter
|
||||
#
|
||||
# Decoding: strip "fp_install_" prefix, then replace every __ with a dot.
|
||||
# Decoding: strip "dev_fp_" prefix, then replace every __ with a dot.
|
||||
# Single underscores in Flatpak IDs are preserved as-is.
|
||||
#
|
||||
# Scope: system-wide (--system), runs as root via systemd service.
|
||||
|
||||
set -e
|
||||
|
||||
PREFIX="fp_install_"
|
||||
PREFIX="dev_fp_"
|
||||
|
||||
# ── Preflight ─────────────────────────────────────────────────────────────────
|
||||
if ! command -v flatpak &>/dev/null; then
|
||||
|
|
@ -35,7 +35,7 @@ if ! flatpak remote-list --system | awk '{print $1}' | grep -qx "flathub"; then
|
|||
https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
fi
|
||||
|
||||
# ── Discover IPA groups matching fp_install_* ─────────────────────────────────
|
||||
# ── Discover IPA groups matching dev_fp_* ────────────────────────────────────
|
||||
# ipa group-find --pkey-only outputs one group name per line (possibly indented).
|
||||
# $NF captures the name regardless of leading label text.
|
||||
IPA_GROUPS=$(ipa group-find --pkey-only 2>/dev/null \
|
||||
|
|
@ -49,7 +49,7 @@ if [[ -z "$IPA_GROUPS" ]]; then
|
|||
fi
|
||||
|
||||
# ── Decode group names → Flatpak application IDs ─────────────────────────────
|
||||
# 1. Strip the fp_install_ prefix
|
||||
# 1. Strip the dev_fp_ prefix
|
||||
# 2. Replace every __ with a literal dot
|
||||
DESIRED_FLATPAKS=()
|
||||
while IFS= read -r G; do
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[Unit]
|
||||
Description=Apply setup modules based on FreeIPA ansipa-module-* host groups
|
||||
Description=Apply setup modules based on FreeIPA dev_mod_* host groups
|
||||
After=network-online.target sssd.service
|
||||
Wants=network-online.target
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@
|
|||
# FreeIPA host group membership.
|
||||
#
|
||||
# Host groups follow the naming convention:
|
||||
# ansipa-module-<name> e.g. ansipa-module-docker, ansipa-module-ollama
|
||||
# dev_mod_<name> e.g. dev_mod_docker, dev_mod_ollama
|
||||
#
|
||||
# When this host is a member of such a group, the corresponding module
|
||||
# script in /usr/local/lib/ansipa-modules/<name>.sh is executed (once,
|
||||
# stamped in /var/lib/ansipa-modules/).
|
||||
# script in /usr/local/lib/ansipa-modules/<name>.sh is executed once.
|
||||
# Completion is tracked via a stamp file in STATE_DIR and reflected in
|
||||
# a JSON manifest at STATE_DIR/manifest.json.
|
||||
#
|
||||
# Guard: the script exits immediately if the FreeIPA client is not enrolled
|
||||
# (/etc/ipa/default.conf must exist and the ipa command must be available).
|
||||
#
|
||||
# Configuration: /etc/ansipa-modules.conf
|
||||
# ANSIPA_USER=<username> non-root user for AUR helper (yay)
|
||||
|
|
@ -22,15 +26,112 @@ CONFIG=/etc/ansipa-modules.conf
|
|||
ANSIPA_USER="${ANSIPA_USER:-}"
|
||||
MODULES_DIR="${MODULES_DIR:-/usr/local/lib/ansipa-modules}"
|
||||
STATE_DIR="${STATE_DIR:-/var/lib/ansipa-modules}"
|
||||
PREFIX="ansipa-module-"
|
||||
MANIFEST="$STATE_DIR/manifest.json"
|
||||
PREFIX="dev_mod_"
|
||||
LOG_TAG="ansipa-modules"
|
||||
|
||||
log() { echo "[$LOG_TAG] $*"; logger -t "$LOG_TAG" "$*" 2>/dev/null || true; }
|
||||
warn() { echo "[$LOG_TAG][WARN] $*" >&2; logger -t "$LOG_TAG" "WARN: $*" 2>/dev/null || true; }
|
||||
|
||||
# ── Guard: only proceed if the ansipa/FreeIPA client is enrolled ──────────────
|
||||
# /etc/ipa/default.conf is written by ipa-client-install on successful enrollment.
|
||||
# Without it, there is no domain to query and no host groups to check.
|
||||
if [[ ! -f /etc/ipa/default.conf ]]; then
|
||||
log "FreeIPA client not enrolled (/etc/ipa/default.conf absent) — skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v ipa &>/dev/null; then
|
||||
warn "ipa command not found — FreeIPA packages not installed. Exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── State directories ─────────────────────────────────────────────────────────
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
HOST_FQDN=$(hostname -f 2>/dev/null || hostname)
|
||||
|
||||
# ── Manifest helpers (python3) ────────────────────────────────────────────────
|
||||
# The manifest is a JSON file that records the status and timestamps for every
|
||||
# module this host has encountered. It is updated atomically (tmp + rename).
|
||||
# Stamp files (.done) remain the authoritative "is this installed" check;
|
||||
# the manifest is derived from them and used for reporting/auditing.
|
||||
|
||||
_manifest_update() {
|
||||
# Args: <module> <status> status ∈ {installed, failed, pending}
|
||||
local module="$1" status="$2"
|
||||
local ts; ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
python3 - "$MANIFEST" "$module" "$status" "$HOST_FQDN" "$ts" <<'PYEOF'
|
||||
import json, sys, os
|
||||
|
||||
manifest_path, module, status, hostname, ts = sys.argv[1:6]
|
||||
|
||||
try:
|
||||
with open(manifest_path) as f:
|
||||
data = json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
data = {}
|
||||
|
||||
data["hostname"] = hostname
|
||||
data.setdefault("modules", {})
|
||||
data["last_run"] = ts
|
||||
|
||||
entry = data["modules"].setdefault(module, {})
|
||||
entry["status"] = status
|
||||
if status == "installed":
|
||||
# Preserve original installed_at if already recorded
|
||||
entry.setdefault("installed_at", ts)
|
||||
else:
|
||||
entry["last_attempt"] = ts
|
||||
|
||||
tmp = manifest_path + ".tmp"
|
||||
with open(tmp, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
f.write("\n")
|
||||
os.rename(tmp, manifest_path)
|
||||
PYEOF
|
||||
}
|
||||
|
||||
_manifest_touch_run() {
|
||||
# Update last_run and hostname without touching any module entries
|
||||
local ts; ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
python3 - "$MANIFEST" "$HOST_FQDN" "$ts" <<'PYEOF'
|
||||
import json, sys, os
|
||||
|
||||
manifest_path, hostname, ts = sys.argv[1:4]
|
||||
|
||||
try:
|
||||
with open(manifest_path) as f:
|
||||
data = json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
data = {}
|
||||
|
||||
data["hostname"] = hostname
|
||||
data.setdefault("modules", {})
|
||||
data["last_run"] = ts
|
||||
|
||||
tmp = manifest_path + ".tmp"
|
||||
with open(tmp, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
f.write("\n")
|
||||
os.rename(tmp, manifest_path)
|
||||
PYEOF
|
||||
}
|
||||
|
||||
# Reconcile: scan existing .done stamps into the manifest.
|
||||
# Handles modules installed before the manifest feature was introduced.
|
||||
_manifest_reconcile() {
|
||||
local stamp_file mod
|
||||
for stamp_file in "$STATE_DIR"/*.done; do
|
||||
[[ -f "$stamp_file" ]] || continue
|
||||
mod="${stamp_file%.done}"
|
||||
mod="${mod##*/}"
|
||||
_manifest_update "$mod" "installed"
|
||||
done
|
||||
}
|
||||
|
||||
# ── Resolve ANSIPA_USER ───────────────────────────────────────────────────────
|
||||
if [[ -z "$ANSIPA_USER" ]]; then
|
||||
# Use the first non-root, non-system user with a login shell
|
||||
ANSIPA_USER=$(awk -F: '($3>=1000 && $7!~/nologin|false/) {print $1; exit}' /etc/passwd)
|
||||
fi
|
||||
if [[ -z "$ANSIPA_USER" ]]; then
|
||||
|
|
@ -39,7 +140,6 @@ if [[ -z "$ANSIPA_USER" ]]; then
|
|||
fi
|
||||
|
||||
log "Running as root, AUR helper delegated to user: $ANSIPA_USER"
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
# ── Create a yay wrapper so module scripts can call 'yay' as non-root ────────
|
||||
YAY_BIN=$(command -v yay 2>/dev/null || true)
|
||||
|
|
@ -54,17 +154,14 @@ EOF
|
|||
chmod +x "$WRAP_DIR/yay"
|
||||
fi
|
||||
|
||||
# ── Discover which ansipa-module-* host groups this host belongs to ───────────
|
||||
HOST_FQDN=$(hostname -f 2>/dev/null || hostname)
|
||||
|
||||
if ! command -v ipa &>/dev/null; then
|
||||
warn "ipa command not found — host not enrolled in FreeIPA. Exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# kinit with host keytab so IPA commands work from the service context
|
||||
# ── Kinit with host keytab so IPA commands work from the service context ──────
|
||||
kinit -k "host/$HOST_FQDN" &>/dev/null || true
|
||||
|
||||
# Record this run in the manifest and reconcile any pre-existing stamps
|
||||
_manifest_touch_run
|
||||
_manifest_reconcile
|
||||
|
||||
# ── Discover which dev_mod_* host groups this host belongs to ─────────────────
|
||||
RAW_GROUPS=$(ipa host-show "$HOST_FQDN" --all 2>/dev/null \
|
||||
| grep -i "Member of host-groups:" | sed 's/.*: //' || true)
|
||||
|
||||
|
|
@ -73,11 +170,11 @@ if [[ -z "$RAW_GROUPS" ]]; then
|
|||
exit 0
|
||||
fi
|
||||
|
||||
# Parse comma-separated list, keep only ansipa-module-* entries
|
||||
# Parse comma-separated list, keep only dev_mod_* entries
|
||||
WANTED_MODULES=()
|
||||
while IFS=',' read -ra GRP_ARRAY; do
|
||||
for g in "${GRP_ARRAY[@]}"; do
|
||||
g="${g// /}" # strip spaces
|
||||
g="${g// /}"
|
||||
if [[ "$g" == ${PREFIX}* ]]; then
|
||||
WANTED_MODULES+=("${g#$PREFIX}")
|
||||
fi
|
||||
|
|
@ -85,7 +182,7 @@ while IFS=',' read -ra GRP_ARRAY; do
|
|||
done <<< "$RAW_GROUPS"
|
||||
|
||||
if [[ ${#WANTED_MODULES[@]} -eq 0 ]]; then
|
||||
log "No ansipa-module-* host groups found for '$HOST_FQDN'."
|
||||
log "No ${PREFIX}* host groups found for '$HOST_FQDN'."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
@ -103,14 +200,19 @@ for MODULE in "${WANTED_MODULES[@]}"; do
|
|||
|
||||
if [[ ! -f "$SCRIPT" ]]; then
|
||||
warn "Module script not found: $SCRIPT — skipping '$MODULE'."
|
||||
_manifest_update "$MODULE" "pending"
|
||||
continue
|
||||
fi
|
||||
|
||||
log "Applying module: $MODULE"
|
||||
_manifest_update "$MODULE" "pending"
|
||||
|
||||
if env PATH="$WRAP_DIR:$PATH" bash "$SCRIPT" >>"$STATE_DIR/${MODULE}.log" 2>&1; then
|
||||
touch "$STAMP"
|
||||
_manifest_update "$MODULE" "installed"
|
||||
log "Module '$MODULE' applied successfully."
|
||||
else
|
||||
_manifest_update "$MODULE" "failed"
|
||||
warn "Module '$MODULE' failed — see $STATE_DIR/${MODULE}.log"
|
||||
fi
|
||||
done
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
PREFIX="ansipa-install-"
|
||||
PREFIX="dev_pkg_"
|
||||
|
||||
# Detect distro
|
||||
if [ -f /etc/os-release ]; then
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[Unit]
|
||||
Description=Install packages based on FreeIPA ansipa-install-* groups
|
||||
Description=Install packages based on FreeIPA dev_pkg_* groups
|
||||
After=network-online.target sssd.service
|
||||
|
||||
[Service]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
mode: '0644'
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Install packages based on FreeIPA ansipa-install-* groups
|
||||
Description=Install packages based on FreeIPA dev_pkg_* groups
|
||||
After=network-online.target sssd.service
|
||||
|
||||
[Service]
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
mode: '0644'
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Install Flatpaks based on FreeIPA fp_install_* groups
|
||||
Description=Install Flatpaks based on FreeIPA dev_fp_* groups
|
||||
After=network-online.target sssd.service
|
||||
Wants=network-online.target
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
# deploy-ansipa-modules.yml — deploy the module auto-installer to enrolled hosts.
|
||||
#
|
||||
# Prerequisites on target hosts:
|
||||
# - FreeIPA client enrolled (sssd running, ipa command available)
|
||||
# - FreeIPA client enrolled (/etc/ipa/default.conf exists, ipa command available)
|
||||
# - python3 installed (used for JSON manifest writes)
|
||||
# - A non-root user with yay access (set ANSIPA_USER in /etc/ansipa-modules.conf)
|
||||
#
|
||||
# Usage:
|
||||
|
|
@ -10,8 +11,10 @@
|
|||
# ansible-playbook -i inventory deploy-ansipa-modules.yml -e ansipa_user=amir
|
||||
#
|
||||
# FreeIPA host group convention:
|
||||
# Create host groups named ansipa-module-<name> (e.g. ansipa-module-docker)
|
||||
# and add hosts to them. The timer will apply the matching module automatically.
|
||||
# Create host groups named dev_mod_<name> (e.g. dev_mod_docker, dev_mod_ollama)
|
||||
# and add hosts to them. The timer checks group membership and applies any missing
|
||||
# modules automatically. State is tracked in STATE_DIR/<module>.done stamps and
|
||||
# summarised in STATE_DIR/manifest.json.
|
||||
|
||||
- name: Deploy FreeIPA module auto-installer
|
||||
hosts: all
|
||||
|
|
@ -24,6 +27,11 @@
|
|||
|
||||
tasks:
|
||||
|
||||
- name: Ensure python3 is installed
|
||||
package:
|
||||
name: python3
|
||||
state: present
|
||||
|
||||
- name: Create module directories
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
|
|
@ -66,7 +74,7 @@
|
|||
mode: '0644'
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Apply setup modules based on FreeIPA ansipa-module-* host groups
|
||||
Description=Apply setup modules based on FreeIPA dev_mod_* host groups
|
||||
After=network-online.target sssd.service
|
||||
Wants=network-online.target
|
||||
|
||||
|
|
|
|||
|
|
@ -2,21 +2,24 @@
|
|||
# deploy-ansipa-policies.yml — deploy the policy enforcement daemon to enrolled clients.
|
||||
#
|
||||
# Installs ansipa-enforce-policies.sh and a systemd timer that runs it every 30 minutes.
|
||||
# Policies are declared by adding hosts to the following FreeIPA host groups:
|
||||
# Device policies (FreeIPA host groups — applied to the whole machine):
|
||||
# dev_daemon-enable-<unit> Ensure <unit> is enabled and running; reverted when host leaves group
|
||||
# dev_daemon-disable-<unit> Ensure <unit> is disabled and stopped; reverted when host leaves group
|
||||
# dev_timeshift-backup Enforce daily Timeshift snapshots (03:00)
|
||||
# dev_security-scan Enforce daily ClamAV + rkhunter + chkrootkit scans + SMB upload (02:00)
|
||||
# dev_no-local-users Lock local account passwords; only FreeIPA accounts can auth
|
||||
# dev_local-sudo-<username> Grant <username> local sudo on this device; reverted when host leaves
|
||||
#
|
||||
# policy-block-binary-<name> Block execution of <name> via a PATH-priority wrapper + AppArmor
|
||||
# policy-daemon-enable-<unit> Ensure <unit> is enabled and running; reverted when host leaves group
|
||||
# policy-daemon-disable-<unit> Ensure <unit> is disabled and stopped; reverted when host leaves group
|
||||
# policy-timeshift-backup Enforce daily Timeshift snapshots (03:00)
|
||||
# policy-security-scan Enforce daily ClamAV + rkhunter + chkrootkit scans + SMB upload (02:00)
|
||||
# policy-scan-notify Fetch alerts from server, notify user every 10 min until acknowledged
|
||||
# User policies (FreeIPA user groups — follow the user across all enrolled devices):
|
||||
# usr_block-binary-<name> Block execution of <name> via a PATH-priority wrapper
|
||||
# usr_scan-notify Fetch alerts from server, notify user every 10 min until acknowledged
|
||||
#
|
||||
# Prerequisites:
|
||||
# - Host enrolled in FreeIPA (sssd + ipa CLI available)
|
||||
# - For security-scan / scan-notify: samba-client installed (handled below)
|
||||
# - For security-scan / scan-notify: smb_scan_password set (use ansible-vault in production)
|
||||
# - For security-scan tools: also add host to ansipa-module-anti-malware group
|
||||
# - For timeshift-backup: also add host to ansipa-module-timeshift group
|
||||
# - For dev_security-scan / usr_scan-notify: samba-client installed (handled below)
|
||||
# - For dev_security-scan / usr_scan-notify: smb_scan_password set (use ansible-vault in production)
|
||||
# - For security-scan tools: also add host to dev_mod_anti-malware group
|
||||
# - For timeshift-backup: also add host to dev_mod_timeshift group
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook -i inventory deploy-ansipa-policies.yml \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
# sync-modules.sh — scan apps/ and stub any missing entries in modules.conf
|
||||
# Safe to run repeatedly; never removes or modifies existing entries.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONF="$SCRIPT_DIR/modules.conf"
|
||||
APPS="$SCRIPT_DIR/modules/optional-Modules/apps"
|
||||
|
||||
# Read all existing IDs from modules.conf into a set.
|
||||
declare -A known
|
||||
while IFS='|' read -r id _rest; do
|
||||
[[ "$id" =~ ^[[:space:]]*# || -z "${id// /}" ]] && continue
|
||||
known["$id"]=1
|
||||
done < "$CONF"
|
||||
|
||||
# Scan apps/ for .sh files not yet in modules.conf and append stubs.
|
||||
added=0
|
||||
for script in "$APPS"/*.sh; do
|
||||
id="${script##*/}"
|
||||
id="${id%.sh}"
|
||||
if [[ -z "${known[$id]+set}" ]]; then
|
||||
printf '%s||||\n' "$id" >> "$CONF"
|
||||
echo " [added stub] $id"
|
||||
(( added++ )) || true
|
||||
fi
|
||||
done
|
||||
|
||||
if (( added == 0 )); then
|
||||
echo "modules.conf is up to date — no new stubs added."
|
||||
else
|
||||
echo "$added stub(s) added to modules.conf. Fill in category and description, then run generate-modules.sh."
|
||||
fi
|
||||
|
|
@ -162,85 +162,88 @@ count_steps() {
|
|||
# Optional app modules: one glob check per app, one increment per match.
|
||||
# Glob syntax *"tag"* matches if the space-separated SELECTED_APPS string
|
||||
# contains the tag anywhere — works because tags never share substrings.
|
||||
[[ "$a" == *"ollama"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"llama-cpp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"open-webui"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"claude"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
# BEGIN GENERATED MODULES: module-counters
|
||||
[[ "$a" == *"ollama"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"llama-cpp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"open-webui"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"claude"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"networking-cli"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"disk-recovery"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"himalaya"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"gnuplot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"blender-povray"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"toot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"db-clients"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"mysql"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"productivity"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"yt-dlp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"sox"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"imagemagick"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"ffmpeg"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"localtunnel"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"butter"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"tlp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"steam"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"vesktop"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"spotify"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"prism"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"vintagestory"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"openarena"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"tetris"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"doom"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"sauerbraten"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"stuntrally"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"localsend"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"croc"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"opendeck"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"onlyoffice"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"wireshark"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"k8s"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"docker"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"podman"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"cockpit"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"ssh-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"freeipa-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"freeipa-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"freeipa-image"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"python"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"zfs"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"wprs"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"chromium"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"disk-recovery"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"himalaya"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"mail-notmuch"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"caldav-sync"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"ssh-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"wireshark"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"anti-malware"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"gnuplot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"blender-povray"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"toot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"db-clients"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"mysql"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"productivity"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"python"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"k8s"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"docker"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"podman"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"cockpit"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"tlp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"butter"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"localsend"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"croc"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"opendeck"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"localtunnel"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"timeshift"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"zfs"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"wprs"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"plymouth-custom"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"steam"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"vesktop"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"spotify"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"prism"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"vintagestory"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"openarena"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"tetris"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"doom"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"sauerbraten"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"stuntrally"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"onlyoffice"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"xournal"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"rnote"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"obsidian"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"tangent-notes"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"ffmpeg"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"sox"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"imagemagick"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"yt-dlp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"gimp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"inkscape"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"krita"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"kdenlive"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"openshot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"shotcut"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"ardour"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"audacity"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"lmms"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"mixxx"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"cecilia"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"chromium"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"firefox-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"zen-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"nyxt"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"librewolf"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"min-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"vscodium"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"zed-ide"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"geany"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"codeblocks"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"kate"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"rdp-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"zen-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"nyxt"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"librewolf"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"min-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"vscodium"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"zed-ide"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"geany"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"codeblocks"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"kate"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"rdp-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"lamco-rdp-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"qemu"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"xournal"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"rnote"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"obsidian"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"tangent-notes"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"gimp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"inkscape"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"krita"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"ardour"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"audacity"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"lmms"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"mixxx"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"cecilia"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"kdenlive"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"openshot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"shotcut"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"anti-malware"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"timeshift"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"mail-notmuch"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"caldav-sync"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"qemu"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"freeipa-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"freeipa-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
[[ "$a" == *"freeipa-image"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||
# END GENERATED MODULES: module-counters
|
||||
}
|
||||
|
||||
# ── Answerfile ────────────────────────────────────────────────────────────────
|
||||
|
|
@ -441,94 +444,92 @@ else
|
|||
# prompt, buttons), with a minimum of 4 to remain usable on tiny screens.
|
||||
_APP_H=$(( TERM_H - 2 < 40 ? TERM_H - 2 : 40 ))
|
||||
_APP_LIST_H=$(( _APP_H - 8 < 4 ? 4 : _APP_H - 8 ))
|
||||
# BEGIN GENERATED MODULES: module-checklist
|
||||
SELECTED_APPS=$(dialog --backtitle "$BACKTITLE" \
|
||||
--title " Applications " \
|
||||
--checklist "Optional applications — installed after base components:" "$_APP_H" 76 "$_APP_LIST_H" \
|
||||
"ollama" "Ollama local LLM runner + API server" off \
|
||||
"llama-cpp" "llama.cpp standalone inference CLI + server" off \
|
||||
"open-webui" "Open WebUI browser UI for Ollama / LLM backends" off \
|
||||
"claude" "Claude Code Anthropic CLI via npm" off \
|
||||
"networking-cli" "Networking CLI nmap · nethogs · mitmproxy · httpie" off \
|
||||
"disk-recovery" "Disk Recovery ddrescue · f3" off \
|
||||
"himalaya" "Himalaya terminal email client (AUR)" off \
|
||||
"mail-notmuch" "Mail (notmuch) isync · msmtp · notmuch · alot stack" off \
|
||||
"caldav-sync" "CalDAV Sync vdirsyncer · khal calendar sync" off \
|
||||
"gnuplot" "Gnuplot scientific plotting" off \
|
||||
"blender-povray" "Blender + POV-Ray 3D modelling & ray-tracing" off \
|
||||
"toot" "toot Mastodon CLI client (AUR)" off \
|
||||
"db-clients" "DB Clients pgcli · mycli" off \
|
||||
"mysql" "MySQL / MariaDB mariadb server + setup" off \
|
||||
"productivity" "Productivity taskwarrior · watson · jrnl" off \
|
||||
"yt-dlp" "yt-dlp YouTube / media downloader" off \
|
||||
"sox" "SoX audio processing toolkit" off \
|
||||
"imagemagick" "ImageMagick image manipulation" off \
|
||||
"ffmpeg" "FFmpeg extras thumbnailer · GStreamer codecs" off \
|
||||
"localtunnel" "LocalTunnel expose localhost via tunnel" off \
|
||||
"butter" "butter btrfs snapshot backup (AUR)" off \
|
||||
"tlp" "TLP laptop power management" off \
|
||||
"steam" "Steam gaming platform" off \
|
||||
"vesktop" "Vesktop Discord + Vencord theme" off \
|
||||
"spotify" "Spotify launcher + Spicetify theming" off \
|
||||
"prism" "PrismLauncher Minecraft launcher (Flatpak)" off \
|
||||
"vintagestory" "Vintage Story survival game (AUR)" off \
|
||||
"openarena" "OpenArena open-source Quake III Arena" off \
|
||||
"tetris" "Tetris CLI bastet · vitetris" off \
|
||||
"doom" "Doom Chocolate Doom + Freedoom data" off \
|
||||
"sauerbraten" "Sauerbraten open-source FPS (Cube 2)" off \
|
||||
"stuntrally" "Stunt Rally rally racing game (Flatpak)" off \
|
||||
"localsend" "LocalSend LAN file transfer (AUR)" off \
|
||||
"croc" "croc cross-platform file transfer" off \
|
||||
"opendeck" "OpenDeck Stream Deck controller (Flatpak+ydotool)" off \
|
||||
"onlyoffice" "OnlyOffice office suite (AUR)" off \
|
||||
"xournal" "Xournal++ note-taking & PDF annotator" off \
|
||||
"rnote" "Rnote handwriting & note-taking (Flatpak)" off \
|
||||
"obsidian" "Obsidian knowledge base & Markdown notes (Flatpak)" off \
|
||||
"tangent-notes" "Tangent Notes networked Markdown notes (Flatpak)" off \
|
||||
"gimp" "GIMP GNU image manipulation program" off \
|
||||
"inkscape" "Inkscape vector graphics editor" off \
|
||||
"krita" "Krita digital painting application" off \
|
||||
"ardour" "Ardour professional DAW" off \
|
||||
"audacity" "Audacity multi-track audio editor" off \
|
||||
"lmms" "LMMS Linux MultiMedia Studio DAW" off \
|
||||
"mixxx" "Mixxx DJ mixing software" off \
|
||||
"cecilia" "Cecilia audio signal processing (AUR)" off \
|
||||
"kdenlive" "Kdenlive KDE non-linear video editor" off \
|
||||
"openshot" "OpenShot easy video editor" off \
|
||||
"shotcut" "Shotcut cross-platform video editor" off \
|
||||
"anti-malware" "Anti-Malware ClamAV · rkhunter · chkrootkit" off \
|
||||
"timeshift" "Timeshift system snapshot / backup + autosnap" off \
|
||||
"wireshark" "Wireshark network packet analyser (GUI)" off \
|
||||
"k8s" "Kubernetes tools kubectl · podman-desktop" off \
|
||||
"docker" "Docker docker · docker-compose" off \
|
||||
"podman" "Podman rootless containers · buildah" off \
|
||||
"cockpit" "Cockpit web UI · machines · podman" off \
|
||||
"ssh-server" "SSH server openssh · key-auth · enabled" off \
|
||||
"freeipa-client" "FreeIPA Client sssd + ipa-client-install + enrollment" off \
|
||||
"freeipa-server" "FreeIPA Server interactive server setup + client gen" off \
|
||||
"freeipa-image" "FreeIPA Image OCI/LXC/Proxmox LXC builder + Keycloak" off \
|
||||
"python" "Python tools pyright · pipx · pynvim" off \
|
||||
"zfs" "ZFS zfs-dkms kernel module" off \
|
||||
"wprs" "WPRS wprs-git (AUR)" off \
|
||||
\
|
||||
"chromium" "Chromium open-source browser (official)" off \
|
||||
"firefox-browser" "Firefox Mozilla browser (official)" off \
|
||||
"zen-browser" "Zen Browser Firefox-based privacy browser (AUR)" off \
|
||||
"nyxt" "Nyxt keyboard-driven browser (AUR)" off \
|
||||
"librewolf" "LibreWolf hardened Firefox fork (AUR)" off \
|
||||
"min-browser" "Min minimal Electron browser (AUR)" off \
|
||||
\
|
||||
"vscodium" "VSCodium telemetry-free VS Code (AUR)" off \
|
||||
"zed-ide" "Zed high-performance Rust IDE (official)" off \
|
||||
"geany" "Geany lightweight IDE + plugins (official)" off \
|
||||
"codeblocks" "Code::Blocks C/C++ IDE (official)" off \
|
||||
"kate" "Kate KDE advanced text editor (official)" off \
|
||||
\
|
||||
"rdp-client" "RDP Client Remmina + FreeRDP + VNC plugins" off \
|
||||
"lamco-rdp-server" "Lamco RDP Server native Wayland RDP server (AUR, Rust)" off \
|
||||
"qemu" "QEMU/KVM full virt stack + virt-manager GUI" off \
|
||||
# Esc / Cancel yields exit code 1; treat it as "no optional apps selected"
|
||||
# rather than a hard abort so the user can still install base components.
|
||||
"ollama" "ollama local LLM runner and API server" off \
|
||||
"llama-cpp" "llama-cpp standalone LLM inference CLI and server" off \
|
||||
"open-webui" "open-webui browser UI for Ollama and LLM backends" off \
|
||||
"claude" "claude Anthropic Claude Code CLI via npm" off \
|
||||
"networking-cli" "networking-cli nmap, nethogs, mitmproxy, httpie" off \
|
||||
"disk-recovery" "disk-recovery ddrescue and f3 disk recovery tools" off \
|
||||
"himalaya" "himalaya terminal email client (AUR)" off \
|
||||
"mail-notmuch" "mail-notmuch isync, msmtp, notmuch, alot mail stack" off \
|
||||
"caldav-sync" "caldav-sync vdirsyncer and khal CalDAV calendar sync" off \
|
||||
"ssh-server" "ssh-server openssh with key-auth and systemd unit enabled" off \
|
||||
"wireshark" "wireshark network packet analyser GUI" off \
|
||||
"anti-malware" "anti-malware ClamAV, rkhunter, chkrootkit" off \
|
||||
"gnuplot" "gnuplot scientific plotting tool" off \
|
||||
"blender-povray" "blender-povray 3D modelling and ray-tracing (Blender + POV-Ray)" off \
|
||||
"toot" "toot Mastodon CLI client (AUR)" off \
|
||||
"db-clients" "db-clients pgcli and mycli interactive database CLIs" off \
|
||||
"mysql" "mysql MariaDB server with initial setup" off \
|
||||
"productivity" "productivity taskwarrior, watson, jrnl — task management and time tracking" off \
|
||||
"python" "python pyright, pipx, pynvim Python tooling" on \
|
||||
"k8s" "k8s kubectl and podman-desktop Kubernetes tools" off \
|
||||
"docker" "docker docker and docker-compose" off \
|
||||
"podman" "podman rootless containers with buildah" off \
|
||||
"cockpit" "cockpit web UI for machines and containers" off \
|
||||
"tlp" "tlp laptop battery optimisation" off \
|
||||
"butter" "butter btrfs snapshot backup manager (AUR)" off \
|
||||
"localsend" "localsend LAN file transfer, AirDrop-like (AUR)" off \
|
||||
"croc" "croc cross-platform encrypted file transfer" off \
|
||||
"opendeck" "opendeck Stream Deck controller — ydotool + OpenDeck (Flatpak)" off \
|
||||
"localtunnel" "localtunnel expose localhost over a public URL" off \
|
||||
"timeshift" "timeshift system snapshot and backup with autosnap" off \
|
||||
"zfs" "zfs zfs-dkms kernel module" off \
|
||||
"wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \
|
||||
"plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \
|
||||
"steam" "steam Steam gaming platform" off \
|
||||
"vesktop" "vesktop Discord client with Vencord theme" off \
|
||||
"spotify" "spotify Spotify launcher with Spicetify theming" off \
|
||||
"prism" "prism PrismLauncher Minecraft launcher (Flatpak)" off \
|
||||
"vintagestory" "vintagestory Vintage Story survival game (AUR)" off \
|
||||
"openarena" "openarena open-source Quake III Arena" off \
|
||||
"tetris" "tetris bastet and vitetris terminal Tetris" off \
|
||||
"doom" "doom Chocolate Doom with Freedoom data" off \
|
||||
"sauerbraten" "sauerbraten Sauerbraten open-source FPS (Cube 2)" off \
|
||||
"stuntrally" "stuntrally Stunt Rally racing game (Flatpak)" off \
|
||||
"onlyoffice" "onlyoffice office suite — Docs, Sheets, Slides (AUR)" on \
|
||||
"xournal" "xournal note-taking and PDF annotator" off \
|
||||
"rnote" "rnote handwriting and note-taking with stylus support (Flatpak)" off \
|
||||
"obsidian" "obsidian knowledge base and Markdown note-taking (Flatpak)" off \
|
||||
"tangent-notes" "tangent-notes networked Markdown note-taking (Flatpak)" off \
|
||||
"ffmpeg" "ffmpeg GStreamer codecs and ffmpegthumbnailer" off \
|
||||
"sox" "sox command-line audio processing toolkit" off \
|
||||
"imagemagick" "imagemagick image manipulation suite" off \
|
||||
"yt-dlp" "yt-dlp YouTube and media downloader" off \
|
||||
"gimp" "gimp GNU Image Manipulation Program" off \
|
||||
"inkscape" "inkscape vector graphics editor" off \
|
||||
"krita" "krita digital painting and illustration" off \
|
||||
"kdenlive" "kdenlive KDE non-linear video editor" off \
|
||||
"openshot" "openshot cross-platform video editor" off \
|
||||
"shotcut" "shotcut cross-platform video editor" off \
|
||||
"ardour" "ardour professional DAW" off \
|
||||
"audacity" "audacity multi-track audio editor" off \
|
||||
"lmms" "lmms Linux MultiMedia Studio music production" off \
|
||||
"mixxx" "mixxx DJ mixing software" off \
|
||||
"cecilia" "cecilia audio synthesis and signal processing (AUR)" off \
|
||||
"chromium" "chromium open-source Chromium browser (official)" off \
|
||||
"firefox-browser" "firefox-browser Mozilla Firefox (official)" on \
|
||||
"zen-browser" "zen-browser privacy-focused Firefox fork (AUR)" off \
|
||||
"nyxt" "nyxt keyboard-driven hackable browser (AUR)" off \
|
||||
"librewolf" "librewolf hardened Firefox fork (AUR)" off \
|
||||
"min-browser" "min-browser minimal Electron browser (AUR)" off \
|
||||
"vscodium" "vscodium telemetry-free VS Code build (AUR)" off \
|
||||
"zed-ide" "zed-ide high-performance Rust IDE (official)" off \
|
||||
"geany" "geany lightweight IDE with plugins (official)" off \
|
||||
"codeblocks" "codeblocks C/C++ IDE (official)" off \
|
||||
"kate" "kate KDE advanced text editor (official)" off \
|
||||
"rdp-client" "rdp-client Remmina with FreeRDP and VNC plugins" off \
|
||||
"lamco-rdp-server" "lamco-rdp-server native Wayland RDP server (AUR, Rust)" off \
|
||||
"qemu" "qemu full QEMU/KVM stack with virt-manager" off \
|
||||
"freeipa-client" "freeipa-client sssd and ipa-client-install with auto-enrollment" off \
|
||||
"freeipa-server" "freeipa-server interactive FreeIPA server setup with client generator" off \
|
||||
"freeipa-image" "freeipa-image OCI/LXC/Proxmox image builder with Keycloak" off \
|
||||
3>&1 1>&2 2>&3) || SELECTED_APPS=""
|
||||
# END GENERATED MODULES: module-checklist
|
||||
fi
|
||||
|
||||
# ── Shell RC preference ───────────────────────────────────────────────────────
|
||||
|
|
@ -560,83 +561,88 @@ if ! $ANSWERFILE_MODE; then
|
|||
|
||||
if [[ -n "$SELECTED_APPS" ]]; then
|
||||
SUMMARY+="\n Applications:\n"
|
||||
[[ "$SELECTED_APPS" == *"ollama"* ]] && SUMMARY+=" ✦ Ollama\n"
|
||||
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && SUMMARY+=" ✦ llama.cpp\n"
|
||||
[[ "$SELECTED_APPS" == *"open-webui"* ]] && SUMMARY+=" ✦ Open WebUI\n"
|
||||
[[ "$SELECTED_APPS" == *"claude"* ]] && SUMMARY+=" ✦ Claude Code\n"
|
||||
[[ "$SELECTED_APPS" == *"networking-cli"* ]] && SUMMARY+=" ✦ Networking CLI (nmap, nethogs, mitmproxy, httpie)\n"
|
||||
[[ "$SELECTED_APPS" == *"disk-recovery"* ]] && SUMMARY+=" ✦ Disk Recovery (ddrescue, f3)\n"
|
||||
[[ "$SELECTED_APPS" == *"himalaya"* ]] && SUMMARY+=" ✦ Himalaya\n"
|
||||
[[ "$SELECTED_APPS" == *"gnuplot"* ]] && SUMMARY+=" ✦ Gnuplot\n"
|
||||
[[ "$SELECTED_APPS" == *"blender-povray"* ]] && SUMMARY+=" ✦ Blender + POV-Ray\n"
|
||||
[[ "$SELECTED_APPS" == *"toot"* ]] && SUMMARY+=" ✦ toot\n"
|
||||
[[ "$SELECTED_APPS" == *"db-clients"* ]] && SUMMARY+=" ✦ DB Clients (pgcli, mycli)\n"
|
||||
[[ "$SELECTED_APPS" == *"mysql"* ]] && SUMMARY+=" ✦ MySQL / MariaDB\n"
|
||||
[[ "$SELECTED_APPS" == *"productivity"* ]] && SUMMARY+=" ✦ Productivity (taskwarrior, watson, jrnl)\n"
|
||||
[[ "$SELECTED_APPS" == *"yt-dlp"* ]] && SUMMARY+=" ✦ yt-dlp\n"
|
||||
[[ "$SELECTED_APPS" == *"sox"* ]] && SUMMARY+=" ✦ SoX\n"
|
||||
[[ "$SELECTED_APPS" == *"imagemagick"* ]] && SUMMARY+=" ✦ ImageMagick\n"
|
||||
[[ "$SELECTED_APPS" == *"ffmpeg"* ]] && SUMMARY+=" ✦ FFmpeg extras\n"
|
||||
[[ "$SELECTED_APPS" == *"localtunnel"* ]] && SUMMARY+=" ✦ LocalTunnel\n"
|
||||
[[ "$SELECTED_APPS" == *"butter"* ]] && SUMMARY+=" ✦ butter (btrfs backup)\n"
|
||||
[[ "$SELECTED_APPS" == *"tlp"* ]] && SUMMARY+=" ✦ TLP\n"
|
||||
[[ "$SELECTED_APPS" == *"steam"* ]] && SUMMARY+=" ✦ Steam\n"
|
||||
[[ "$SELECTED_APPS" == *"vesktop"* ]] && SUMMARY+=" ✦ Vesktop + Vencord theme\n"
|
||||
[[ "$SELECTED_APPS" == *"spotify"* ]] && SUMMARY+=" ✦ Spotify + Spicetify\n"
|
||||
[[ "$SELECTED_APPS" == *"prism"* ]] && SUMMARY+=" ✦ PrismLauncher\n"
|
||||
[[ "$SELECTED_APPS" == *"vintagestory"* ]] && SUMMARY+=" ✦ Vintage Story\n"
|
||||
[[ "$SELECTED_APPS" == *"openarena"* ]] && SUMMARY+=" ✦ OpenArena\n"
|
||||
[[ "$SELECTED_APPS" == *"tetris"* ]] && SUMMARY+=" ✦ Tetris CLI (bastet · vitetris)\n"
|
||||
[[ "$SELECTED_APPS" == *"doom"* ]] && SUMMARY+=" ✦ Doom\n"
|
||||
[[ "$SELECTED_APPS" == *"sauerbraten"* ]] && SUMMARY+=" ✦ Sauerbraten\n"
|
||||
[[ "$SELECTED_APPS" == *"stuntrally"* ]] && SUMMARY+=" ✦ Stunt Rally\n"
|
||||
[[ "$SELECTED_APPS" == *"localsend"* ]] && SUMMARY+=" ✦ LocalSend\n"
|
||||
[[ "$SELECTED_APPS" == *"croc"* ]] && SUMMARY+=" ✦ croc\n"
|
||||
[[ "$SELECTED_APPS" == *"opendeck"* ]] && SUMMARY+=" ✦ OpenDeck + ydotool\n"
|
||||
[[ "$SELECTED_APPS" == *"onlyoffice"* ]] && SUMMARY+=" ✦ OnlyOffice\n"
|
||||
[[ "$SELECTED_APPS" == *"xournal"* ]] && SUMMARY+=" ✦ Xournal++\n"
|
||||
[[ "$SELECTED_APPS" == *"rnote"* ]] && SUMMARY+=" ✦ Rnote\n"
|
||||
[[ "$SELECTED_APPS" == *"obsidian"* ]] && SUMMARY+=" ✦ Obsidian\n"
|
||||
[[ "$SELECTED_APPS" == *"tangent-notes"* ]] && SUMMARY+=" ✦ Tangent Notes\n"
|
||||
[[ "$SELECTED_APPS" == *"gimp"* ]] && SUMMARY+=" ✦ GIMP\n"
|
||||
[[ "$SELECTED_APPS" == *"inkscape"* ]] && SUMMARY+=" ✦ Inkscape\n"
|
||||
[[ "$SELECTED_APPS" == *"krita"* ]] && SUMMARY+=" ✦ Krita\n"
|
||||
[[ "$SELECTED_APPS" == *"ardour"* ]] && SUMMARY+=" ✦ Ardour\n"
|
||||
[[ "$SELECTED_APPS" == *"audacity"* ]] && SUMMARY+=" ✦ Audacity\n"
|
||||
[[ "$SELECTED_APPS" == *"lmms"* ]] && SUMMARY+=" ✦ LMMS\n"
|
||||
[[ "$SELECTED_APPS" == *"mixxx"* ]] && SUMMARY+=" ✦ Mixxx\n"
|
||||
[[ "$SELECTED_APPS" == *"cecilia"* ]] && SUMMARY+=" ✦ Cecilia\n"
|
||||
[[ "$SELECTED_APPS" == *"kdenlive"* ]] && SUMMARY+=" ✦ Kdenlive\n"
|
||||
[[ "$SELECTED_APPS" == *"openshot"* ]] && SUMMARY+=" ✦ OpenShot\n"
|
||||
[[ "$SELECTED_APPS" == *"shotcut"* ]] && SUMMARY+=" ✦ Shotcut\n"
|
||||
[[ "$SELECTED_APPS" == *"anti-malware"* ]] && SUMMARY+=" ✦ Anti-Malware (ClamAV, rkhunter, chkrootkit)\n"
|
||||
[[ "$SELECTED_APPS" == *"timeshift"* ]] && SUMMARY+=" ✦ Timeshift\n"
|
||||
[[ "$SELECTED_APPS" == *"wireshark"* ]] && SUMMARY+=" ✦ Wireshark\n"
|
||||
[[ "$SELECTED_APPS" == *"k8s"* ]] && SUMMARY+=" ✦ Kubernetes tools\n"
|
||||
[[ "$SELECTED_APPS" == *"docker"* ]] && SUMMARY+=" ✦ Docker + Compose\n"
|
||||
[[ "$SELECTED_APPS" == *"podman"* ]] && SUMMARY+=" ✦ Podman (rootless) + Buildah\n"
|
||||
[[ "$SELECTED_APPS" == *"cockpit"* ]] && SUMMARY+=" ✦ Cockpit web UI\n"
|
||||
[[ "$SELECTED_APPS" == *"ssh-server"* ]] && SUMMARY+=" ✦ SSH server (openssh, key auth)\n"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-client"* ]] && SUMMARY+=" ✦ FreeIPA Client\n"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-server"* ]] && SUMMARY+=" ✦ FreeIPA Server\n"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-image"* ]] && SUMMARY+=" ✦ FreeIPA Image Builder\n"
|
||||
[[ "$SELECTED_APPS" == *"python"* ]] && SUMMARY+=" ✦ Python tools\n"
|
||||
[[ "$SELECTED_APPS" == *"zfs"* ]] && SUMMARY+=" ✦ ZFS\n"
|
||||
[[ "$SELECTED_APPS" == *"wprs"* ]] && SUMMARY+=" ✦ WPRS\n"
|
||||
[[ "$SELECTED_APPS" == *"chromium"* ]] && SUMMARY+=" ✦ Chromium\n"
|
||||
[[ "$SELECTED_APPS" == *"firefox-browser"* ]] && SUMMARY+=" ✦ Firefox\n"
|
||||
[[ "$SELECTED_APPS" == *"zen-browser"* ]] && SUMMARY+=" ✦ Zen Browser\n"
|
||||
[[ "$SELECTED_APPS" == *"nyxt"* ]] && SUMMARY+=" ✦ Nyxt\n"
|
||||
[[ "$SELECTED_APPS" == *"librewolf"* ]] && SUMMARY+=" ✦ LibreWolf\n"
|
||||
[[ "$SELECTED_APPS" == *"min-browser"* ]] && SUMMARY+=" ✦ Min Browser\n"
|
||||
[[ "$SELECTED_APPS" == *"vscodium"* ]] && SUMMARY+=" ✦ VSCodium\n"
|
||||
[[ "$SELECTED_APPS" == *"zed-ide"* ]] && SUMMARY+=" ✦ Zed IDE\n"
|
||||
[[ "$SELECTED_APPS" == *"geany"* ]] && SUMMARY+=" ✦ Geany\n"
|
||||
[[ "$SELECTED_APPS" == *"codeblocks"* ]] && SUMMARY+=" ✦ Code::Blocks\n"
|
||||
[[ "$SELECTED_APPS" == *"kate"* ]] && SUMMARY+=" ✦ Kate\n"
|
||||
[[ "$SELECTED_APPS" == *"rdp-client"* ]] && SUMMARY+=" ✦ RDP Client (Remmina + FreeRDP)\n"
|
||||
[[ "$SELECTED_APPS" == *"lamco-rdp-server"* ]] && SUMMARY+=" ✦ Lamco RDP Server (native Wayland)\n"
|
||||
[[ "$SELECTED_APPS" == *"qemu"* ]] && SUMMARY+=" ✦ QEMU/KVM + virt-manager\n"
|
||||
# BEGIN GENERATED MODULES: module-summary
|
||||
[[ "$SELECTED_APPS" == *"ollama"* ]] && SUMMARY+=" ✦ ollama\n"
|
||||
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && SUMMARY+=" ✦ llama-cpp\n"
|
||||
[[ "$SELECTED_APPS" == *"open-webui"* ]] && SUMMARY+=" ✦ open-webui\n"
|
||||
[[ "$SELECTED_APPS" == *"claude"* ]] && SUMMARY+=" ✦ claude\n"
|
||||
[[ "$SELECTED_APPS" == *"networking-cli"* ]] && SUMMARY+=" ✦ networking-cli\n"
|
||||
[[ "$SELECTED_APPS" == *"disk-recovery"* ]] && SUMMARY+=" ✦ disk-recovery\n"
|
||||
[[ "$SELECTED_APPS" == *"himalaya"* ]] && SUMMARY+=" ✦ himalaya\n"
|
||||
[[ "$SELECTED_APPS" == *"mail-notmuch"* ]] && SUMMARY+=" ✦ mail-notmuch\n"
|
||||
[[ "$SELECTED_APPS" == *"caldav-sync"* ]] && SUMMARY+=" ✦ caldav-sync\n"
|
||||
[[ "$SELECTED_APPS" == *"ssh-server"* ]] && SUMMARY+=" ✦ ssh-server\n"
|
||||
[[ "$SELECTED_APPS" == *"wireshark"* ]] && SUMMARY+=" ✦ wireshark\n"
|
||||
[[ "$SELECTED_APPS" == *"anti-malware"* ]] && SUMMARY+=" ✦ anti-malware\n"
|
||||
[[ "$SELECTED_APPS" == *"gnuplot"* ]] && SUMMARY+=" ✦ gnuplot\n"
|
||||
[[ "$SELECTED_APPS" == *"blender-povray"* ]] && SUMMARY+=" ✦ blender-povray\n"
|
||||
[[ "$SELECTED_APPS" == *"toot"* ]] && SUMMARY+=" ✦ toot\n"
|
||||
[[ "$SELECTED_APPS" == *"db-clients"* ]] && SUMMARY+=" ✦ db-clients\n"
|
||||
[[ "$SELECTED_APPS" == *"mysql"* ]] && SUMMARY+=" ✦ mysql\n"
|
||||
[[ "$SELECTED_APPS" == *"productivity"* ]] && SUMMARY+=" ✦ productivity\n"
|
||||
[[ "$SELECTED_APPS" == *"python"* ]] && SUMMARY+=" ✦ python\n"
|
||||
[[ "$SELECTED_APPS" == *"k8s"* ]] && SUMMARY+=" ✦ k8s\n"
|
||||
[[ "$SELECTED_APPS" == *"docker"* ]] && SUMMARY+=" ✦ docker\n"
|
||||
[[ "$SELECTED_APPS" == *"podman"* ]] && SUMMARY+=" ✦ podman\n"
|
||||
[[ "$SELECTED_APPS" == *"cockpit"* ]] && SUMMARY+=" ✦ cockpit\n"
|
||||
[[ "$SELECTED_APPS" == *"tlp"* ]] && SUMMARY+=" ✦ tlp\n"
|
||||
[[ "$SELECTED_APPS" == *"butter"* ]] && SUMMARY+=" ✦ butter\n"
|
||||
[[ "$SELECTED_APPS" == *"localsend"* ]] && SUMMARY+=" ✦ localsend\n"
|
||||
[[ "$SELECTED_APPS" == *"croc"* ]] && SUMMARY+=" ✦ croc\n"
|
||||
[[ "$SELECTED_APPS" == *"opendeck"* ]] && SUMMARY+=" ✦ opendeck\n"
|
||||
[[ "$SELECTED_APPS" == *"localtunnel"* ]] && SUMMARY+=" ✦ localtunnel\n"
|
||||
[[ "$SELECTED_APPS" == *"timeshift"* ]] && SUMMARY+=" ✦ timeshift\n"
|
||||
[[ "$SELECTED_APPS" == *"zfs"* ]] && SUMMARY+=" ✦ zfs\n"
|
||||
[[ "$SELECTED_APPS" == *"wprs"* ]] && SUMMARY+=" ✦ wprs\n"
|
||||
[[ "$SELECTED_APPS" == *"plymouth-custom"* ]] && SUMMARY+=" ✦ plymouth-custom\n"
|
||||
[[ "$SELECTED_APPS" == *"steam"* ]] && SUMMARY+=" ✦ steam\n"
|
||||
[[ "$SELECTED_APPS" == *"vesktop"* ]] && SUMMARY+=" ✦ vesktop\n"
|
||||
[[ "$SELECTED_APPS" == *"spotify"* ]] && SUMMARY+=" ✦ spotify\n"
|
||||
[[ "$SELECTED_APPS" == *"prism"* ]] && SUMMARY+=" ✦ prism\n"
|
||||
[[ "$SELECTED_APPS" == *"vintagestory"* ]] && SUMMARY+=" ✦ vintagestory\n"
|
||||
[[ "$SELECTED_APPS" == *"openarena"* ]] && SUMMARY+=" ✦ openarena\n"
|
||||
[[ "$SELECTED_APPS" == *"tetris"* ]] && SUMMARY+=" ✦ tetris\n"
|
||||
[[ "$SELECTED_APPS" == *"doom"* ]] && SUMMARY+=" ✦ doom\n"
|
||||
[[ "$SELECTED_APPS" == *"sauerbraten"* ]] && SUMMARY+=" ✦ sauerbraten\n"
|
||||
[[ "$SELECTED_APPS" == *"stuntrally"* ]] && SUMMARY+=" ✦ stuntrally\n"
|
||||
[[ "$SELECTED_APPS" == *"onlyoffice"* ]] && SUMMARY+=" ✦ onlyoffice\n"
|
||||
[[ "$SELECTED_APPS" == *"xournal"* ]] && SUMMARY+=" ✦ xournal\n"
|
||||
[[ "$SELECTED_APPS" == *"rnote"* ]] && SUMMARY+=" ✦ rnote\n"
|
||||
[[ "$SELECTED_APPS" == *"obsidian"* ]] && SUMMARY+=" ✦ obsidian\n"
|
||||
[[ "$SELECTED_APPS" == *"tangent-notes"* ]] && SUMMARY+=" ✦ tangent-notes\n"
|
||||
[[ "$SELECTED_APPS" == *"ffmpeg"* ]] && SUMMARY+=" ✦ ffmpeg\n"
|
||||
[[ "$SELECTED_APPS" == *"sox"* ]] && SUMMARY+=" ✦ sox\n"
|
||||
[[ "$SELECTED_APPS" == *"imagemagick"* ]] && SUMMARY+=" ✦ imagemagick\n"
|
||||
[[ "$SELECTED_APPS" == *"yt-dlp"* ]] && SUMMARY+=" ✦ yt-dlp\n"
|
||||
[[ "$SELECTED_APPS" == *"gimp"* ]] && SUMMARY+=" ✦ gimp\n"
|
||||
[[ "$SELECTED_APPS" == *"inkscape"* ]] && SUMMARY+=" ✦ inkscape\n"
|
||||
[[ "$SELECTED_APPS" == *"krita"* ]] && SUMMARY+=" ✦ krita\n"
|
||||
[[ "$SELECTED_APPS" == *"kdenlive"* ]] && SUMMARY+=" ✦ kdenlive\n"
|
||||
[[ "$SELECTED_APPS" == *"openshot"* ]] && SUMMARY+=" ✦ openshot\n"
|
||||
[[ "$SELECTED_APPS" == *"shotcut"* ]] && SUMMARY+=" ✦ shotcut\n"
|
||||
[[ "$SELECTED_APPS" == *"ardour"* ]] && SUMMARY+=" ✦ ardour\n"
|
||||
[[ "$SELECTED_APPS" == *"audacity"* ]] && SUMMARY+=" ✦ audacity\n"
|
||||
[[ "$SELECTED_APPS" == *"lmms"* ]] && SUMMARY+=" ✦ lmms\n"
|
||||
[[ "$SELECTED_APPS" == *"mixxx"* ]] && SUMMARY+=" ✦ mixxx\n"
|
||||
[[ "$SELECTED_APPS" == *"cecilia"* ]] && SUMMARY+=" ✦ cecilia\n"
|
||||
[[ "$SELECTED_APPS" == *"chromium"* ]] && SUMMARY+=" ✦ chromium\n"
|
||||
[[ "$SELECTED_APPS" == *"firefox-browser"* ]] && SUMMARY+=" ✦ firefox-browser\n"
|
||||
[[ "$SELECTED_APPS" == *"zen-browser"* ]] && SUMMARY+=" ✦ zen-browser\n"
|
||||
[[ "$SELECTED_APPS" == *"nyxt"* ]] && SUMMARY+=" ✦ nyxt\n"
|
||||
[[ "$SELECTED_APPS" == *"librewolf"* ]] && SUMMARY+=" ✦ librewolf\n"
|
||||
[[ "$SELECTED_APPS" == *"min-browser"* ]] && SUMMARY+=" ✦ min-browser\n"
|
||||
[[ "$SELECTED_APPS" == *"vscodium"* ]] && SUMMARY+=" ✦ vscodium\n"
|
||||
[[ "$SELECTED_APPS" == *"zed-ide"* ]] && SUMMARY+=" ✦ zed-ide\n"
|
||||
[[ "$SELECTED_APPS" == *"geany"* ]] && SUMMARY+=" ✦ geany\n"
|
||||
[[ "$SELECTED_APPS" == *"codeblocks"* ]] && SUMMARY+=" ✦ codeblocks\n"
|
||||
[[ "$SELECTED_APPS" == *"kate"* ]] && SUMMARY+=" ✦ kate\n"
|
||||
[[ "$SELECTED_APPS" == *"rdp-client"* ]] && SUMMARY+=" ✦ rdp-client\n"
|
||||
[[ "$SELECTED_APPS" == *"lamco-rdp-server"* ]] && SUMMARY+=" ✦ lamco-rdp-server\n"
|
||||
[[ "$SELECTED_APPS" == *"qemu"* ]] && SUMMARY+=" ✦ qemu\n"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-client"* ]] && SUMMARY+=" ✦ freeipa-client\n"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-server"* ]] && SUMMARY+=" ✦ freeipa-server\n"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-image"* ]] && SUMMARY+=" ✦ freeipa-image\n"
|
||||
# END GENERATED MODULES: module-summary
|
||||
fi
|
||||
|
||||
# Size the confirmation dialog to the terminal, capped at 24 rows.
|
||||
|
|
@ -680,85 +686,94 @@ fi
|
|||
# Same guard pattern as base components. Each line is independent; a missing
|
||||
# module script will be caught by run_module()'s error handling rather than
|
||||
# silently skipped — 'bash "$script"' will exit non-zero if the file is absent.
|
||||
[[ "$SELECTED_APPS" == *"ollama"* ]] && run_module "Ollama" "$APPS/ollama.sh"
|
||||
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && run_module "llama.cpp" "$APPS/llama-cpp.sh"
|
||||
[[ "$SELECTED_APPS" == *"open-webui"* ]] && run_module "Open WebUI" "$APPS/open-webui.sh"
|
||||
[[ "$SELECTED_APPS" == *"claude"* ]] && run_module "Claude Code" "$APPS/claude.sh"
|
||||
[[ "$SELECTED_APPS" == *"networking-cli"* ]] && run_module "Networking CLI" "$APPS/networking-cli.sh"
|
||||
[[ "$SELECTED_APPS" == *"disk-recovery"* ]] && run_module "Disk Recovery" "$APPS/disk-recovery.sh"
|
||||
[[ "$SELECTED_APPS" == *"himalaya"* ]] && run_module "Himalaya" "$APPS/himalaya.sh"
|
||||
[[ "$SELECTED_APPS" == *"mail-notmuch"* ]] && run_module "Mail (notmuch)" "$APPS/mail-notmuch.sh"
|
||||
[[ "$SELECTED_APPS" == *"caldav-sync"* ]] && run_module "CalDAV Sync" "$APPS/caldav-sync.sh"
|
||||
[[ "$SELECTED_APPS" == *"gnuplot"* ]] && run_module "Gnuplot" "$APPS/gnuplot.sh"
|
||||
[[ "$SELECTED_APPS" == *"blender-povray"* ]] && run_module "Blender + POV-Ray" "$APPS/blender-povray.sh"
|
||||
[[ "$SELECTED_APPS" == *"toot"* ]] && run_module "toot" "$APPS/toot.sh"
|
||||
[[ "$SELECTED_APPS" == *"db-clients"* ]] && run_module "DB Clients" "$APPS/db-clients.sh"
|
||||
[[ "$SELECTED_APPS" == *"mysql"* ]] && run_module "MySQL / MariaDB" "$APPS/mysql.sh"
|
||||
[[ "$SELECTED_APPS" == *"productivity"* ]] && run_module "Productivity" "$APPS/productivity.sh"
|
||||
[[ "$SELECTED_APPS" == *"yt-dlp"* ]] && run_module "yt-dlp" "$APPS/yt-dlp.sh"
|
||||
[[ "$SELECTED_APPS" == *"sox"* ]] && run_module "SoX" "$APPS/sox.sh"
|
||||
[[ "$SELECTED_APPS" == *"imagemagick"* ]] && run_module "ImageMagick" "$APPS/imagemagick.sh"
|
||||
[[ "$SELECTED_APPS" == *"ffmpeg"* ]] && run_module "FFmpeg extras" "$APPS/ffmpeg.sh"
|
||||
[[ "$SELECTED_APPS" == *"localtunnel"* ]] && run_module "LocalTunnel" "$APPS/localtunnel.sh"
|
||||
[[ "$SELECTED_APPS" == *"butter"* ]] && run_module "butter" "$APPS/butter.sh"
|
||||
[[ "$SELECTED_APPS" == *"tlp"* ]] && run_module "TLP" "$APPS/tlp.sh"
|
||||
[[ "$SELECTED_APPS" == *"steam"* ]] && run_module "Steam" "$APPS/steam.sh"
|
||||
[[ "$SELECTED_APPS" == *"vesktop"* ]] && run_module "Vesktop" "$APPS/vesktop.sh"
|
||||
[[ "$SELECTED_APPS" == *"spotify"* ]] && run_module "Spotify" "$APPS/spotify.sh"
|
||||
[[ "$SELECTED_APPS" == *"prism"* ]] && run_module "PrismLauncher" "$APPS/prismlauncher.sh"
|
||||
[[ "$SELECTED_APPS" == *"vintagestory"* ]] && run_module "Vintage Story" "$APPS/vintagestory.sh"
|
||||
[[ "$SELECTED_APPS" == *"openarena"* ]] && run_module "OpenArena" "$APPS/openarena.sh"
|
||||
[[ "$SELECTED_APPS" == *"tetris"* ]] && run_module "Tetris CLI" "$APPS/tetris.sh"
|
||||
[[ "$SELECTED_APPS" == *"doom"* ]] && run_module "Doom" "$APPS/doom.sh"
|
||||
[[ "$SELECTED_APPS" == *"sauerbraten"* ]] && run_module "Sauerbraten" "$APPS/sauerbraten.sh"
|
||||
[[ "$SELECTED_APPS" == *"stuntrally"* ]] && run_module "Stunt Rally" "$APPS/stuntrally.sh"
|
||||
[[ "$SELECTED_APPS" == *"localsend"* ]] && run_module "LocalSend" "$APPS/localsend.sh"
|
||||
[[ "$SELECTED_APPS" == *"croc"* ]] && run_module "croc" "$APPS/croc.sh"
|
||||
[[ "$SELECTED_APPS" == *"opendeck"* ]] && run_module "OpenDeck" "$APPS/opendeck.sh"
|
||||
[[ "$SELECTED_APPS" == *"onlyoffice"* ]] && run_module "OnlyOffice" "$APPS/onlyoffice.sh"
|
||||
[[ "$SELECTED_APPS" == *"xournal"* ]] && run_module "Xournal++" "$APPS/xournal.sh"
|
||||
[[ "$SELECTED_APPS" == *"rnote"* ]] && run_module "Rnote" "$APPS/rnote.sh"
|
||||
[[ "$SELECTED_APPS" == *"obsidian"* ]] && run_module "Obsidian" "$APPS/obsidian.sh"
|
||||
[[ "$SELECTED_APPS" == *"tangent-notes"* ]] && run_module "Tangent Notes" "$APPS/tangent-notes.sh"
|
||||
[[ "$SELECTED_APPS" == *"gimp"* ]] && run_module "GIMP" "$APPS/gimp.sh"
|
||||
[[ "$SELECTED_APPS" == *"inkscape"* ]] && run_module "Inkscape" "$APPS/inkscape.sh"
|
||||
[[ "$SELECTED_APPS" == *"krita"* ]] && run_module "Krita" "$APPS/krita.sh"
|
||||
[[ "$SELECTED_APPS" == *"ardour"* ]] && run_module "Ardour" "$APPS/ardour.sh"
|
||||
[[ "$SELECTED_APPS" == *"audacity"* ]] && run_module "Audacity" "$APPS/audacity.sh"
|
||||
[[ "$SELECTED_APPS" == *"lmms"* ]] && run_module "LMMS" "$APPS/lmms.sh"
|
||||
[[ "$SELECTED_APPS" == *"mixxx"* ]] && run_module "Mixxx" "$APPS/mixxx.sh"
|
||||
[[ "$SELECTED_APPS" == *"cecilia"* ]] && run_module "Cecilia" "$APPS/cecilia.sh"
|
||||
[[ "$SELECTED_APPS" == *"kdenlive"* ]] && run_module "Kdenlive" "$APPS/kdenlive.sh"
|
||||
[[ "$SELECTED_APPS" == *"openshot"* ]] && run_module "OpenShot" "$APPS/openshot.sh"
|
||||
[[ "$SELECTED_APPS" == *"shotcut"* ]] && run_module "Shotcut" "$APPS/shotcut.sh"
|
||||
[[ "$SELECTED_APPS" == *"anti-malware"* ]] && run_module "Anti-Malware" "$APPS/anti-malware.sh"
|
||||
[[ "$SELECTED_APPS" == *"timeshift"* ]] && run_module "Timeshift" "$APPS/timeshift.sh"
|
||||
[[ "$SELECTED_APPS" == *"wireshark"* ]] && run_module "Wireshark" "$APPS/wireshark.sh"
|
||||
[[ "$SELECTED_APPS" == *"k8s"* ]] && run_module "Kubernetes Tools" "$APPS/k8s.sh"
|
||||
[[ "$SELECTED_APPS" == *"docker"* ]] && run_module "Docker" "$APPS/docker.sh"
|
||||
[[ "$SELECTED_APPS" == *"podman"* ]] && run_module "Podman" "$APPS/podman.sh"
|
||||
[[ "$SELECTED_APPS" == *"cockpit"* ]] && run_module "Cockpit" "$APPS/cockpit.sh"
|
||||
[[ "$SELECTED_APPS" == *"ssh-server"* ]] && run_module "SSH Server" "$APPS/ssh-server.sh"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-client"* ]] && run_module "FreeIPA Client" "$APPS/freeipa-client.sh"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-server"* ]] && run_module "FreeIPA Server" "$APPS/freeipa-server.sh"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-image"* ]] && run_module "FreeIPA Image" "$APPS/freeipa-image-builder.sh"
|
||||
[[ "$SELECTED_APPS" == *"python"* ]] && run_module "Python Tools" "$MODULES/optional-Modules/python.sh"
|
||||
[[ "$SELECTED_APPS" == *"zfs"* ]] && run_module "ZFS" "$MODULES/optional-Modules/zfs.sh"
|
||||
[[ "$SELECTED_APPS" == *"wprs"* ]] && run_module "WPRS" "$MODULES/optional-Modules/wprs.sh"
|
||||
[[ "$SELECTED_APPS" == *"chromium"* ]] && run_module "Chromium" "$APPS/chromium.sh"
|
||||
[[ "$SELECTED_APPS" == *"firefox-browser"* ]] && run_module "Firefox" "$APPS/firefox.sh"
|
||||
[[ "$SELECTED_APPS" == *"zen-browser"* ]] && run_module "Zen Browser" "$APPS/zen-browser.sh"
|
||||
[[ "$SELECTED_APPS" == *"nyxt"* ]] && run_module "Nyxt" "$APPS/nyxt.sh"
|
||||
[[ "$SELECTED_APPS" == *"librewolf"* ]] && run_module "LibreWolf" "$APPS/librewolf.sh"
|
||||
[[ "$SELECTED_APPS" == *"min-browser"* ]] && run_module "Min Browser" "$APPS/min-browser.sh"
|
||||
[[ "$SELECTED_APPS" == *"vscodium"* ]] && run_module "VSCodium" "$APPS/vscodium.sh"
|
||||
[[ "$SELECTED_APPS" == *"zed-ide"* ]] && run_module "Zed IDE" "$APPS/zed.sh"
|
||||
[[ "$SELECTED_APPS" == *"geany"* ]] && run_module "Geany" "$APPS/geany.sh"
|
||||
[[ "$SELECTED_APPS" == *"codeblocks"* ]] && run_module "Code::Blocks" "$APPS/codeblocks.sh"
|
||||
[[ "$SELECTED_APPS" == *"kate"* ]] && run_module "Kate" "$APPS/kate.sh"
|
||||
[[ "$SELECTED_APPS" == *"rdp-client"* ]] && run_module "RDP Client" "$APPS/rdp-client.sh"
|
||||
[[ "$SELECTED_APPS" == *"lamco-rdp-server"* ]] && run_module "Lamco RDP Server" "$APPS/lamco-rdp-server.sh"
|
||||
[[ "$SELECTED_APPS" == *"qemu"* ]] && run_module "QEMU/KVM" "$APPS/qemu.sh"
|
||||
# BEGIN GENERATED MODULES: module-conflicts
|
||||
if [[ "$SELECTED_APPS" == *"plymouth-custom"* && "$SELECTED_APPS" == *"plymouth"* ]]; then
|
||||
warn "plymouth-custom and plymouth are mutually exclusive — skipping plymouth"
|
||||
SELECTED_APPS="${SELECTED_APPS/plymouth/}"
|
||||
fi
|
||||
# END GENERATED MODULES: module-conflicts
|
||||
# BEGIN GENERATED MODULES: module-dispatch
|
||||
[[ "$SELECTED_APPS" == *"ollama"* ]] && run_module "ollama" "$APPS/ollama.sh"
|
||||
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && run_module "llama-cpp" "$APPS/llama-cpp.sh"
|
||||
[[ "$SELECTED_APPS" == *"open-webui"* ]] && run_module "open-webui" "$APPS/open-webui.sh"
|
||||
[[ "$SELECTED_APPS" == *"claude"* ]] && run_module "claude" "$APPS/claude.sh"
|
||||
[[ "$SELECTED_APPS" == *"networking-cli"* ]] && run_module "networking-cli" "$APPS/networking-cli.sh"
|
||||
[[ "$SELECTED_APPS" == *"disk-recovery"* ]] && run_module "disk-recovery" "$APPS/disk-recovery.sh"
|
||||
[[ "$SELECTED_APPS" == *"himalaya"* ]] && run_module "himalaya" "$APPS/himalaya.sh"
|
||||
[[ "$SELECTED_APPS" == *"mail-notmuch"* ]] && run_module "mail-notmuch" "$APPS/mail-notmuch.sh"
|
||||
[[ "$SELECTED_APPS" == *"caldav-sync"* ]] && run_module "caldav-sync" "$APPS/caldav-sync.sh"
|
||||
[[ "$SELECTED_APPS" == *"ssh-server"* ]] && run_module "ssh-server" "$APPS/ssh-server.sh"
|
||||
[[ "$SELECTED_APPS" == *"wireshark"* ]] && run_module "wireshark" "$APPS/wireshark.sh"
|
||||
[[ "$SELECTED_APPS" == *"anti-malware"* ]] && run_module "anti-malware" "$APPS/anti-malware.sh"
|
||||
[[ "$SELECTED_APPS" == *"gnuplot"* ]] && run_module "gnuplot" "$APPS/gnuplot.sh"
|
||||
[[ "$SELECTED_APPS" == *"blender-povray"* ]] && run_module "blender-povray" "$APPS/blender-povray.sh"
|
||||
[[ "$SELECTED_APPS" == *"toot"* ]] && run_module "toot" "$APPS/toot.sh"
|
||||
[[ "$SELECTED_APPS" == *"db-clients"* ]] && run_module "db-clients" "$APPS/db-clients.sh"
|
||||
[[ "$SELECTED_APPS" == *"mysql"* ]] && run_module "mysql" "$APPS/mysql.sh"
|
||||
[[ "$SELECTED_APPS" == *"productivity"* ]] && run_module "productivity" "$APPS/productivity.sh"
|
||||
[[ "$SELECTED_APPS" == *"python"* ]] && run_module "python" "$APPS/python.sh"
|
||||
[[ "$SELECTED_APPS" == *"k8s"* ]] && run_module "k8s" "$APPS/k8s.sh"
|
||||
[[ "$SELECTED_APPS" == *"docker"* ]] && run_module "docker" "$APPS/docker.sh"
|
||||
[[ "$SELECTED_APPS" == *"podman"* ]] && run_module "podman" "$APPS/podman.sh"
|
||||
[[ "$SELECTED_APPS" == *"cockpit"* ]] && run_module "cockpit" "$APPS/cockpit.sh"
|
||||
[[ "$SELECTED_APPS" == *"tlp"* ]] && run_module "tlp" "$APPS/tlp.sh"
|
||||
[[ "$SELECTED_APPS" == *"butter"* ]] && run_module "butter" "$APPS/butter.sh"
|
||||
[[ "$SELECTED_APPS" == *"localsend"* ]] && run_module "localsend" "$APPS/localsend.sh"
|
||||
[[ "$SELECTED_APPS" == *"croc"* ]] && run_module "croc" "$APPS/croc.sh"
|
||||
[[ "$SELECTED_APPS" == *"opendeck"* ]] && run_module "opendeck" "$APPS/opendeck.sh"
|
||||
[[ "$SELECTED_APPS" == *"localtunnel"* ]] && run_module "localtunnel" "$APPS/localtunnel.sh"
|
||||
[[ "$SELECTED_APPS" == *"timeshift"* ]] && run_module "timeshift" "$APPS/timeshift.sh"
|
||||
[[ "$SELECTED_APPS" == *"zfs"* ]] && run_module "zfs" "$APPS/zfs.sh"
|
||||
[[ "$SELECTED_APPS" == *"wprs"* ]] && run_module "wprs" "$APPS/wprs.sh"
|
||||
[[ "$SELECTED_APPS" == *"plymouth-custom"* ]] && run_module "plymouth-custom" "$APPS/plymouth-custom.sh"
|
||||
[[ "$SELECTED_APPS" == *"steam"* ]] && run_module "steam" "$APPS/steam.sh"
|
||||
[[ "$SELECTED_APPS" == *"vesktop"* ]] && run_module "vesktop" "$APPS/vesktop.sh"
|
||||
[[ "$SELECTED_APPS" == *"spotify"* ]] && run_module "spotify" "$APPS/spotify.sh"
|
||||
[[ "$SELECTED_APPS" == *"prism"* ]] && run_module "prism" "$APPS/prism.sh"
|
||||
[[ "$SELECTED_APPS" == *"vintagestory"* ]] && run_module "vintagestory" "$APPS/vintagestory.sh"
|
||||
[[ "$SELECTED_APPS" == *"openarena"* ]] && run_module "openarena" "$APPS/openarena.sh"
|
||||
[[ "$SELECTED_APPS" == *"tetris"* ]] && run_module "tetris" "$APPS/tetris.sh"
|
||||
[[ "$SELECTED_APPS" == *"doom"* ]] && run_module "doom" "$APPS/doom.sh"
|
||||
[[ "$SELECTED_APPS" == *"sauerbraten"* ]] && run_module "sauerbraten" "$APPS/sauerbraten.sh"
|
||||
[[ "$SELECTED_APPS" == *"stuntrally"* ]] && run_module "stuntrally" "$APPS/stuntrally.sh"
|
||||
[[ "$SELECTED_APPS" == *"onlyoffice"* ]] && run_module "onlyoffice" "$APPS/onlyoffice.sh"
|
||||
[[ "$SELECTED_APPS" == *"xournal"* ]] && run_module "xournal" "$APPS/xournal.sh"
|
||||
[[ "$SELECTED_APPS" == *"rnote"* ]] && run_module "rnote" "$APPS/rnote.sh"
|
||||
[[ "$SELECTED_APPS" == *"obsidian"* ]] && run_module "obsidian" "$APPS/obsidian.sh"
|
||||
[[ "$SELECTED_APPS" == *"tangent-notes"* ]] && run_module "tangent-notes" "$APPS/tangent-notes.sh"
|
||||
[[ "$SELECTED_APPS" == *"ffmpeg"* ]] && run_module "ffmpeg" "$APPS/ffmpeg.sh"
|
||||
[[ "$SELECTED_APPS" == *"sox"* ]] && run_module "sox" "$APPS/sox.sh"
|
||||
[[ "$SELECTED_APPS" == *"imagemagick"* ]] && run_module "imagemagick" "$APPS/imagemagick.sh"
|
||||
[[ "$SELECTED_APPS" == *"yt-dlp"* ]] && run_module "yt-dlp" "$APPS/yt-dlp.sh"
|
||||
[[ "$SELECTED_APPS" == *"gimp"* ]] && run_module "gimp" "$APPS/gimp.sh"
|
||||
[[ "$SELECTED_APPS" == *"inkscape"* ]] && run_module "inkscape" "$APPS/inkscape.sh"
|
||||
[[ "$SELECTED_APPS" == *"krita"* ]] && run_module "krita" "$APPS/krita.sh"
|
||||
[[ "$SELECTED_APPS" == *"kdenlive"* ]] && run_module "kdenlive" "$APPS/kdenlive.sh"
|
||||
[[ "$SELECTED_APPS" == *"openshot"* ]] && run_module "openshot" "$APPS/openshot.sh"
|
||||
[[ "$SELECTED_APPS" == *"shotcut"* ]] && run_module "shotcut" "$APPS/shotcut.sh"
|
||||
[[ "$SELECTED_APPS" == *"ardour"* ]] && run_module "ardour" "$APPS/ardour.sh"
|
||||
[[ "$SELECTED_APPS" == *"audacity"* ]] && run_module "audacity" "$APPS/audacity.sh"
|
||||
[[ "$SELECTED_APPS" == *"lmms"* ]] && run_module "lmms" "$APPS/lmms.sh"
|
||||
[[ "$SELECTED_APPS" == *"mixxx"* ]] && run_module "mixxx" "$APPS/mixxx.sh"
|
||||
[[ "$SELECTED_APPS" == *"cecilia"* ]] && run_module "cecilia" "$APPS/cecilia.sh"
|
||||
[[ "$SELECTED_APPS" == *"chromium"* ]] && run_module "chromium" "$APPS/chromium.sh"
|
||||
[[ "$SELECTED_APPS" == *"firefox-browser"* ]] && run_module "firefox-browser" "$APPS/firefox-browser.sh"
|
||||
[[ "$SELECTED_APPS" == *"zen-browser"* ]] && run_module "zen-browser" "$APPS/zen-browser.sh"
|
||||
[[ "$SELECTED_APPS" == *"nyxt"* ]] && run_module "nyxt" "$APPS/nyxt.sh"
|
||||
[[ "$SELECTED_APPS" == *"librewolf"* ]] && run_module "librewolf" "$APPS/librewolf.sh"
|
||||
[[ "$SELECTED_APPS" == *"min-browser"* ]] && run_module "min-browser" "$APPS/min-browser.sh"
|
||||
[[ "$SELECTED_APPS" == *"vscodium"* ]] && run_module "vscodium" "$APPS/vscodium.sh"
|
||||
[[ "$SELECTED_APPS" == *"zed-ide"* ]] && run_module "zed-ide" "$APPS/zed-ide.sh"
|
||||
[[ "$SELECTED_APPS" == *"geany"* ]] && run_module "geany" "$APPS/geany.sh"
|
||||
[[ "$SELECTED_APPS" == *"codeblocks"* ]] && run_module "codeblocks" "$APPS/codeblocks.sh"
|
||||
[[ "$SELECTED_APPS" == *"kate"* ]] && run_module "kate" "$APPS/kate.sh"
|
||||
[[ "$SELECTED_APPS" == *"rdp-client"* ]] && run_module "rdp-client" "$APPS/rdp-client.sh"
|
||||
[[ "$SELECTED_APPS" == *"lamco-rdp-server"* ]] && run_module "lamco-rdp-server" "$APPS/lamco-rdp-server.sh"
|
||||
[[ "$SELECTED_APPS" == *"qemu"* ]] && run_module "qemu" "$APPS/qemu.sh"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-client"* ]] && run_module "freeipa-client" "$APPS/freeipa-client.sh"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-server"* ]] && run_module "freeipa-server" "$APPS/freeipa-server.sh"
|
||||
[[ "$SELECTED_APPS" == *"freeipa-image"* ]] && run_module "freeipa-image" "$APPS/freeipa-image.sh"
|
||||
# END GENERATED MODULES: module-dispatch
|
||||
|
||||
# ── Colorway (final step) ─────────────────────────────────────────────────────
|
||||
# Read defaults from repo colors.conf for pre-population.
|
||||
|
|
|
|||
Loading…
Reference in New Issue