Compare commits
No commits in common. "5d7c97409beaba3410503a5f21f23841b9b20719" and "2be85739b519b08e330622f3a2768fa45615260b" have entirely different histories.
5d7c97409b
...
2be85739b5
|
|
@ -84,175 +84,31 @@ Install via `tui-install.sh` at first install, or add later:
|
||||||
bash ~/Dotfiles/setup/install-modules.sh
|
bash ~/Dotfiles/setup/install-modules.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
> This table is generated from `setup/modules.conf`. Run `setup/generate-modules.sh` to regenerate.
|
|
||||||
|
|
||||||
### AI & Machine Learning
|
### AI & Machine Learning
|
||||||
|
|
||||||
<!-- BEGIN GENERATED MODULES: ai -->
|
| ID | Package | Description |
|
||||||
| ID | Description |
|
|----|---------|-------------|
|
||||||
|----|-------------|
|
| `ollama` | ollama | Local LLM runner with REST API server |
|
||||||
| `ollama` | local LLM runner and API server |
|
| `llama-cpp` | llama.cpp | Standalone inference CLI + server |
|
||||||
| `llama-cpp` | standalone LLM inference CLI and server |
|
| `open-webui` | open-webui | Browser UI for Ollama / OpenAI-compatible backends |
|
||||||
| `open-webui` | browser UI for Ollama and LLM backends |
|
| `claude` | claude (npm) | Anthropic Claude Code CLI |
|
||||||
| `claude` | Anthropic Claude Code CLI via npm |
|
|
||||||
<!-- END GENERATED MODULES: ai -->
|
|
||||||
|
|
||||||
### Networking & Security
|
### Networking & Security
|
||||||
|
|
||||||
<!-- BEGIN GENERATED MODULES: networking -->
|
| ID | Packages | Description |
|
||||||
| ID | Description |
|
|----|---------|-------------|
|
||||||
|----|-------------|
|
| `networking-cli` | nmap · nethogs · mitmproxy · httpie | Network analysis and HTTP tooling |
|
||||||
| `networking-cli` | nmap, nethogs, mitmproxy, httpie |
|
| `disk-recovery` | ddrescue · f3 | Disk imaging and flash drive testing |
|
||||||
| `disk-recovery` | ddrescue and f3 disk recovery tools |
|
| `ssh-server` | openssh | SSH daemon with key-auth enforcement |
|
||||||
| `himalaya` | terminal email client (AUR) |
|
| `wireshark` | wireshark-qt | Packet capture and analysis GUI |
|
||||||
| `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
|
### Virtualisation & Remote Desktop
|
||||||
|
|
||||||
<!-- BEGIN GENERATED MODULES: virt -->
|
| ID | Packages | Description |
|
||||||
| ID | 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 with FreeRDP and VNC plugins |
|
| `rdp-client` | remmina · freerdp · libvncserver | Remmina remote desktop client with RDP (FreeRDP) and VNC support |
|
||||||
| `lamco-rdp-server` | native Wayland RDP server (AUR, Rust) |
|
| `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 |
|
||||||
| `qemu` | full QEMU/KVM stack with virt-manager |
|
|
||||||
<!-- END GENERATED MODULES: virt -->
|
|
||||||
|
|
||||||
**lamco-rdp-server notes:**
|
**lamco-rdp-server notes:**
|
||||||
- Enabled as a user service: `systemctl --user enable lamco-rdp-server.service`
|
- Enabled as a user service: `systemctl --user enable lamco-rdp-server.service`
|
||||||
|
|
@ -260,15 +116,122 @@ bash ~/Dotfiles/setup/install-modules.sh
|
||||||
- Optional GUI tray: `lamco-rdp-server-gui`
|
- Optional GUI tray: `lamco-rdp-server-gui`
|
||||||
- Requires an `xdg-desktop-portal` matching your compositor (`-hyprland`, `-wlr`, `-gnome`, `-kde`)
|
- 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
|
### Identity & Infrastructure
|
||||||
|
|
||||||
<!-- BEGIN GENERATED MODULES: infra -->
|
|
||||||
| ID | Description |
|
| ID | Description |
|
||||||
|----|-------------|
|
|----|-------------|
|
||||||
| `freeipa-client` | sssd and ipa-client-install with auto-enrollment |
|
| `freeipa-client` | sssd + ipa-client-install + auto-enrollment (see [FreeIPA](freeipa-ansible.md)) |
|
||||||
| `freeipa-server` | interactive FreeIPA server setup with client generator |
|
| `freeipa-server` | Interactive FreeIPA server setup + client generator |
|
||||||
| `freeipa-image` | OCI/LXC/Proxmox image builder with Keycloak |
|
| `freeipa-image` | OCI / LXC / Proxmox LXC image builder + Keycloak |
|
||||||
<!-- END GENERATED MODULES: infra -->
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,92 +216,89 @@ if [[ "$AF_RUN_TUI" == "true" ]]; then
|
||||||
3>&1 1>&2 2>&3) || AF_DE="none"
|
3>&1 1>&2 2>&3) || AF_DE="none"
|
||||||
|
|
||||||
# ── Apps ──────────────────────────────────────────────────────────────────
|
# ── Apps ──────────────────────────────────────────────────────────────────
|
||||||
# BEGIN GENERATED MODULES: module-checklist
|
|
||||||
AF_APPS=$(dialog --backtitle "$BACKTITLE" \
|
AF_APPS=$(dialog --backtitle "$BACKTITLE" \
|
||||||
--title " Applications " \
|
--title " Applications " \
|
||||||
--checklist "Optional applications — installed after base components:" 40 76 80 \
|
--checklist "Optional applications — installed after base components:" 40 76 32 \
|
||||||
"ollama" "ollama local LLM runner and API server" off \
|
"ollama" "Ollama local LLM runner + API server" off \
|
||||||
"llama-cpp" "llama-cpp standalone LLM inference CLI and server" off \
|
"llama-cpp" "llama.cpp standalone inference CLI + server" off \
|
||||||
"open-webui" "open-webui browser UI for Ollama and LLM backends" off \
|
"open-webui" "Open WebUI browser UI for Ollama / LLM backends" off \
|
||||||
"claude" "claude Anthropic Claude Code CLI via npm" off \
|
"claude" "Claude Code Anthropic CLI via npm" off \
|
||||||
"networking-cli" "networking-cli nmap, nethogs, mitmproxy, httpie" off \
|
"networking-cli" "Networking CLI nmap · nethogs · mitmproxy · httpie" off \
|
||||||
"disk-recovery" "disk-recovery ddrescue and f3 disk recovery tools" off \
|
"disk-recovery" "Disk Recovery ddrescue · f3" off \
|
||||||
"himalaya" "himalaya terminal email client (AUR)" off \
|
"himalaya" "Himalaya terminal email client (AUR)" off \
|
||||||
"mail-notmuch" "mail-notmuch isync, msmtp, notmuch, alot mail stack" off \
|
"mail-notmuch" "Mail (notmuch) isync · msmtp · notmuch · alot stack" off \
|
||||||
"caldav-sync" "caldav-sync vdirsyncer and khal CalDAV calendar sync" off \
|
"caldav-sync" "CalDAV Sync vdirsyncer · khal calendar sync" off \
|
||||||
"ssh-server" "ssh-server openssh with key-auth and systemd unit enabled" off \
|
"gnuplot" "Gnuplot scientific plotting" off \
|
||||||
"wireshark" "wireshark network packet analyser GUI" off \
|
"blender-povray" "Blender + POV-Ray 3D modelling & ray-tracing" 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 \
|
"toot" "toot Mastodon CLI client (AUR)" off \
|
||||||
"db-clients" "db-clients pgcli and mycli interactive database CLIs" off \
|
"db-clients" "DB Clients pgcli · mycli" off \
|
||||||
"mysql" "mysql MariaDB server with initial setup" off \
|
"mysql" "MySQL / MariaDB mariadb server + setup" off \
|
||||||
"productivity" "productivity taskwarrior, watson, jrnl — task management and time tracking" off \
|
"productivity" "Productivity taskwarrior · watson · jrnl" off \
|
||||||
"python" "python pyright, pipx, pynvim Python tooling" on \
|
"yt-dlp" "yt-dlp YouTube / media downloader" off \
|
||||||
"k8s" "k8s kubectl and podman-desktop Kubernetes tools" off \
|
"sox" "SoX audio processing toolkit" off \
|
||||||
"docker" "docker docker and docker-compose" off \
|
"imagemagick" "ImageMagick image manipulation" off \
|
||||||
"podman" "podman rootless containers with buildah" off \
|
"ffmpeg" "FFmpeg extras thumbnailer · GStreamer codecs" off \
|
||||||
"cockpit" "cockpit web UI for machines and containers" off \
|
"localtunnel" "LocalTunnel expose localhost via tunnel" off \
|
||||||
"tlp" "tlp laptop battery optimisation" off \
|
"butter" "butter btrfs snapshot backup (AUR)" off \
|
||||||
"butter" "butter btrfs snapshot backup manager (AUR)" off \
|
"tlp" "TLP laptop power management" off \
|
||||||
"localsend" "localsend LAN file transfer, AirDrop-like (AUR)" off \
|
"steam" "Steam gaming platform" off \
|
||||||
"croc" "croc cross-platform encrypted file transfer" off \
|
"vesktop" "Vesktop Discord + Vencord theme" off \
|
||||||
"opendeck" "opendeck Stream Deck controller — ydotool + OpenDeck (Flatpak)" off \
|
"spotify" "Spotify launcher + Spicetify theming" off \
|
||||||
"localtunnel" "localtunnel expose localhost over a public URL" off \
|
"prism" "PrismLauncher Minecraft launcher (Flatpak)" off \
|
||||||
"timeshift" "timeshift system snapshot and backup with autosnap" off \
|
"vintagestory" "Vintage Story survival game (AUR)" off \
|
||||||
"zfs" "zfs zfs-dkms kernel module" off \
|
"openarena" "OpenArena open-source Quake III Arena" off \
|
||||||
"wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \
|
"tetris" "Tetris CLI bastet · vitetris" off \
|
||||||
"plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \
|
"doom" "Doom Chocolate Doom + Freedoom data" off \
|
||||||
"steam" "steam Steam gaming platform" off \
|
"sauerbraten" "Sauerbraten open-source FPS (Cube 2)" off \
|
||||||
"vesktop" "vesktop Discord client with Vencord theme" off \
|
"stuntrally" "Stunt Rally rally racing game (Flatpak)" off \
|
||||||
"spotify" "spotify Spotify launcher with Spicetify theming" off \
|
"localsend" "LocalSend LAN file transfer (AUR)" off \
|
||||||
"prism" "prism PrismLauncher Minecraft launcher (Flatpak)" off \
|
"croc" "croc cross-platform file transfer" off \
|
||||||
"vintagestory" "vintagestory Vintage Story survival game (AUR)" off \
|
"opendeck" "OpenDeck Stream Deck controller (Flatpak+ydotool)" off \
|
||||||
"openarena" "openarena open-source Quake III Arena" off \
|
"onlyoffice" "OnlyOffice office suite (AUR)" off \
|
||||||
"tetris" "tetris bastet and vitetris terminal Tetris" off \
|
"xournal" "Xournal++ note-taking & PDF annotator" off \
|
||||||
"doom" "doom Chocolate Doom with Freedoom data" off \
|
"rnote" "Rnote handwriting & note-taking (Flatpak)" off \
|
||||||
"sauerbraten" "sauerbraten Sauerbraten open-source FPS (Cube 2)" off \
|
"obsidian" "Obsidian knowledge base & Markdown notes (Flatpak)" off \
|
||||||
"stuntrally" "stuntrally Stunt Rally racing game (Flatpak)" off \
|
"tangent-notes" "Tangent Notes networked Markdown notes (Flatpak)" off \
|
||||||
"onlyoffice" "onlyoffice office suite — Docs, Sheets, Slides (AUR)" on \
|
"gimp" "GIMP GNU image manipulation program" off \
|
||||||
"xournal" "xournal note-taking and PDF annotator" off \
|
"inkscape" "Inkscape vector graphics editor" off \
|
||||||
"rnote" "rnote handwriting and note-taking with stylus support (Flatpak)" off \
|
"krita" "Krita digital painting application" off \
|
||||||
"obsidian" "obsidian knowledge base and Markdown note-taking (Flatpak)" off \
|
"ardour" "Ardour professional DAW" off \
|
||||||
"tangent-notes" "tangent-notes networked Markdown note-taking (Flatpak)" off \
|
"audacity" "Audacity multi-track audio editor" off \
|
||||||
"ffmpeg" "ffmpeg GStreamer codecs and ffmpegthumbnailer" off \
|
"lmms" "LMMS Linux MultiMedia Studio DAW" off \
|
||||||
"sox" "sox command-line audio processing toolkit" off \
|
"mixxx" "Mixxx DJ mixing software" off \
|
||||||
"imagemagick" "imagemagick image manipulation suite" off \
|
"cecilia" "Cecilia audio signal processing (AUR)" off \
|
||||||
"yt-dlp" "yt-dlp YouTube and media downloader" off \
|
"kdenlive" "Kdenlive KDE non-linear video editor" off \
|
||||||
"gimp" "gimp GNU Image Manipulation Program" off \
|
"openshot" "OpenShot easy video editor" off \
|
||||||
"inkscape" "inkscape vector graphics editor" off \
|
"shotcut" "Shotcut cross-platform video editor" off \
|
||||||
"krita" "krita digital painting and illustration" off \
|
"anti-malware" "Anti-Malware ClamAV · rkhunter · chkrootkit" off \
|
||||||
"kdenlive" "kdenlive KDE non-linear video editor" off \
|
"timeshift" "Timeshift system snapshot / backup + autosnap" off \
|
||||||
"openshot" "openshot cross-platform video editor" off \
|
"wireshark" "Wireshark network packet analyser (GUI)" off \
|
||||||
"shotcut" "shotcut cross-platform video editor" off \
|
"k8s" "Kubernetes tools kubectl · podman-desktop" off \
|
||||||
"ardour" "ardour professional DAW" off \
|
"docker" "Docker docker · docker-compose" off \
|
||||||
"audacity" "audacity multi-track audio editor" off \
|
"podman" "Podman rootless containers · buildah" off \
|
||||||
"lmms" "lmms Linux MultiMedia Studio music production" off \
|
"cockpit" "Cockpit web UI · machines · podman" off \
|
||||||
"mixxx" "mixxx DJ mixing software" off \
|
"ssh-server" "SSH server openssh · key-auth · enabled" off \
|
||||||
"cecilia" "cecilia audio synthesis and signal processing (AUR)" off \
|
"freeipa-client" "FreeIPA Client sssd + ipa-client-install + enrollment" off \
|
||||||
"chromium" "chromium open-source Chromium browser (official)" off \
|
"freeipa-server" "FreeIPA Server interactive server setup + client gen" off \
|
||||||
"firefox-browser" "firefox-browser Mozilla Firefox (official)" on \
|
"freeipa-image" "FreeIPA Image OCI/LXC/Proxmox LXC builder + Keycloak" off \
|
||||||
"zen-browser" "zen-browser privacy-focused Firefox fork (AUR)" off \
|
"python" "Python tools pyright · pipx · pynvim" off \
|
||||||
"nyxt" "nyxt keyboard-driven hackable browser (AUR)" off \
|
"zfs" "ZFS zfs-dkms kernel module" off \
|
||||||
"librewolf" "librewolf hardened Firefox fork (AUR)" off \
|
"wprs" "WPRS wprs-git (AUR)" off \
|
||||||
"min-browser" "min-browser minimal Electron browser (AUR)" off \
|
"chromium" "Chromium open-source browser (official)" off \
|
||||||
"vscodium" "vscodium telemetry-free VS Code build (AUR)" off \
|
"firefox-browser" "Firefox Mozilla browser (official)" off \
|
||||||
"zed-ide" "zed-ide high-performance Rust IDE (official)" off \
|
"zen-browser" "Zen Browser Firefox-based privacy browser (AUR)" off \
|
||||||
"geany" "geany lightweight IDE with plugins (official)" off \
|
"nyxt" "Nyxt keyboard-driven browser (AUR)" off \
|
||||||
"codeblocks" "codeblocks C/C++ IDE (official)" off \
|
"librewolf" "LibreWolf hardened Firefox fork (AUR)" off \
|
||||||
"kate" "kate KDE advanced text editor (official)" off \
|
"min-browser" "Min minimal Electron browser (AUR)" off \
|
||||||
"rdp-client" "rdp-client Remmina with FreeRDP and VNC plugins" off \
|
"vscodium" "VSCodium telemetry-free VS Code (AUR)" off \
|
||||||
"lamco-rdp-server" "lamco-rdp-server native Wayland RDP server (AUR, Rust)" off \
|
"zed-ide" "Zed high-performance Rust IDE (official)" off \
|
||||||
"qemu" "qemu full QEMU/KVM stack with virt-manager" off \
|
"geany" "Geany lightweight IDE + plugins (official)" off \
|
||||||
"freeipa-client" "freeipa-client sssd and ipa-client-install with auto-enrollment" off \
|
"codeblocks" "Code::Blocks C/C++ IDE (official)" off \
|
||||||
"freeipa-server" "freeipa-server interactive FreeIPA server setup with client generator" off \
|
"kate" "Kate KDE advanced text editor (official)" off \
|
||||||
"freeipa-image" "freeipa-image OCI/LXC/Proxmox image builder with Keycloak" 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 \
|
||||||
3>&1 1>&2 2>&3) || AF_APPS=""
|
3>&1 1>&2 2>&3) || AF_APPS=""
|
||||||
# END GENERATED MODULES: module-checklist
|
|
||||||
|
|
||||||
# ── Shell RC preference ───────────────────────────────────────────────────
|
# ── Shell RC preference ───────────────────────────────────────────────────
|
||||||
AF_SHELL_RC=$(dialog --backtitle "$BACKTITLE" \
|
AF_SHELL_RC=$(dialog --backtitle "$BACKTITLE" \
|
||||||
|
|
|
||||||
|
|
@ -1,234 +0,0 @@
|
||||||
#!/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."
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
# 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,31 +5,32 @@
|
||||||
# leaving the group removes it on the next run (every 30 min via systemd timer).
|
# 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):
|
# Host-group naming conventions (device policies — applied to the whole machine):
|
||||||
# dev_daemon-enable-<unit> Ensure <unit> is enabled and running (systemctl enable --now).
|
# policy-daemon-enable-<unit> Ensure <unit> is enabled and running (systemctl enable --now).
|
||||||
# Leaving the group reverts: service is disabled and stopped.
|
# Leaving the group reverts: service is disabled and stopped.
|
||||||
# dev_daemon-disable-<unit> Ensure <unit> is disabled and stopped (systemctl disable --now).
|
# policy-daemon-disable-<unit> Ensure <unit> is disabled and stopped (systemctl disable --now).
|
||||||
# Leaving the group reverts: service is re-enabled and started.
|
# Leaving the group reverts: service is re-enabled and started.
|
||||||
# <unit> may omit the .service suffix; all systemd unit types work.
|
# <unit> may omit the .service suffix; all systemd unit types work.
|
||||||
# If a unit appears in both enable and disable groups it is skipped.
|
# If a unit appears in both enable and disable groups it is skipped.
|
||||||
# dev_timeshift-backup Enforce a daily Timeshift snapshot (requires timeshift installed)
|
# policy-timeshift-backup Enforce a daily Timeshift snapshot (requires timeshift installed)
|
||||||
# dev_security-scan Enforce daily ClamAV + rkhunter + chkrootkit scans
|
# policy-security-scan Enforce daily ClamAV + rkhunter + chkrootkit scans
|
||||||
# dev_no-local-users Lock passwords for root and all local users (UID >= 1000) so
|
# 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
|
# that only FreeIPA domain accounts with centrally-managed sudo
|
||||||
# rules can authenticate and gain elevated privileges.
|
# rules can authenticate and gain elevated privileges.
|
||||||
# Leaving the group reverts: every account locked by this policy
|
# Leaving the group reverts: every account locked by this policy
|
||||||
# is unlocked on the next run.
|
# is unlocked on the next run.
|
||||||
# dev_local-sudo-<username> Grant <username> full sudo on this specific device by adding
|
# local_sudo_<username> Grant <username> full sudo on this specific device by adding
|
||||||
# them to the local sudoers drop-in. Leaving the group removes
|
# them to the local sudoers drop-in. Leaving the group removes
|
||||||
# the drop-in on the next run.
|
# the drop-in on the next run.
|
||||||
#
|
#
|
||||||
# User-group naming conventions (per-user policies — follow the user across devices):
|
# User-group naming conventions (per-user policies — follow the user across devices):
|
||||||
# usr_block-binary-<name> Prevent members of this FreeIPA user group from running <name>
|
# 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
|
# on any enrolled host. Use __ in place of . to support Flatpak
|
||||||
# app IDs (e.g. usr_block-binary-org__gimp__Gimp blocks the
|
# app IDs (e.g. policy-block-binary-org__gimp__Gimp blocks the
|
||||||
# Flatpak org.gimp.Gimp). Enforced via a PATH-priority wrapper
|
# Flatpak org.gimp.Gimp). Enforced via a PATH-priority wrapper
|
||||||
# that checks group membership at runtime via SSSD/id(1).
|
# that checks group membership at runtime via SSSD/id(1).
|
||||||
# Removing the user group from FreeIPA reverts the wrapper.
|
# Removing the user group from FreeIPA reverts the wrapper.
|
||||||
# usr_scan-notify Members receive scan alert notifications on every enrolled device
|
# policy-scan-notify Members receive scan alert notifications on every enrolled device
|
||||||
# they log into. The fetch-alerts timer is installed fleet-wide
|
# they log into. The fetch-alerts timer is installed fleet-wide
|
||||||
# when the group exists; the notification daemon starts on login
|
# when the group exists; the notification daemon starts on login
|
||||||
# only for group members (checked via id(1) / SSSD).
|
# only for group members (checked via id(1) / SSSD).
|
||||||
|
|
@ -37,8 +38,8 @@
|
||||||
# snippet on the next enforcer run.
|
# snippet on the next enforcer run.
|
||||||
#
|
#
|
||||||
# Notes:
|
# Notes:
|
||||||
# - Install scan tools first: add the host to dev_mod_anti-malware.
|
# - Install scan tools first: add the host to ansipa-module-anti-malware.
|
||||||
# - Configure Timeshift (type + target device) before enabling dev_timeshift-backup.
|
# - Configure Timeshift (type + target device) before enabling policy-timeshift-backup.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
|
@ -78,40 +79,40 @@ if [[ -n "$RAW_GROUPS" ]]; then
|
||||||
for g in "${GRP_ARRAY[@]}"; do
|
for g in "${GRP_ARRAY[@]}"; do
|
||||||
g="${g// /}"
|
g="${g// /}"
|
||||||
case "$g" in
|
case "$g" in
|
||||||
dev_daemon-enable-*) ACTIVE_DAEMON_ENABLE+=("${g#dev_daemon-enable-}") ;;
|
policy-daemon-enable-*) ACTIVE_DAEMON_ENABLE+=("${g#policy-daemon-enable-}") ;;
|
||||||
dev_daemon-disable-*) ACTIVE_DAEMON_DISABLE+=("${g#dev_daemon-disable-}") ;;
|
policy-daemon-disable-*) ACTIVE_DAEMON_DISABLE+=("${g#policy-daemon-disable-}") ;;
|
||||||
dev_timeshift-backup) WANT_TIMESHIFT_BACKUP=true ;;
|
policy-timeshift-backup) WANT_TIMESHIFT_BACKUP=true ;;
|
||||||
dev_security-scan) WANT_SECURITY_SCAN=true ;;
|
policy-security-scan) WANT_SECURITY_SCAN=true ;;
|
||||||
dev_no-local-users) WANT_NO_LOCAL_USERS=true ;;
|
no_local_users) WANT_NO_LOCAL_USERS=true ;;
|
||||||
dev_local-sudo-*) ACTIVE_LOCAL_SUDO_USERS+=("${g#dev_local-sudo-}") ;;
|
local_sudo_*) ACTIVE_LOCAL_SUDO_USERS+=("${g#local_sudo_}") ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
done <<< "$RAW_GROUPS"
|
done <<< "$RAW_GROUPS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Fetch user-group-based binary block policies from FreeIPA ─────────────────
|
# ── Fetch user-group-based binary block policies from FreeIPA ─────────────────
|
||||||
# usr_block-binary-<name> groups are FreeIPA *user* groups — membership follows
|
# policy-block-binary-<name> groups are FreeIPA *user* groups — membership follows
|
||||||
# the user to every enrolled host rather than being tied to a device.
|
# the user to every enrolled host rather than being tied to a device.
|
||||||
ACTIVE_BLOCK_BINARIES=()
|
ACTIVE_BLOCK_BINARIES=()
|
||||||
ACTIVE_BLOCK_IPA_GROUPS=()
|
ACTIVE_BLOCK_IPA_GROUPS=()
|
||||||
|
|
||||||
_BLOCK_LIST=$(ipa group-find --pkey-only 2>/dev/null \
|
_BLOCK_LIST=$(ipa group-find --pkey-only 2>/dev/null \
|
||||||
| awk '/Group name:/ {print $NF}' \
|
| awk '/Group name:/ {print $NF}' \
|
||||||
| grep "^usr_block-binary-" | sort -u || true)
|
| grep "^policy-block-binary-" | sort -u || true)
|
||||||
|
|
||||||
while IFS= read -r _grp; do
|
while IFS= read -r _grp; do
|
||||||
[[ -z "$_grp" ]] && continue
|
[[ -z "$_grp" ]] && continue
|
||||||
_raw="${_grp#usr_block-binary-}"
|
_raw="${_grp#policy-block-binary-}"
|
||||||
ACTIVE_BLOCK_BINARIES+=("${_raw//__/.}")
|
ACTIVE_BLOCK_BINARIES+=("${_raw//__/.}")
|
||||||
ACTIVE_BLOCK_IPA_GROUPS+=("$_grp")
|
ACTIVE_BLOCK_IPA_GROUPS+=("$_grp")
|
||||||
done <<< "$_BLOCK_LIST"
|
done <<< "$_BLOCK_LIST"
|
||||||
unset _BLOCK_LIST _grp _raw
|
unset _BLOCK_LIST _grp _raw
|
||||||
|
|
||||||
# ── Fetch user-group-based scan-notify policy from FreeIPA ────────────────────
|
# ── Fetch user-group-based scan-notify policy from FreeIPA ────────────────────
|
||||||
# usr_scan-notify is a FreeIPA *user* group — membership follows the user to
|
# policy-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
|
# 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.
|
# group exists; the profile.d snippet gates daemon start on runtime membership.
|
||||||
if ipa group-show usr_scan-notify >/dev/null 2>&1; then
|
if ipa group-show policy-scan-notify >/dev/null 2>&1; then
|
||||||
WANT_SCAN_NOTIFY=true
|
WANT_SCAN_NOTIFY=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -133,7 +134,7 @@ _in_block_list() {
|
||||||
|
|
||||||
# ── Binary blocking (user-based) ──────────────────────────────────────────────
|
# ── Binary blocking (user-based) ──────────────────────────────────────────────
|
||||||
# A PATH-priority wrapper is installed in /usr/local/bin/ for every binary named
|
# A PATH-priority wrapper is installed in /usr/local/bin/ for every binary named
|
||||||
# by a usr_block-binary-* FreeIPA *user* group. The wrapper checks the
|
# by a policy-block-binary-* FreeIPA *user* group. The wrapper checks the
|
||||||
# caller's group membership at runtime (via id + SSSD) and only blocks members;
|
# caller's group membership at runtime (via id + SSSD) and only blocks members;
|
||||||
# non-members are transparently passed through to the real binary.
|
# non-members are transparently passed through to the real binary.
|
||||||
# __ in the group suffix decodes to . so Flatpak app IDs are fully supported.
|
# __ in the group suffix decodes to . so Flatpak app IDs are fully supported.
|
||||||
|
|
@ -194,11 +195,11 @@ TIMESHIFT_CRON="$CRON_DIR/ansipa-timeshift-backup"
|
||||||
if [[ "$WANT_TIMESHIFT_BACKUP" == true ]]; then
|
if [[ "$WANT_TIMESHIFT_BACKUP" == true ]]; then
|
||||||
if [[ ! -f "$TIMESHIFT_CRON" ]]; then
|
if [[ ! -f "$TIMESHIFT_CRON" ]]; then
|
||||||
if ! command -v timeshift &>/dev/null; then
|
if ! command -v timeshift &>/dev/null; then
|
||||||
warn "timeshift not found — add host to dev_mod_timeshift first. Cron will be installed anyway."
|
warn "timeshift not found — add host to ansipa-module-timeshift first. Cron will be installed anyway."
|
||||||
fi
|
fi
|
||||||
log "Enabling daily Timeshift backups"
|
log "Enabling daily Timeshift backups"
|
||||||
cat > "$TIMESHIFT_CRON" <<'CRON'
|
cat > "$TIMESHIFT_CRON" <<'CRON'
|
||||||
# ansipa-dev_timeshift-backup: managed by ansipa-enforce-policies — do not edit manually.
|
# ansipa-policy-timeshift-backup: managed by ansipa-enforce-policies — do not edit manually.
|
||||||
# Timeshift must be configured on this host (type + target device) before snapshots work.
|
# 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
|
0 3 * * * root /usr/bin/timeshift --create --comments "ansipa-daily" --tags D 2>&1 | logger -t timeshift-backup
|
||||||
CRON
|
CRON
|
||||||
|
|
@ -207,7 +208,7 @@ CRON
|
||||||
else
|
else
|
||||||
if [[ -f "$TIMESHIFT_CRON" ]]; then
|
if [[ -f "$TIMESHIFT_CRON" ]]; then
|
||||||
rm -f "$TIMESHIFT_CRON"
|
rm -f "$TIMESHIFT_CRON"
|
||||||
log "Removed Timeshift backup cron (host left dev_timeshift-backup group)"
|
log "Removed Timeshift backup cron (host left policy-timeshift-backup group)"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -262,8 +263,8 @@ SCAN
|
||||||
if [[ ! -f "$SCAN_CRON" ]]; then
|
if [[ ! -f "$SCAN_CRON" ]]; then
|
||||||
log "Enabling daily security scans (ClamAV / rkhunter / chkrootkit)"
|
log "Enabling daily security scans (ClamAV / rkhunter / chkrootkit)"
|
||||||
cat > "$SCAN_CRON" <<'CRON'
|
cat > "$SCAN_CRON" <<'CRON'
|
||||||
# ansipa-dev_security-scan: managed by ansipa-enforce-policies — do not edit manually.
|
# ansipa-policy-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.
|
# Install scan tools by adding the host to the ansipa-module-anti-malware group.
|
||||||
0 2 * * * root /usr/local/bin/ansipa-security-scan.sh
|
0 2 * * * root /usr/local/bin/ansipa-security-scan.sh
|
||||||
CRON
|
CRON
|
||||||
chmod 644 "$SCAN_CRON"
|
chmod 644 "$SCAN_CRON"
|
||||||
|
|
@ -272,12 +273,12 @@ else
|
||||||
if [[ -f "$SCAN_CRON" ]]; then
|
if [[ -f "$SCAN_CRON" ]]; then
|
||||||
rm -f "$SCAN_CRON"
|
rm -f "$SCAN_CRON"
|
||||||
rm -f "$SCAN_SCRIPT"
|
rm -f "$SCAN_SCRIPT"
|
||||||
log "Removed security scan policy (host left dev_security-scan group)"
|
log "Removed security scan policy (host left policy-security-scan group)"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Scan notification daemon ──────────────────────────────────────────────────
|
# ── Scan notification daemon ──────────────────────────────────────────────────
|
||||||
# usr_scan-notify is a FreeIPA *user* group (not a host group). The fetch-
|
# policy-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
|
# 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
|
# 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).
|
# (checked via id(1) / SSSD so no IPA query is needed at login time).
|
||||||
|
|
@ -334,11 +335,11 @@ UNIT
|
||||||
log "Installing /etc/profile.d/ansipa-notify.sh"
|
log "Installing /etc/profile.d/ansipa-notify.sh"
|
||||||
cat > "$NOTIFY_PROFILED" <<'PROFILED'
|
cat > "$NOTIFY_PROFILED" <<'PROFILED'
|
||||||
# ansipa-notify: launch the scan alert notification daemon on login for
|
# ansipa-notify: launch the scan alert notification daemon on login for
|
||||||
# members of the usr_scan-notify FreeIPA user group.
|
# members of the policy-scan-notify FreeIPA user group.
|
||||||
# Managed by ansipa-enforce-policies — do not edit manually.
|
# Managed by ansipa-enforce-policies — do not edit manually.
|
||||||
_NOTIFY_DAEMON=/usr/local/bin/ansipa-scan-notify.sh
|
_NOTIFY_DAEMON=/usr/local/bin/ansipa-scan-notify.sh
|
||||||
if [[ -x "$_NOTIFY_DAEMON" ]] && \
|
if [[ -x "$_NOTIFY_DAEMON" ]] && \
|
||||||
id -nG 2>/dev/null | grep -qw "usr_scan-notify" && \
|
id -nG 2>/dev/null | grep -qw "policy-scan-notify" && \
|
||||||
! pgrep -u "$(id -u)" -f "ansipa-scan-notify" >/dev/null 2>&1; then
|
! pgrep -u "$(id -u)" -f "ansipa-scan-notify" >/dev/null 2>&1; then
|
||||||
"$_NOTIFY_DAEMON" &
|
"$_NOTIFY_DAEMON" &
|
||||||
disown
|
disown
|
||||||
|
|
@ -352,7 +353,7 @@ else
|
||||||
systemctl disable --now ansipa-fetch-alerts.timer 2>/dev/null || true
|
systemctl disable --now ansipa-fetch-alerts.timer 2>/dev/null || true
|
||||||
rm -f "$FETCH_SVC" "$FETCH_TIMER"
|
rm -f "$FETCH_SVC" "$FETCH_TIMER"
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
log "Removed ansipa-fetch-alerts timer (usr_scan-notify user group no longer exists)"
|
log "Removed ansipa-fetch-alerts timer (policy-scan-notify user group no longer exists)"
|
||||||
fi
|
fi
|
||||||
if [[ -f "$NOTIFY_PROFILED" ]]; then
|
if [[ -f "$NOTIFY_PROFILED" ]]; then
|
||||||
rm -f "$NOTIFY_PROFILED"
|
rm -f "$NOTIFY_PROFILED"
|
||||||
|
|
@ -361,9 +362,9 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Daemon enable / disable ───────────────────────────────────────────────────
|
# ── Daemon enable / disable ───────────────────────────────────────────────────
|
||||||
# dev_daemon-enable-<unit>: ensure the unit is enabled and running.
|
# policy-daemon-enable-<unit>: ensure the unit is enabled and running.
|
||||||
# Leaving the group reverts: unit is disabled and stopped.
|
# Leaving the group reverts: unit is disabled and stopped.
|
||||||
# dev_daemon-disable-<unit>: ensure the unit is disabled and stopped.
|
# policy-daemon-disable-<unit>: ensure the unit is disabled and stopped.
|
||||||
# Leaving the group reverts: unit is re-enabled and started.
|
# Leaving the group reverts: unit is re-enabled and started.
|
||||||
# <unit> may omit the .service suffix; systemd accepts both forms.
|
# <unit> may omit the .service suffix; systemd accepts both forms.
|
||||||
# Conflicts (unit in both lists): logged as a warning, unit is left untouched.
|
# Conflicts (unit in both lists): logged as a warning, unit is left untouched.
|
||||||
|
|
@ -447,7 +448,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Per-device local sudo grants ──────────────────────────────────────────────
|
# ── Per-device local sudo grants ──────────────────────────────────────────────
|
||||||
# dev_local-sudo-<username>: write a sudoers drop-in granting <username> full sudo on
|
# 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.
|
# this specific device. The drop-in is removed when the host leaves the group.
|
||||||
|
|
||||||
LOCAL_SUDO_DIR="/etc/sudoers.d"
|
LOCAL_SUDO_DIR="/etc/sudoers.d"
|
||||||
|
|
@ -464,7 +465,7 @@ for _USER in "${ACTIVE_LOCAL_SUDO_USERS[@]}"; do
|
||||||
grep -qxF "$_USER" "$LOCAL_SUDO_STATE" 2>/dev/null || echo "$_USER" >> "$LOCAL_SUDO_STATE"
|
grep -qxF "$_USER" "$LOCAL_SUDO_STATE" 2>/dev/null || echo "$_USER" >> "$LOCAL_SUDO_STATE"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Revoke sudo for users no longer in any active dev_local-sudo-* group.
|
# Revoke sudo for users no longer in any active local_sudo_* group.
|
||||||
while IFS= read -r _OLD_USER; do
|
while IFS= read -r _OLD_USER; do
|
||||||
[[ -z "$_OLD_USER" ]] && continue
|
[[ -z "$_OLD_USER" ]] && continue
|
||||||
_still_active=false
|
_still_active=false
|
||||||
|
|
@ -475,7 +476,7 @@ while IFS= read -r _OLD_USER; do
|
||||||
_DROPIN="$LOCAL_SUDO_DIR/ansipa-local-sudo-${_OLD_USER}"
|
_DROPIN="$LOCAL_SUDO_DIR/ansipa-local-sudo-${_OLD_USER}"
|
||||||
if [[ -f "$_DROPIN" ]]; then
|
if [[ -f "$_DROPIN" ]]; then
|
||||||
rm -f "$_DROPIN"
|
rm -f "$_DROPIN"
|
||||||
log "Revoked local sudo for $_OLD_USER (host left dev_local-sudo-$_OLD_USER group)"
|
log "Revoked local sudo for $_OLD_USER (host left local_sudo_$_OLD_USER group)"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done < "$LOCAL_SUDO_STATE"
|
done < "$LOCAL_SUDO_STATE"
|
||||||
|
|
@ -489,7 +490,7 @@ fi
|
||||||
unset _USER _DROPIN _OLD_USER _still_active _U
|
unset _USER _DROPIN _OLD_USER _still_active _U
|
||||||
|
|
||||||
# ── No-local-users policy ──────────────────────────────────────────────────────
|
# ── No-local-users policy ──────────────────────────────────────────────────────
|
||||||
# dev_no-local-users: lock the passwords of root and all local users (UID >= 1000)
|
# 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
|
# so that only FreeIPA domain accounts with centrally-managed sudo rules can
|
||||||
# authenticate and gain elevated privileges.
|
# authenticate and gain elevated privileges.
|
||||||
# Leaving the group reverts: every account locked by this policy is unlocked.
|
# Leaving the group reverts: every account locked by this policy is unlocked.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ansipa-fetch-alerts.sh — fetch security alerts from the server SMB share.
|
# ansipa-fetch-alerts.sh — fetch security alerts from the server SMB share.
|
||||||
# Runs as root every 10 minutes via ansipa-fetch-alerts.timer (usr_scan-notify).
|
# Runs as root every 10 minutes via ansipa-fetch-alerts.timer (policy-scan-notify).
|
||||||
#
|
#
|
||||||
# For each alert on the server that hasn't been acknowledged yet:
|
# For each alert on the server that hasn't been acknowledged yet:
|
||||||
# - Downloads it to ~/administration/<hostname>/ for every active login session.
|
# - Downloads it to ~/administration/<hostname>/ for every active login session.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Install Flatpaks based on FreeIPA dev_fp_* groups
|
Description=Install Flatpaks based on FreeIPA fp_install_* groups
|
||||||
After=network-online.target sssd.service
|
After=network-online.target sssd.service
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,18 @@
|
||||||
# ansipa-install-flatpaks.sh — install Flatpak apps based on FreeIPA group membership.
|
# ansipa-install-flatpaks.sh — install Flatpak apps based on FreeIPA group membership.
|
||||||
#
|
#
|
||||||
# IPA group naming convention (dots encoded as double underscores):
|
# IPA group naming convention (dots encoded as double underscores):
|
||||||
# dev_fp_org__mozilla__firefox → installs org.mozilla.firefox
|
# fp_install_org__mozilla__firefox → installs org.mozilla.firefox
|
||||||
# dev_fp_com__spotify__Client → installs com.spotify.Client
|
# fp_install_com__spotify__Client → installs com.spotify.Client
|
||||||
# dev_fp_io__missioncenter__MissionCenter → installs io.missioncenter.MissionCenter
|
# fp_install_io__missioncenter__MissionCenter → installs io.missioncenter.MissionCenter
|
||||||
#
|
#
|
||||||
# Decoding: strip "dev_fp_" prefix, then replace every __ with a dot.
|
# Decoding: strip "fp_install_" prefix, then replace every __ with a dot.
|
||||||
# Single underscores in Flatpak IDs are preserved as-is.
|
# Single underscores in Flatpak IDs are preserved as-is.
|
||||||
#
|
#
|
||||||
# Scope: system-wide (--system), runs as root via systemd service.
|
# Scope: system-wide (--system), runs as root via systemd service.
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
PREFIX="dev_fp_"
|
PREFIX="fp_install_"
|
||||||
|
|
||||||
# ── Preflight ─────────────────────────────────────────────────────────────────
|
# ── Preflight ─────────────────────────────────────────────────────────────────
|
||||||
if ! command -v flatpak &>/dev/null; then
|
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
|
https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Discover IPA groups matching dev_fp_* ────────────────────────────────────
|
# ── Discover IPA groups matching fp_install_* ─────────────────────────────────
|
||||||
# ipa group-find --pkey-only outputs one group name per line (possibly indented).
|
# ipa group-find --pkey-only outputs one group name per line (possibly indented).
|
||||||
# $NF captures the name regardless of leading label text.
|
# $NF captures the name regardless of leading label text.
|
||||||
IPA_GROUPS=$(ipa group-find --pkey-only 2>/dev/null \
|
IPA_GROUPS=$(ipa group-find --pkey-only 2>/dev/null \
|
||||||
|
|
@ -49,7 +49,7 @@ if [[ -z "$IPA_GROUPS" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Decode group names → Flatpak application IDs ─────────────────────────────
|
# ── Decode group names → Flatpak application IDs ─────────────────────────────
|
||||||
# 1. Strip the dev_fp_ prefix
|
# 1. Strip the fp_install_ prefix
|
||||||
# 2. Replace every __ with a literal dot
|
# 2. Replace every __ with a literal dot
|
||||||
DESIRED_FLATPAKS=()
|
DESIRED_FLATPAKS=()
|
||||||
while IFS= read -r G; do
|
while IFS= read -r G; do
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Apply setup modules based on FreeIPA dev_mod_* host groups
|
Description=Apply setup modules based on FreeIPA ansipa-module-* host groups
|
||||||
After=network-online.target sssd.service
|
After=network-online.target sssd.service
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,11 @@
|
||||||
# FreeIPA host group membership.
|
# FreeIPA host group membership.
|
||||||
#
|
#
|
||||||
# Host groups follow the naming convention:
|
# Host groups follow the naming convention:
|
||||||
# dev_mod_<name> e.g. dev_mod_docker, dev_mod_ollama
|
# ansipa-module-<name> e.g. ansipa-module-docker, ansipa-module-ollama
|
||||||
#
|
#
|
||||||
# When this host is a member of such a group, the corresponding module
|
# 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.
|
# 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
|
# stamped in /var/lib/ansipa-modules/).
|
||||||
# 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
|
# Configuration: /etc/ansipa-modules.conf
|
||||||
# ANSIPA_USER=<username> non-root user for AUR helper (yay)
|
# ANSIPA_USER=<username> non-root user for AUR helper (yay)
|
||||||
|
|
@ -26,112 +22,15 @@ CONFIG=/etc/ansipa-modules.conf
|
||||||
ANSIPA_USER="${ANSIPA_USER:-}"
|
ANSIPA_USER="${ANSIPA_USER:-}"
|
||||||
MODULES_DIR="${MODULES_DIR:-/usr/local/lib/ansipa-modules}"
|
MODULES_DIR="${MODULES_DIR:-/usr/local/lib/ansipa-modules}"
|
||||||
STATE_DIR="${STATE_DIR:-/var/lib/ansipa-modules}"
|
STATE_DIR="${STATE_DIR:-/var/lib/ansipa-modules}"
|
||||||
MANIFEST="$STATE_DIR/manifest.json"
|
PREFIX="ansipa-module-"
|
||||||
PREFIX="dev_mod_"
|
|
||||||
LOG_TAG="ansipa-modules"
|
LOG_TAG="ansipa-modules"
|
||||||
|
|
||||||
log() { echo "[$LOG_TAG] $*"; logger -t "$LOG_TAG" "$*" 2>/dev/null || true; }
|
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; }
|
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 ───────────────────────────────────────────────────────
|
# ── Resolve ANSIPA_USER ───────────────────────────────────────────────────────
|
||||||
if [[ -z "$ANSIPA_USER" ]]; then
|
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)
|
ANSIPA_USER=$(awk -F: '($3>=1000 && $7!~/nologin|false/) {print $1; exit}' /etc/passwd)
|
||||||
fi
|
fi
|
||||||
if [[ -z "$ANSIPA_USER" ]]; then
|
if [[ -z "$ANSIPA_USER" ]]; then
|
||||||
|
|
@ -140,6 +39,7 @@ if [[ -z "$ANSIPA_USER" ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "Running as root, AUR helper delegated to user: $ANSIPA_USER"
|
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 ────────
|
# ── Create a yay wrapper so module scripts can call 'yay' as non-root ────────
|
||||||
YAY_BIN=$(command -v yay 2>/dev/null || true)
|
YAY_BIN=$(command -v yay 2>/dev/null || true)
|
||||||
|
|
@ -154,14 +54,17 @@ EOF
|
||||||
chmod +x "$WRAP_DIR/yay"
|
chmod +x "$WRAP_DIR/yay"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Kinit with host keytab so IPA commands work from the service context ──────
|
# ── 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 -k "host/$HOST_FQDN" &>/dev/null || true
|
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 \
|
RAW_GROUPS=$(ipa host-show "$HOST_FQDN" --all 2>/dev/null \
|
||||||
| grep -i "Member of host-groups:" | sed 's/.*: //' || true)
|
| grep -i "Member of host-groups:" | sed 's/.*: //' || true)
|
||||||
|
|
||||||
|
|
@ -170,11 +73,11 @@ if [[ -z "$RAW_GROUPS" ]]; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Parse comma-separated list, keep only dev_mod_* entries
|
# Parse comma-separated list, keep only ansipa-module-* entries
|
||||||
WANTED_MODULES=()
|
WANTED_MODULES=()
|
||||||
while IFS=',' read -ra GRP_ARRAY; do
|
while IFS=',' read -ra GRP_ARRAY; do
|
||||||
for g in "${GRP_ARRAY[@]}"; do
|
for g in "${GRP_ARRAY[@]}"; do
|
||||||
g="${g// /}"
|
g="${g// /}" # strip spaces
|
||||||
if [[ "$g" == ${PREFIX}* ]]; then
|
if [[ "$g" == ${PREFIX}* ]]; then
|
||||||
WANTED_MODULES+=("${g#$PREFIX}")
|
WANTED_MODULES+=("${g#$PREFIX}")
|
||||||
fi
|
fi
|
||||||
|
|
@ -182,7 +85,7 @@ while IFS=',' read -ra GRP_ARRAY; do
|
||||||
done <<< "$RAW_GROUPS"
|
done <<< "$RAW_GROUPS"
|
||||||
|
|
||||||
if [[ ${#WANTED_MODULES[@]} -eq 0 ]]; then
|
if [[ ${#WANTED_MODULES[@]} -eq 0 ]]; then
|
||||||
log "No ${PREFIX}* host groups found for '$HOST_FQDN'."
|
log "No ansipa-module-* host groups found for '$HOST_FQDN'."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -200,19 +103,14 @@ for MODULE in "${WANTED_MODULES[@]}"; do
|
||||||
|
|
||||||
if [[ ! -f "$SCRIPT" ]]; then
|
if [[ ! -f "$SCRIPT" ]]; then
|
||||||
warn "Module script not found: $SCRIPT — skipping '$MODULE'."
|
warn "Module script not found: $SCRIPT — skipping '$MODULE'."
|
||||||
_manifest_update "$MODULE" "pending"
|
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "Applying module: $MODULE"
|
log "Applying module: $MODULE"
|
||||||
_manifest_update "$MODULE" "pending"
|
|
||||||
|
|
||||||
if env PATH="$WRAP_DIR:$PATH" bash "$SCRIPT" >>"$STATE_DIR/${MODULE}.log" 2>&1; then
|
if env PATH="$WRAP_DIR:$PATH" bash "$SCRIPT" >>"$STATE_DIR/${MODULE}.log" 2>&1; then
|
||||||
touch "$STAMP"
|
touch "$STAMP"
|
||||||
_manifest_update "$MODULE" "installed"
|
|
||||||
log "Module '$MODULE' applied successfully."
|
log "Module '$MODULE' applied successfully."
|
||||||
else
|
else
|
||||||
_manifest_update "$MODULE" "failed"
|
|
||||||
warn "Module '$MODULE' failed — see $STATE_DIR/${MODULE}.log"
|
warn "Module '$MODULE' failed — see $STATE_DIR/${MODULE}.log"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
PREFIX="dev_pkg_"
|
PREFIX="ansipa-install-"
|
||||||
|
|
||||||
# Detect distro
|
# Detect distro
|
||||||
if [ -f /etc/os-release ]; then
|
if [ -f /etc/os-release ]; then
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Install packages based on FreeIPA dev_pkg_* groups
|
Description=Install packages based on FreeIPA ansipa-install-* groups
|
||||||
After=network-online.target sssd.service
|
After=network-online.target sssd.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
content: |
|
content: |
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Install packages based on FreeIPA dev_pkg_* groups
|
Description=Install packages based on FreeIPA ansipa-install-* groups
|
||||||
After=network-online.target sssd.service
|
After=network-online.target sssd.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|
@ -51,7 +51,7 @@
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
content: |
|
content: |
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Install Flatpaks based on FreeIPA dev_fp_* groups
|
Description=Install Flatpaks based on FreeIPA fp_install_* groups
|
||||||
After=network-online.target sssd.service
|
After=network-online.target sssd.service
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
# deploy-ansipa-modules.yml — deploy the module auto-installer to enrolled hosts.
|
# deploy-ansipa-modules.yml — deploy the module auto-installer to enrolled hosts.
|
||||||
#
|
#
|
||||||
# Prerequisites on target hosts:
|
# Prerequisites on target hosts:
|
||||||
# - FreeIPA client enrolled (/etc/ipa/default.conf exists, ipa command available)
|
# - FreeIPA client enrolled (sssd running, 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)
|
# - A non-root user with yay access (set ANSIPA_USER in /etc/ansipa-modules.conf)
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
|
|
@ -11,10 +10,8 @@
|
||||||
# ansible-playbook -i inventory deploy-ansipa-modules.yml -e ansipa_user=amir
|
# ansible-playbook -i inventory deploy-ansipa-modules.yml -e ansipa_user=amir
|
||||||
#
|
#
|
||||||
# FreeIPA host group convention:
|
# FreeIPA host group convention:
|
||||||
# Create host groups named dev_mod_<name> (e.g. dev_mod_docker, dev_mod_ollama)
|
# Create host groups named ansipa-module-<name> (e.g. ansipa-module-docker)
|
||||||
# and add hosts to them. The timer checks group membership and applies any missing
|
# and add hosts to them. The timer will apply the matching module automatically.
|
||||||
# modules automatically. State is tracked in STATE_DIR/<module>.done stamps and
|
|
||||||
# summarised in STATE_DIR/manifest.json.
|
|
||||||
|
|
||||||
- name: Deploy FreeIPA module auto-installer
|
- name: Deploy FreeIPA module auto-installer
|
||||||
hosts: all
|
hosts: all
|
||||||
|
|
@ -27,11 +24,6 @@
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
|
||||||
- name: Ensure python3 is installed
|
|
||||||
package:
|
|
||||||
name: python3
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Create module directories
|
- name: Create module directories
|
||||||
file:
|
file:
|
||||||
path: "{{ item }}"
|
path: "{{ item }}"
|
||||||
|
|
@ -74,7 +66,7 @@
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
content: |
|
content: |
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Apply setup modules based on FreeIPA dev_mod_* host groups
|
Description=Apply setup modules based on FreeIPA ansipa-module-* host groups
|
||||||
After=network-online.target sssd.service
|
After=network-online.target sssd.service
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,21 @@
|
||||||
# deploy-ansipa-policies.yml — deploy the policy enforcement daemon to enrolled clients.
|
# 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.
|
# Installs ansipa-enforce-policies.sh and a systemd timer that runs it every 30 minutes.
|
||||||
# Device policies (FreeIPA host groups — applied to the whole machine):
|
# Policies are declared by adding hosts to the following FreeIPA host groups:
|
||||||
# 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
|
|
||||||
#
|
#
|
||||||
# User policies (FreeIPA user groups — follow the user across all enrolled devices):
|
# policy-block-binary-<name> Block execution of <name> via a PATH-priority wrapper + AppArmor
|
||||||
# usr_block-binary-<name> Block execution of <name> via a PATH-priority wrapper
|
# policy-daemon-enable-<unit> Ensure <unit> is enabled and running; reverted when host leaves group
|
||||||
# usr_scan-notify Fetch alerts from server, notify user every 10 min until acknowledged
|
# 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
|
||||||
#
|
#
|
||||||
# Prerequisites:
|
# Prerequisites:
|
||||||
# - Host enrolled in FreeIPA (sssd + ipa CLI available)
|
# - Host enrolled in FreeIPA (sssd + ipa CLI available)
|
||||||
# - For dev_security-scan / usr_scan-notify: samba-client installed (handled below)
|
# - For security-scan / 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 / 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 security-scan tools: also add host to ansipa-module-anti-malware group
|
||||||
# - For timeshift-backup: also add host to dev_mod_timeshift group
|
# - For timeshift-backup: also add host to ansipa-module-timeshift group
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ansible-playbook -i inventory deploy-ansipa-policies.yml \
|
# ansible-playbook -i inventory deploy-ansipa-policies.yml \
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
#!/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,7 +162,6 @@ count_steps() {
|
||||||
# Optional app modules: one glob check per app, one increment per match.
|
# Optional app modules: one glob check per app, one increment per match.
|
||||||
# Glob syntax *"tag"* matches if the space-separated SELECTED_APPS string
|
# Glob syntax *"tag"* matches if the space-separated SELECTED_APPS string
|
||||||
# contains the tag anywhere — works because tags never share substrings.
|
# contains the tag anywhere — works because tags never share substrings.
|
||||||
# BEGIN GENERATED MODULES: module-counters
|
|
||||||
[[ "$a" == *"ollama"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"ollama"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"llama-cpp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"llama-cpp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"open-webui"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"open-webui"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
|
|
@ -170,32 +169,19 @@ count_steps() {
|
||||||
[[ "$a" == *"networking-cli"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"networking-cli"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"disk-recovery"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"disk-recovery"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"himalaya"* ]] && 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" == *"gnuplot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"blender-povray"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"blender-povray"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"toot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"toot"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"db-clients"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"db-clients"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"mysql"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"mysql"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"productivity"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"productivity"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"python"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"yt-dlp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"k8s"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"sox"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"docker"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"imagemagick"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"podman"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"ffmpeg"* ]] && 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" == *"localtunnel"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"timeshift"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"butter"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"zfs"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"tlp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"wprs"* ]] && TOTAL=$(( TOTAL + 1 ))
|
|
||||||
[[ "$a" == *"plymouth-custom"* ]] && TOTAL=$(( TOTAL + 1 ))
|
|
||||||
[[ "$a" == *"steam"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"steam"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"vesktop"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"vesktop"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"spotify"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"spotify"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
|
|
@ -206,26 +192,22 @@ count_steps() {
|
||||||
[[ "$a" == *"doom"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"doom"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"sauerbraten"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"sauerbraten"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"stuntrally"* ]] && 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" == *"onlyoffice"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"xournal"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"wireshark"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"rnote"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"k8s"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"obsidian"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"docker"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"tangent-notes"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"podman"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"ffmpeg"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"cockpit"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"sox"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"ssh-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"imagemagick"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"freeipa-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"yt-dlp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"freeipa-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"gimp"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"freeipa-image"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"inkscape"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"python"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"krita"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"zfs"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"kdenlive"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"wprs"* ]] && 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" == *"chromium"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"firefox-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"firefox-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"zen-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"zen-browser"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
|
|
@ -240,10 +222,25 @@ count_steps() {
|
||||||
[[ "$a" == *"rdp-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"rdp-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"lamco-rdp-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"lamco-rdp-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"qemu"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"qemu"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"freeipa-client"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"xournal"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"freeipa-server"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"rnote"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
[[ "$a" == *"freeipa-image"* ]] && TOTAL=$(( TOTAL + 1 ))
|
[[ "$a" == *"obsidian"* ]] && TOTAL=$(( TOTAL + 1 ))
|
||||||
# END GENERATED MODULES: module-counters
|
[[ "$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 ))
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Answerfile ────────────────────────────────────────────────────────────────
|
# ── Answerfile ────────────────────────────────────────────────────────────────
|
||||||
|
|
@ -444,92 +441,94 @@ else
|
||||||
# prompt, buttons), with a minimum of 4 to remain usable on tiny screens.
|
# prompt, buttons), with a minimum of 4 to remain usable on tiny screens.
|
||||||
_APP_H=$(( TERM_H - 2 < 40 ? TERM_H - 2 : 40 ))
|
_APP_H=$(( TERM_H - 2 < 40 ? TERM_H - 2 : 40 ))
|
||||||
_APP_LIST_H=$(( _APP_H - 8 < 4 ? 4 : _APP_H - 8 ))
|
_APP_LIST_H=$(( _APP_H - 8 < 4 ? 4 : _APP_H - 8 ))
|
||||||
# BEGIN GENERATED MODULES: module-checklist
|
|
||||||
SELECTED_APPS=$(dialog --backtitle "$BACKTITLE" \
|
SELECTED_APPS=$(dialog --backtitle "$BACKTITLE" \
|
||||||
--title " Applications " \
|
--title " Applications " \
|
||||||
--checklist "Optional applications — installed after base components:" "$_APP_H" 76 "$_APP_LIST_H" \
|
--checklist "Optional applications — installed after base components:" "$_APP_H" 76 "$_APP_LIST_H" \
|
||||||
"ollama" "ollama local LLM runner and API server" off \
|
"ollama" "Ollama local LLM runner + API server" off \
|
||||||
"llama-cpp" "llama-cpp standalone LLM inference CLI and server" off \
|
"llama-cpp" "llama.cpp standalone inference CLI + server" off \
|
||||||
"open-webui" "open-webui browser UI for Ollama and LLM backends" off \
|
"open-webui" "Open WebUI browser UI for Ollama / LLM backends" off \
|
||||||
"claude" "claude Anthropic Claude Code CLI via npm" off \
|
"claude" "Claude Code Anthropic CLI via npm" off \
|
||||||
"networking-cli" "networking-cli nmap, nethogs, mitmproxy, httpie" off \
|
"networking-cli" "Networking CLI nmap · nethogs · mitmproxy · httpie" off \
|
||||||
"disk-recovery" "disk-recovery ddrescue and f3 disk recovery tools" off \
|
"disk-recovery" "Disk Recovery ddrescue · f3" off \
|
||||||
"himalaya" "himalaya terminal email client (AUR)" off \
|
"himalaya" "Himalaya terminal email client (AUR)" off \
|
||||||
"mail-notmuch" "mail-notmuch isync, msmtp, notmuch, alot mail stack" off \
|
"mail-notmuch" "Mail (notmuch) isync · msmtp · notmuch · alot stack" off \
|
||||||
"caldav-sync" "caldav-sync vdirsyncer and khal CalDAV calendar sync" off \
|
"caldav-sync" "CalDAV Sync vdirsyncer · khal calendar sync" off \
|
||||||
"ssh-server" "ssh-server openssh with key-auth and systemd unit enabled" off \
|
"gnuplot" "Gnuplot scientific plotting" off \
|
||||||
"wireshark" "wireshark network packet analyser GUI" off \
|
"blender-povray" "Blender + POV-Ray 3D modelling & ray-tracing" 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 \
|
"toot" "toot Mastodon CLI client (AUR)" off \
|
||||||
"db-clients" "db-clients pgcli and mycli interactive database CLIs" off \
|
"db-clients" "DB Clients pgcli · mycli" off \
|
||||||
"mysql" "mysql MariaDB server with initial setup" off \
|
"mysql" "MySQL / MariaDB mariadb server + setup" off \
|
||||||
"productivity" "productivity taskwarrior, watson, jrnl — task management and time tracking" off \
|
"productivity" "Productivity taskwarrior · watson · jrnl" off \
|
||||||
"python" "python pyright, pipx, pynvim Python tooling" on \
|
"yt-dlp" "yt-dlp YouTube / media downloader" off \
|
||||||
"k8s" "k8s kubectl and podman-desktop Kubernetes tools" off \
|
"sox" "SoX audio processing toolkit" off \
|
||||||
"docker" "docker docker and docker-compose" off \
|
"imagemagick" "ImageMagick image manipulation" off \
|
||||||
"podman" "podman rootless containers with buildah" off \
|
"ffmpeg" "FFmpeg extras thumbnailer · GStreamer codecs" off \
|
||||||
"cockpit" "cockpit web UI for machines and containers" off \
|
"localtunnel" "LocalTunnel expose localhost via tunnel" off \
|
||||||
"tlp" "tlp laptop battery optimisation" off \
|
"butter" "butter btrfs snapshot backup (AUR)" off \
|
||||||
"butter" "butter btrfs snapshot backup manager (AUR)" off \
|
"tlp" "TLP laptop power management" off \
|
||||||
"localsend" "localsend LAN file transfer, AirDrop-like (AUR)" off \
|
"steam" "Steam gaming platform" off \
|
||||||
"croc" "croc cross-platform encrypted file transfer" off \
|
"vesktop" "Vesktop Discord + Vencord theme" off \
|
||||||
"opendeck" "opendeck Stream Deck controller — ydotool + OpenDeck (Flatpak)" off \
|
"spotify" "Spotify launcher + Spicetify theming" off \
|
||||||
"localtunnel" "localtunnel expose localhost over a public URL" off \
|
"prism" "PrismLauncher Minecraft launcher (Flatpak)" off \
|
||||||
"timeshift" "timeshift system snapshot and backup with autosnap" off \
|
"vintagestory" "Vintage Story survival game (AUR)" off \
|
||||||
"zfs" "zfs zfs-dkms kernel module" off \
|
"openarena" "OpenArena open-source Quake III Arena" off \
|
||||||
"wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \
|
"tetris" "Tetris CLI bastet · vitetris" off \
|
||||||
"plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \
|
"doom" "Doom Chocolate Doom + Freedoom data" off \
|
||||||
"steam" "steam Steam gaming platform" off \
|
"sauerbraten" "Sauerbraten open-source FPS (Cube 2)" off \
|
||||||
"vesktop" "vesktop Discord client with Vencord theme" off \
|
"stuntrally" "Stunt Rally rally racing game (Flatpak)" off \
|
||||||
"spotify" "spotify Spotify launcher with Spicetify theming" off \
|
"localsend" "LocalSend LAN file transfer (AUR)" off \
|
||||||
"prism" "prism PrismLauncher Minecraft launcher (Flatpak)" off \
|
"croc" "croc cross-platform file transfer" off \
|
||||||
"vintagestory" "vintagestory Vintage Story survival game (AUR)" off \
|
"opendeck" "OpenDeck Stream Deck controller (Flatpak+ydotool)" off \
|
||||||
"openarena" "openarena open-source Quake III Arena" off \
|
"onlyoffice" "OnlyOffice office suite (AUR)" off \
|
||||||
"tetris" "tetris bastet and vitetris terminal Tetris" off \
|
"xournal" "Xournal++ note-taking & PDF annotator" off \
|
||||||
"doom" "doom Chocolate Doom with Freedoom data" off \
|
"rnote" "Rnote handwriting & note-taking (Flatpak)" off \
|
||||||
"sauerbraten" "sauerbraten Sauerbraten open-source FPS (Cube 2)" off \
|
"obsidian" "Obsidian knowledge base & Markdown notes (Flatpak)" off \
|
||||||
"stuntrally" "stuntrally Stunt Rally racing game (Flatpak)" off \
|
"tangent-notes" "Tangent Notes networked Markdown notes (Flatpak)" off \
|
||||||
"onlyoffice" "onlyoffice office suite — Docs, Sheets, Slides (AUR)" on \
|
"gimp" "GIMP GNU image manipulation program" off \
|
||||||
"xournal" "xournal note-taking and PDF annotator" off \
|
"inkscape" "Inkscape vector graphics editor" off \
|
||||||
"rnote" "rnote handwriting and note-taking with stylus support (Flatpak)" off \
|
"krita" "Krita digital painting application" off \
|
||||||
"obsidian" "obsidian knowledge base and Markdown note-taking (Flatpak)" off \
|
"ardour" "Ardour professional DAW" off \
|
||||||
"tangent-notes" "tangent-notes networked Markdown note-taking (Flatpak)" off \
|
"audacity" "Audacity multi-track audio editor" off \
|
||||||
"ffmpeg" "ffmpeg GStreamer codecs and ffmpegthumbnailer" off \
|
"lmms" "LMMS Linux MultiMedia Studio DAW" off \
|
||||||
"sox" "sox command-line audio processing toolkit" off \
|
"mixxx" "Mixxx DJ mixing software" off \
|
||||||
"imagemagick" "imagemagick image manipulation suite" off \
|
"cecilia" "Cecilia audio signal processing (AUR)" off \
|
||||||
"yt-dlp" "yt-dlp YouTube and media downloader" off \
|
"kdenlive" "Kdenlive KDE non-linear video editor" off \
|
||||||
"gimp" "gimp GNU Image Manipulation Program" off \
|
"openshot" "OpenShot easy video editor" off \
|
||||||
"inkscape" "inkscape vector graphics editor" off \
|
"shotcut" "Shotcut cross-platform video editor" off \
|
||||||
"krita" "krita digital painting and illustration" off \
|
"anti-malware" "Anti-Malware ClamAV · rkhunter · chkrootkit" off \
|
||||||
"kdenlive" "kdenlive KDE non-linear video editor" off \
|
"timeshift" "Timeshift system snapshot / backup + autosnap" off \
|
||||||
"openshot" "openshot cross-platform video editor" off \
|
"wireshark" "Wireshark network packet analyser (GUI)" off \
|
||||||
"shotcut" "shotcut cross-platform video editor" off \
|
"k8s" "Kubernetes tools kubectl · podman-desktop" off \
|
||||||
"ardour" "ardour professional DAW" off \
|
"docker" "Docker docker · docker-compose" off \
|
||||||
"audacity" "audacity multi-track audio editor" off \
|
"podman" "Podman rootless containers · buildah" off \
|
||||||
"lmms" "lmms Linux MultiMedia Studio music production" off \
|
"cockpit" "Cockpit web UI · machines · podman" off \
|
||||||
"mixxx" "mixxx DJ mixing software" off \
|
"ssh-server" "SSH server openssh · key-auth · enabled" off \
|
||||||
"cecilia" "cecilia audio synthesis and signal processing (AUR)" off \
|
"freeipa-client" "FreeIPA Client sssd + ipa-client-install + enrollment" off \
|
||||||
"chromium" "chromium open-source Chromium browser (official)" off \
|
"freeipa-server" "FreeIPA Server interactive server setup + client gen" off \
|
||||||
"firefox-browser" "firefox-browser Mozilla Firefox (official)" on \
|
"freeipa-image" "FreeIPA Image OCI/LXC/Proxmox LXC builder + Keycloak" off \
|
||||||
"zen-browser" "zen-browser privacy-focused Firefox fork (AUR)" off \
|
"python" "Python tools pyright · pipx · pynvim" off \
|
||||||
"nyxt" "nyxt keyboard-driven hackable browser (AUR)" off \
|
"zfs" "ZFS zfs-dkms kernel module" off \
|
||||||
"librewolf" "librewolf hardened Firefox fork (AUR)" off \
|
"wprs" "WPRS wprs-git (AUR)" off \
|
||||||
"min-browser" "min-browser minimal Electron browser (AUR)" off \
|
\
|
||||||
"vscodium" "vscodium telemetry-free VS Code build (AUR)" off \
|
"chromium" "Chromium open-source browser (official)" off \
|
||||||
"zed-ide" "zed-ide high-performance Rust IDE (official)" off \
|
"firefox-browser" "Firefox Mozilla browser (official)" off \
|
||||||
"geany" "geany lightweight IDE with plugins (official)" off \
|
"zen-browser" "Zen Browser Firefox-based privacy browser (AUR)" off \
|
||||||
"codeblocks" "codeblocks C/C++ IDE (official)" off \
|
"nyxt" "Nyxt keyboard-driven browser (AUR)" off \
|
||||||
"kate" "kate KDE advanced text editor (official)" off \
|
"librewolf" "LibreWolf hardened Firefox fork (AUR)" off \
|
||||||
"rdp-client" "rdp-client Remmina with FreeRDP and VNC plugins" off \
|
"min-browser" "Min minimal Electron browser (AUR)" off \
|
||||||
"lamco-rdp-server" "lamco-rdp-server native Wayland RDP server (AUR, Rust)" off \
|
\
|
||||||
"qemu" "qemu full QEMU/KVM stack with virt-manager" off \
|
"vscodium" "VSCodium telemetry-free VS Code (AUR)" off \
|
||||||
"freeipa-client" "freeipa-client sssd and ipa-client-install with auto-enrollment" off \
|
"zed-ide" "Zed high-performance Rust IDE (official)" off \
|
||||||
"freeipa-server" "freeipa-server interactive FreeIPA server setup with client generator" off \
|
"geany" "Geany lightweight IDE + plugins (official)" off \
|
||||||
"freeipa-image" "freeipa-image OCI/LXC/Proxmox image builder with Keycloak" 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.
|
||||||
3>&1 1>&2 2>&3) || SELECTED_APPS=""
|
3>&1 1>&2 2>&3) || SELECTED_APPS=""
|
||||||
# END GENERATED MODULES: module-checklist
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Shell RC preference ───────────────────────────────────────────────────────
|
# ── Shell RC preference ───────────────────────────────────────────────────────
|
||||||
|
|
@ -561,88 +560,83 @@ if ! $ANSWERFILE_MODE; then
|
||||||
|
|
||||||
if [[ -n "$SELECTED_APPS" ]]; then
|
if [[ -n "$SELECTED_APPS" ]]; then
|
||||||
SUMMARY+="\n Applications:\n"
|
SUMMARY+="\n Applications:\n"
|
||||||
# BEGIN GENERATED MODULES: module-summary
|
[[ "$SELECTED_APPS" == *"ollama"* ]] && SUMMARY+=" ✦ Ollama\n"
|
||||||
[[ "$SELECTED_APPS" == *"ollama"* ]] && SUMMARY+=" ✦ ollama\n"
|
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && SUMMARY+=" ✦ llama.cpp\n"
|
||||||
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && SUMMARY+=" ✦ llama-cpp\n"
|
[[ "$SELECTED_APPS" == *"open-webui"* ]] && SUMMARY+=" ✦ Open WebUI\n"
|
||||||
[[ "$SELECTED_APPS" == *"open-webui"* ]] && SUMMARY+=" ✦ open-webui\n"
|
[[ "$SELECTED_APPS" == *"claude"* ]] && SUMMARY+=" ✦ Claude Code\n"
|
||||||
[[ "$SELECTED_APPS" == *"claude"* ]] && SUMMARY+=" ✦ claude\n"
|
[[ "$SELECTED_APPS" == *"networking-cli"* ]] && SUMMARY+=" ✦ Networking CLI (nmap, nethogs, mitmproxy, httpie)\n"
|
||||||
[[ "$SELECTED_APPS" == *"networking-cli"* ]] && SUMMARY+=" ✦ networking-cli\n"
|
[[ "$SELECTED_APPS" == *"disk-recovery"* ]] && SUMMARY+=" ✦ Disk Recovery (ddrescue, f3)\n"
|
||||||
[[ "$SELECTED_APPS" == *"disk-recovery"* ]] && SUMMARY+=" ✦ disk-recovery\n"
|
[[ "$SELECTED_APPS" == *"himalaya"* ]] && SUMMARY+=" ✦ Himalaya\n"
|
||||||
[[ "$SELECTED_APPS" == *"himalaya"* ]] && SUMMARY+=" ✦ himalaya\n"
|
[[ "$SELECTED_APPS" == *"gnuplot"* ]] && SUMMARY+=" ✦ Gnuplot\n"
|
||||||
[[ "$SELECTED_APPS" == *"mail-notmuch"* ]] && SUMMARY+=" ✦ mail-notmuch\n"
|
[[ "$SELECTED_APPS" == *"blender-povray"* ]] && SUMMARY+=" ✦ Blender + POV-Ray\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" == *"toot"* ]] && SUMMARY+=" ✦ toot\n"
|
||||||
[[ "$SELECTED_APPS" == *"db-clients"* ]] && SUMMARY+=" ✦ db-clients\n"
|
[[ "$SELECTED_APPS" == *"db-clients"* ]] && SUMMARY+=" ✦ DB Clients (pgcli, mycli)\n"
|
||||||
[[ "$SELECTED_APPS" == *"mysql"* ]] && SUMMARY+=" ✦ mysql\n"
|
[[ "$SELECTED_APPS" == *"mysql"* ]] && SUMMARY+=" ✦ MySQL / MariaDB\n"
|
||||||
[[ "$SELECTED_APPS" == *"productivity"* ]] && SUMMARY+=" ✦ productivity\n"
|
[[ "$SELECTED_APPS" == *"productivity"* ]] && SUMMARY+=" ✦ Productivity (taskwarrior, watson, jrnl)\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" == *"yt-dlp"* ]] && SUMMARY+=" ✦ yt-dlp\n"
|
||||||
[[ "$SELECTED_APPS" == *"gimp"* ]] && SUMMARY+=" ✦ gimp\n"
|
[[ "$SELECTED_APPS" == *"sox"* ]] && SUMMARY+=" ✦ SoX\n"
|
||||||
[[ "$SELECTED_APPS" == *"inkscape"* ]] && SUMMARY+=" ✦ inkscape\n"
|
[[ "$SELECTED_APPS" == *"imagemagick"* ]] && SUMMARY+=" ✦ ImageMagick\n"
|
||||||
[[ "$SELECTED_APPS" == *"krita"* ]] && SUMMARY+=" ✦ krita\n"
|
[[ "$SELECTED_APPS" == *"ffmpeg"* ]] && SUMMARY+=" ✦ FFmpeg extras\n"
|
||||||
[[ "$SELECTED_APPS" == *"kdenlive"* ]] && SUMMARY+=" ✦ kdenlive\n"
|
[[ "$SELECTED_APPS" == *"localtunnel"* ]] && SUMMARY+=" ✦ LocalTunnel\n"
|
||||||
[[ "$SELECTED_APPS" == *"openshot"* ]] && SUMMARY+=" ✦ openshot\n"
|
[[ "$SELECTED_APPS" == *"butter"* ]] && SUMMARY+=" ✦ butter (btrfs backup)\n"
|
||||||
[[ "$SELECTED_APPS" == *"shotcut"* ]] && SUMMARY+=" ✦ shotcut\n"
|
[[ "$SELECTED_APPS" == *"tlp"* ]] && SUMMARY+=" ✦ TLP\n"
|
||||||
[[ "$SELECTED_APPS" == *"ardour"* ]] && SUMMARY+=" ✦ ardour\n"
|
[[ "$SELECTED_APPS" == *"steam"* ]] && SUMMARY+=" ✦ Steam\n"
|
||||||
[[ "$SELECTED_APPS" == *"audacity"* ]] && SUMMARY+=" ✦ audacity\n"
|
[[ "$SELECTED_APPS" == *"vesktop"* ]] && SUMMARY+=" ✦ Vesktop + Vencord theme\n"
|
||||||
[[ "$SELECTED_APPS" == *"lmms"* ]] && SUMMARY+=" ✦ lmms\n"
|
[[ "$SELECTED_APPS" == *"spotify"* ]] && SUMMARY+=" ✦ Spotify + Spicetify\n"
|
||||||
[[ "$SELECTED_APPS" == *"mixxx"* ]] && SUMMARY+=" ✦ mixxx\n"
|
[[ "$SELECTED_APPS" == *"prism"* ]] && SUMMARY+=" ✦ PrismLauncher\n"
|
||||||
[[ "$SELECTED_APPS" == *"cecilia"* ]] && SUMMARY+=" ✦ cecilia\n"
|
[[ "$SELECTED_APPS" == *"vintagestory"* ]] && SUMMARY+=" ✦ Vintage Story\n"
|
||||||
[[ "$SELECTED_APPS" == *"chromium"* ]] && SUMMARY+=" ✦ chromium\n"
|
[[ "$SELECTED_APPS" == *"openarena"* ]] && SUMMARY+=" ✦ OpenArena\n"
|
||||||
[[ "$SELECTED_APPS" == *"firefox-browser"* ]] && SUMMARY+=" ✦ firefox-browser\n"
|
[[ "$SELECTED_APPS" == *"tetris"* ]] && SUMMARY+=" ✦ Tetris CLI (bastet · vitetris)\n"
|
||||||
[[ "$SELECTED_APPS" == *"zen-browser"* ]] && SUMMARY+=" ✦ zen-browser\n"
|
[[ "$SELECTED_APPS" == *"doom"* ]] && SUMMARY+=" ✦ Doom\n"
|
||||||
[[ "$SELECTED_APPS" == *"nyxt"* ]] && SUMMARY+=" ✦ nyxt\n"
|
[[ "$SELECTED_APPS" == *"sauerbraten"* ]] && SUMMARY+=" ✦ Sauerbraten\n"
|
||||||
[[ "$SELECTED_APPS" == *"librewolf"* ]] && SUMMARY+=" ✦ librewolf\n"
|
[[ "$SELECTED_APPS" == *"stuntrally"* ]] && SUMMARY+=" ✦ Stunt Rally\n"
|
||||||
[[ "$SELECTED_APPS" == *"min-browser"* ]] && SUMMARY+=" ✦ min-browser\n"
|
[[ "$SELECTED_APPS" == *"localsend"* ]] && SUMMARY+=" ✦ LocalSend\n"
|
||||||
[[ "$SELECTED_APPS" == *"vscodium"* ]] && SUMMARY+=" ✦ vscodium\n"
|
[[ "$SELECTED_APPS" == *"croc"* ]] && SUMMARY+=" ✦ croc\n"
|
||||||
[[ "$SELECTED_APPS" == *"zed-ide"* ]] && SUMMARY+=" ✦ zed-ide\n"
|
[[ "$SELECTED_APPS" == *"opendeck"* ]] && SUMMARY+=" ✦ OpenDeck + ydotool\n"
|
||||||
[[ "$SELECTED_APPS" == *"geany"* ]] && SUMMARY+=" ✦ geany\n"
|
[[ "$SELECTED_APPS" == *"onlyoffice"* ]] && SUMMARY+=" ✦ OnlyOffice\n"
|
||||||
[[ "$SELECTED_APPS" == *"codeblocks"* ]] && SUMMARY+=" ✦ codeblocks\n"
|
[[ "$SELECTED_APPS" == *"xournal"* ]] && SUMMARY+=" ✦ Xournal++\n"
|
||||||
[[ "$SELECTED_APPS" == *"kate"* ]] && SUMMARY+=" ✦ kate\n"
|
[[ "$SELECTED_APPS" == *"rnote"* ]] && SUMMARY+=" ✦ Rnote\n"
|
||||||
[[ "$SELECTED_APPS" == *"rdp-client"* ]] && SUMMARY+=" ✦ rdp-client\n"
|
[[ "$SELECTED_APPS" == *"obsidian"* ]] && SUMMARY+=" ✦ Obsidian\n"
|
||||||
[[ "$SELECTED_APPS" == *"lamco-rdp-server"* ]] && SUMMARY+=" ✦ lamco-rdp-server\n"
|
[[ "$SELECTED_APPS" == *"tangent-notes"* ]] && SUMMARY+=" ✦ Tangent Notes\n"
|
||||||
[[ "$SELECTED_APPS" == *"qemu"* ]] && SUMMARY+=" ✦ qemu\n"
|
[[ "$SELECTED_APPS" == *"gimp"* ]] && SUMMARY+=" ✦ GIMP\n"
|
||||||
[[ "$SELECTED_APPS" == *"freeipa-client"* ]] && SUMMARY+=" ✦ freeipa-client\n"
|
[[ "$SELECTED_APPS" == *"inkscape"* ]] && SUMMARY+=" ✦ Inkscape\n"
|
||||||
[[ "$SELECTED_APPS" == *"freeipa-server"* ]] && SUMMARY+=" ✦ freeipa-server\n"
|
[[ "$SELECTED_APPS" == *"krita"* ]] && SUMMARY+=" ✦ Krita\n"
|
||||||
[[ "$SELECTED_APPS" == *"freeipa-image"* ]] && SUMMARY+=" ✦ freeipa-image\n"
|
[[ "$SELECTED_APPS" == *"ardour"* ]] && SUMMARY+=" ✦ Ardour\n"
|
||||||
# END GENERATED MODULES: module-summary
|
[[ "$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"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Size the confirmation dialog to the terminal, capped at 24 rows.
|
# Size the confirmation dialog to the terminal, capped at 24 rows.
|
||||||
|
|
@ -686,94 +680,85 @@ fi
|
||||||
# Same guard pattern as base components. Each line is independent; a missing
|
# 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
|
# 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.
|
# silently skipped — 'bash "$script"' will exit non-zero if the file is absent.
|
||||||
# BEGIN GENERATED MODULES: module-conflicts
|
[[ "$SELECTED_APPS" == *"ollama"* ]] && run_module "Ollama" "$APPS/ollama.sh"
|
||||||
if [[ "$SELECTED_APPS" == *"plymouth-custom"* && "$SELECTED_APPS" == *"plymouth"* ]]; then
|
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && run_module "llama.cpp" "$APPS/llama-cpp.sh"
|
||||||
warn "plymouth-custom and plymouth are mutually exclusive — skipping plymouth"
|
[[ "$SELECTED_APPS" == *"open-webui"* ]] && run_module "Open WebUI" "$APPS/open-webui.sh"
|
||||||
SELECTED_APPS="${SELECTED_APPS/plymouth/}"
|
[[ "$SELECTED_APPS" == *"claude"* ]] && run_module "Claude Code" "$APPS/claude.sh"
|
||||||
fi
|
[[ "$SELECTED_APPS" == *"networking-cli"* ]] && run_module "Networking CLI" "$APPS/networking-cli.sh"
|
||||||
# END GENERATED MODULES: module-conflicts
|
[[ "$SELECTED_APPS" == *"disk-recovery"* ]] && run_module "Disk Recovery" "$APPS/disk-recovery.sh"
|
||||||
# BEGIN GENERATED MODULES: module-dispatch
|
[[ "$SELECTED_APPS" == *"himalaya"* ]] && run_module "Himalaya" "$APPS/himalaya.sh"
|
||||||
[[ "$SELECTED_APPS" == *"ollama"* ]] && run_module "ollama" "$APPS/ollama.sh"
|
[[ "$SELECTED_APPS" == *"mail-notmuch"* ]] && run_module "Mail (notmuch)" "$APPS/mail-notmuch.sh"
|
||||||
[[ "$SELECTED_APPS" == *"llama-cpp"* ]] && run_module "llama-cpp" "$APPS/llama-cpp.sh"
|
[[ "$SELECTED_APPS" == *"caldav-sync"* ]] && run_module "CalDAV Sync" "$APPS/caldav-sync.sh"
|
||||||
[[ "$SELECTED_APPS" == *"open-webui"* ]] && run_module "open-webui" "$APPS/open-webui.sh"
|
[[ "$SELECTED_APPS" == *"gnuplot"* ]] && run_module "Gnuplot" "$APPS/gnuplot.sh"
|
||||||
[[ "$SELECTED_APPS" == *"claude"* ]] && run_module "claude" "$APPS/claude.sh"
|
[[ "$SELECTED_APPS" == *"blender-povray"* ]] && run_module "Blender + POV-Ray" "$APPS/blender-povray.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" == *"toot"* ]] && run_module "toot" "$APPS/toot.sh"
|
||||||
[[ "$SELECTED_APPS" == *"db-clients"* ]] && run_module "db-clients" "$APPS/db-clients.sh"
|
[[ "$SELECTED_APPS" == *"db-clients"* ]] && run_module "DB Clients" "$APPS/db-clients.sh"
|
||||||
[[ "$SELECTED_APPS" == *"mysql"* ]] && run_module "mysql" "$APPS/mysql.sh"
|
[[ "$SELECTED_APPS" == *"mysql"* ]] && run_module "MySQL / MariaDB" "$APPS/mysql.sh"
|
||||||
[[ "$SELECTED_APPS" == *"productivity"* ]] && run_module "productivity" "$APPS/productivity.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" == *"yt-dlp"* ]] && run_module "yt-dlp" "$APPS/yt-dlp.sh"
|
||||||
[[ "$SELECTED_APPS" == *"gimp"* ]] && run_module "gimp" "$APPS/gimp.sh"
|
[[ "$SELECTED_APPS" == *"sox"* ]] && run_module "SoX" "$APPS/sox.sh"
|
||||||
[[ "$SELECTED_APPS" == *"inkscape"* ]] && run_module "inkscape" "$APPS/inkscape.sh"
|
[[ "$SELECTED_APPS" == *"imagemagick"* ]] && run_module "ImageMagick" "$APPS/imagemagick.sh"
|
||||||
[[ "$SELECTED_APPS" == *"krita"* ]] && run_module "krita" "$APPS/krita.sh"
|
[[ "$SELECTED_APPS" == *"ffmpeg"* ]] && run_module "FFmpeg extras" "$APPS/ffmpeg.sh"
|
||||||
[[ "$SELECTED_APPS" == *"kdenlive"* ]] && run_module "kdenlive" "$APPS/kdenlive.sh"
|
[[ "$SELECTED_APPS" == *"localtunnel"* ]] && run_module "LocalTunnel" "$APPS/localtunnel.sh"
|
||||||
[[ "$SELECTED_APPS" == *"openshot"* ]] && run_module "openshot" "$APPS/openshot.sh"
|
[[ "$SELECTED_APPS" == *"butter"* ]] && run_module "butter" "$APPS/butter.sh"
|
||||||
[[ "$SELECTED_APPS" == *"shotcut"* ]] && run_module "shotcut" "$APPS/shotcut.sh"
|
[[ "$SELECTED_APPS" == *"tlp"* ]] && run_module "TLP" "$APPS/tlp.sh"
|
||||||
[[ "$SELECTED_APPS" == *"ardour"* ]] && run_module "ardour" "$APPS/ardour.sh"
|
[[ "$SELECTED_APPS" == *"steam"* ]] && run_module "Steam" "$APPS/steam.sh"
|
||||||
[[ "$SELECTED_APPS" == *"audacity"* ]] && run_module "audacity" "$APPS/audacity.sh"
|
[[ "$SELECTED_APPS" == *"vesktop"* ]] && run_module "Vesktop" "$APPS/vesktop.sh"
|
||||||
[[ "$SELECTED_APPS" == *"lmms"* ]] && run_module "lmms" "$APPS/lmms.sh"
|
[[ "$SELECTED_APPS" == *"spotify"* ]] && run_module "Spotify" "$APPS/spotify.sh"
|
||||||
[[ "$SELECTED_APPS" == *"mixxx"* ]] && run_module "mixxx" "$APPS/mixxx.sh"
|
[[ "$SELECTED_APPS" == *"prism"* ]] && run_module "PrismLauncher" "$APPS/prismlauncher.sh"
|
||||||
[[ "$SELECTED_APPS" == *"cecilia"* ]] && run_module "cecilia" "$APPS/cecilia.sh"
|
[[ "$SELECTED_APPS" == *"vintagestory"* ]] && run_module "Vintage Story" "$APPS/vintagestory.sh"
|
||||||
[[ "$SELECTED_APPS" == *"chromium"* ]] && run_module "chromium" "$APPS/chromium.sh"
|
[[ "$SELECTED_APPS" == *"openarena"* ]] && run_module "OpenArena" "$APPS/openarena.sh"
|
||||||
[[ "$SELECTED_APPS" == *"firefox-browser"* ]] && run_module "firefox-browser" "$APPS/firefox-browser.sh"
|
[[ "$SELECTED_APPS" == *"tetris"* ]] && run_module "Tetris CLI" "$APPS/tetris.sh"
|
||||||
[[ "$SELECTED_APPS" == *"zen-browser"* ]] && run_module "zen-browser" "$APPS/zen-browser.sh"
|
[[ "$SELECTED_APPS" == *"doom"* ]] && run_module "Doom" "$APPS/doom.sh"
|
||||||
[[ "$SELECTED_APPS" == *"nyxt"* ]] && run_module "nyxt" "$APPS/nyxt.sh"
|
[[ "$SELECTED_APPS" == *"sauerbraten"* ]] && run_module "Sauerbraten" "$APPS/sauerbraten.sh"
|
||||||
[[ "$SELECTED_APPS" == *"librewolf"* ]] && run_module "librewolf" "$APPS/librewolf.sh"
|
[[ "$SELECTED_APPS" == *"stuntrally"* ]] && run_module "Stunt Rally" "$APPS/stuntrally.sh"
|
||||||
[[ "$SELECTED_APPS" == *"min-browser"* ]] && run_module "min-browser" "$APPS/min-browser.sh"
|
[[ "$SELECTED_APPS" == *"localsend"* ]] && run_module "LocalSend" "$APPS/localsend.sh"
|
||||||
[[ "$SELECTED_APPS" == *"vscodium"* ]] && run_module "vscodium" "$APPS/vscodium.sh"
|
[[ "$SELECTED_APPS" == *"croc"* ]] && run_module "croc" "$APPS/croc.sh"
|
||||||
[[ "$SELECTED_APPS" == *"zed-ide"* ]] && run_module "zed-ide" "$APPS/zed-ide.sh"
|
[[ "$SELECTED_APPS" == *"opendeck"* ]] && run_module "OpenDeck" "$APPS/opendeck.sh"
|
||||||
[[ "$SELECTED_APPS" == *"geany"* ]] && run_module "geany" "$APPS/geany.sh"
|
[[ "$SELECTED_APPS" == *"onlyoffice"* ]] && run_module "OnlyOffice" "$APPS/onlyoffice.sh"
|
||||||
[[ "$SELECTED_APPS" == *"codeblocks"* ]] && run_module "codeblocks" "$APPS/codeblocks.sh"
|
[[ "$SELECTED_APPS" == *"xournal"* ]] && run_module "Xournal++" "$APPS/xournal.sh"
|
||||||
[[ "$SELECTED_APPS" == *"kate"* ]] && run_module "kate" "$APPS/kate.sh"
|
[[ "$SELECTED_APPS" == *"rnote"* ]] && run_module "Rnote" "$APPS/rnote.sh"
|
||||||
[[ "$SELECTED_APPS" == *"rdp-client"* ]] && run_module "rdp-client" "$APPS/rdp-client.sh"
|
[[ "$SELECTED_APPS" == *"obsidian"* ]] && run_module "Obsidian" "$APPS/obsidian.sh"
|
||||||
[[ "$SELECTED_APPS" == *"lamco-rdp-server"* ]] && run_module "lamco-rdp-server" "$APPS/lamco-rdp-server.sh"
|
[[ "$SELECTED_APPS" == *"tangent-notes"* ]] && run_module "Tangent Notes" "$APPS/tangent-notes.sh"
|
||||||
[[ "$SELECTED_APPS" == *"qemu"* ]] && run_module "qemu" "$APPS/qemu.sh"
|
[[ "$SELECTED_APPS" == *"gimp"* ]] && run_module "GIMP" "$APPS/gimp.sh"
|
||||||
[[ "$SELECTED_APPS" == *"freeipa-client"* ]] && run_module "freeipa-client" "$APPS/freeipa-client.sh"
|
[[ "$SELECTED_APPS" == *"inkscape"* ]] && run_module "Inkscape" "$APPS/inkscape.sh"
|
||||||
[[ "$SELECTED_APPS" == *"freeipa-server"* ]] && run_module "freeipa-server" "$APPS/freeipa-server.sh"
|
[[ "$SELECTED_APPS" == *"krita"* ]] && run_module "Krita" "$APPS/krita.sh"
|
||||||
[[ "$SELECTED_APPS" == *"freeipa-image"* ]] && run_module "freeipa-image" "$APPS/freeipa-image.sh"
|
[[ "$SELECTED_APPS" == *"ardour"* ]] && run_module "Ardour" "$APPS/ardour.sh"
|
||||||
# END GENERATED MODULES: module-dispatch
|
[[ "$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"
|
||||||
|
|
||||||
# ── Colorway (final step) ─────────────────────────────────────────────────────
|
# ── Colorway (final step) ─────────────────────────────────────────────────────
|
||||||
# Read defaults from repo colors.conf for pre-population.
|
# Read defaults from repo colors.conf for pre-population.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue