diff --git a/AGENTS.md b/AGENTS.md index b7d813a..59f2fc3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md -Ansible-driven personal infrastructure repo for Void desktops, Linux workstations, WSL, and an Ubuntu server. +Ansible-driven personal infrastructure repo for Void desktops, Linux Mint and FreeBSD transition targets, Linux workstations, WSL, and an Ubuntu server. ## Source Of Truth - Main orchestration: `ansible/site.yml` @@ -11,14 +11,17 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation - Codex config is rendered from `dotfiles/common/.codex/config.toml.j2` so `model_instructions_file` points to the deployed `~/.config/ai/bootstrap.md`. ## Topology -- Void desktops: `ikaros`, `nymph` +- Current personal desktop: `ikaros = platform_mint + role_personal_workstation + desktop_cinnamon` +- Current laptop/lab: `nymph = platform_void + role_lab + desktop_niri` +- Void desktop profile is also the base for other future/reference hosts via `platform_void + graphical_desktop` - Native Linux workstation: `deadalus-fedora` - WSL dev: `deadalus-wsl` - Ubuntu server: `prometheus` - Hosts intentionally belong to multiple groups; trust `ansible/site.yml` over hostname assumptions. +- Inventory axes are independent: `platform_*`, `role_*`, and `desktop_*`. Legacy `void` and `desktop` remain compatibility parents. ## Working Rules -- Preserve layering `all -> OS -> profile -> host`. +- Preserve layering `all -> platform -> role -> desktop -> host`. - Keep `ansible/site.yml` small; orchestration belongs there, implementation belongs in roles. - Prefer minimal, targeted edits. Preserve idempotency and existing ordering. - All hosts use `ansible_connection: local`. @@ -34,12 +37,13 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation - `ansible-lint ansible/roles` - `yamllint ansible/` - Host-focused dry runs: - - Void desktop work: `ansible-playbook ansible/site.yml --limit ikaros --check --diff` or `--limit nymph --check --diff` + - Mint desktop work: `ansible-playbook ansible/site.yml --limit ikaros --check --diff` + - Void laptop work: `ansible-playbook ansible/site.yml --limit nymph --check --diff` - Fedora workstation: `ansible-playbook ansible/site.yml --limit deadalus-fedora --check --diff` - WSL dev: `ansible-playbook ansible/site.yml --limit deadalus-wsl --check --diff` - Server: `ansible-playbook ansible/site.yml --limit prometheus --check --diff` - Focused checks: - - Emacs dotfiles only: `ansible-playbook ansible/site.yml --limit ikaros --tags emacs --check --diff` or `--limit nymph --tags emacs --check --diff` + - Emacs is disabled by default; temporary Emacs check: `ansible-playbook ansible/site.yml --limit --tags emacs --check --diff -e emacs_enabled=true` - Mail bootstrap: `sh -n scripts/bootstrap_mail.sh` and `shellcheck scripts/bootstrap_mail.sh` - Server compose render: `docker compose -f /opt/docker/server/docker-compose.yml config` @@ -52,18 +56,23 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation - Use `no_log: true` for secret-bearing task inputs or outputs. ## Desktop Notes -- `desktop_environment` selects the mutually exclusive `minimal` (default), `xfce`, or `kde` desktop mode. `profile_desktop_common` owns shared bootstrap; the minimal mode uses `profile_desktop_sway` and `profile_desktop_hyprland`, `profile_desktop_xfce` owns the reproducible XFCE setup, and `profile_desktop_kde` owns KDE-specific defaults and cleanup. `desktop_sessions_enabled` and `desktop_default_session` apply only to the minimal mode. -- `.emacs.d` is deployed by a dedicated `profile_desktop_common` task tagged `emacs`. +- `desktop_profile` names independently selectable desktop groups such as `desktop_hyprland`, `desktop_sway`, `desktop_niri`, and `desktop_cinnamon`. Keep platform-specific session bootstrap in platform-specific roles. +- `desktop_environment` selects the mutually exclusive `minimal` (default), `xfce`, or `kde` desktop mode. `profile_desktop_common` owns shared bootstrap; the minimal mode uses `profile_desktop_sway`, `profile_desktop_hyprland`, and `profile_desktop_niri`, `profile_desktop_xfce` owns the reproducible XFCE setup, and `profile_desktop_kde` owns KDE-specific defaults and cleanup. `desktop_sessions_enabled` and `desktop_default_session` apply only to the minimal mode. +- Emacs packages and `.emacs.d` deploy are disabled by default via `emacs_enabled: false`; keep the dotfiles in the repo for reversible opt-in only. - NTFS filesystem support is provided by `ntfs-3g` in `ansible/inventory/group_vars/void.yml`. - Void user services are managed by `turnstile` and live under `dotfiles/desktop/.config/service/`. - `ssh-agent` keeps the stable socket `~/.local/state/ssh-agent/socket`. - Critical session entrypoints: - `dotfiles/desktop/.config/sway/config` plus `host.conf` and `session-env` deployed via `host_sway_dotfiles` (sway / Wayland) - `dotfiles/desktop/.config/hypr/hyprland.conf` plus `host.conf` and `session-env` deployed via `host_hyprland_dotfiles` (Hyprland / Wayland) + - `dotfiles/desktop/.config/niri/config.kdl` and `session-env` deployed via `desktop_niri_dotfiles` (Niri / Wayland) +- Void Niri (the `nymph` target) lives in `profile_desktop_niri`, gated on `'niri' in desktop_sessions_enabled`; it installs the `emptty` `niri.desktop` session, the `/usr/local/bin/start-niri` launcher, and the xdg-desktop-portal config, mirroring `profile_desktop_sway`. +- FreeBSD Niri (dormant; `platform_freebsd` currently has no hosts) must keep FreeBSD-specific package, rc, DBus, seat, portal, and launcher behavior in `profile_desktop_niri_freebsd` or FreeBSD platform vars. - Do not switch or restart a display manager during a playbook run from an active graphical session. Changing among `emptty`, LightDM, and SDDM requires an explicit run from another TTY/SSH session with `desktop_allow_display_manager_switch=true`. Apply managed XFCE XML while logged out of XFCE so `xfconfd` cannot overwrite it from its in-memory state. -- `nymph` is a Void laptop with NVIDIA Optimus, running sway (Wayland) and Hyprland (Wayland); host-specific tasks in `profile_desktop_host/tasks/nymph.yml` handle GRUB NVIDIA cmdline params, `prime-run` wrapper, and the WirePlumber camera priority config. Multi-monitor on sway is driven by `kanshi` (config deployed via `host_sway_dotfiles`), and on Hyprland by host-specific Hyprland monitor/workspace rules. +- `nymph` is the Void/Niri laptop target; prefer minimal scrollable-tiling defaults first, then host-specific tuning after real use. ## Void Package And Dotfile Bucket Rules +`platform_void` is the reusable Void platform selection. The legacy `void` group remains a compatibility parent so existing `group_vars/void.yml` and `when: "'void' in group_names"` checks keep working during the transition. The Void desktop package lists in `ansible/inventory/group_vars/void.yml` are kept disjoint by role: - `void_packages_base` — system runtime only (init/services, kernel, audio core, networking, filesystem, firewall, hardware daemons, runit logging). - `desktop_common_packages` — GUI infrastructure shared by all desktop modes. diff --git a/README.md b/README.md index 66f1961..b6e30cc 100644 --- a/README.md +++ b/README.md @@ -56,55 +56,84 @@ Il repository è diviso in due componenti principali: # Macchine gestite Il repository modella attualmente tre tipologie di profilo, con i filoni workstation Linux nativa e WSL. +La nuova direzione del repository separa tre assi indipendenti: + +```text +common user environment ++ host-specific platform ++ role-specific software ++ independently selectable desktop ++ host hardware overrides +``` + +Matrice target: + +| Host | Platform | Role | Desktop | +| -------------- | ---------- | -------------------- | --------------------------------- | +| ikaros | Linux Mint | Personal workstation | Cinnamon | +| nymph | Void Linux | Lab | Niri | +| void-reference | Void Linux | Lab/reference | Current preserved desktop profile | + +Regola operativa: + +```text +ikaros must be boring +nymph is allowed to break +``` + +`ikaros` usa il target stabile Linux Mint/Cinnamon; `nymph` usa il target +Void/Niri per il workflow laptop scrollable-tiling. I gruppi legacy `void` e +`desktop` restano alias di compatibilita per eventuali host Void futuri mentre i +nuovi assi sono `platform_*`, `role_*` e `desktop_*`. + +Prima di una migrazione reale degli host e consigliato creare uno snapshot +logico, per esempio: + +```bash +git switch -c refactor/platform-role-desktop +git tag void-desktop-before-platform-refactor +``` Nota sullo stato attuale del playbook principale: -- `ansible/site.yml` applica oggi in automatico il profilo desktop su host Void Linux +- `ansible/site.yml` applica oggi in automatico Cinnamon su Linux Mint e Niri su FreeBSD - `ansible/site.yml` applica la workstation Linux nativa separando il layer dev comune dal layer host GNOME - `ansible/site.yml` applica anche il ramo `workstation_dev_wsl` per il modello dev in WSL - `ansible/site.yml` applica anche il profilo `ubuntu_server` con baseline apt, systemd, dotfiles server e firewall UFW ## Desktop -Sistema operativo: +Target operativi: -- Void Linux +- `ikaros`: Linux Mint + Cinnamon, desktop personale stabile/floating. +- `nymph`: Void Linux + Niri, laptop scrollable-tiling per sfruttare meglio lo schermo piccolo. -Modalita desktop: - -- `minimal`: sway (Wayland) + Hyprland (Wayland), gestite da `emptty` -- `xfce`: XFCE puro con look scuro e sobrio, gestito da LightDM -- `kde`: KDE Plasma, gestito da SDDM - -Macchine: - -- `ikaros` -- `nymph` - -Queste macchine condividono la stessa configurazione base desktop e vengono mantenute allineate tramite Ansible. `desktop_environment` seleziona in modo esclusivo `minimal` (default), `xfce` oppure `kde`. Nella modalita minimale Sway/SwayFX e Hyprland sono installate in parallelo e selezionabili da `emptty`; `desktop_default_session` decide quale sessione viene preselezionata al login. XFCE usa direttamente la sessione `xfce` tramite LightDM. +Il profilo Void desktop resta disponibile come modello riutilizzabile per host +futuri. `desktop_environment` continua a selezionare in modo esclusivo +`minimal`, `xfce` oppure `kde` per i desktop Void; Niri e Cinnamon sono profili +desktop indipendenti via gruppi `desktop_niri` e `desktop_cinnamon`. Lo stato attuale del profilo desktop include, tra le altre cose: - dotfiles comuni e desktop -- sessioni sway e Hyprland su entrambi gli host in modalita `minimal` -- KDE Plasma con applicazioni KDE curate e SDDM disponibile come alternativa esclusiva -- XFCE con pannello, keybinding, terminale, tema e workspace dichiarativi, LightDM e Thunderbird come client grafico principale -- `emptty` con default host-specific in modalita `minimal`, con session file Wayland esposti per `sway` e `hyprland` +- sessioni sway e Hyprland per eventuali host Void in modalita `minimal` +- KDE Plasma con applicazioni KDE curate e SDDM disponibile come alternativa esclusiva +- XFCE con pannello, keybinding, terminale, tema e workspace dichiarativi, LightDM e Thunderbird come client grafico principale +- `emptty` con default host-specific in modalita `minimal`, con session file Wayland esposti per `sway` e `hyprland` - pacchetti Void Linux e servizi runit; le liste pacchetti Void desktop sono separate per criterio: - `void_packages_base` per il runtime sistema (init, kernel, audio core, networking, firewall, hw daemons) - - `desktop_common_packages` per l'infrastruttura condivisa dalle modalita - - `desktop_minimal_packages` per applicazioni GTK/XFCE e `emptty` - - `desktop_xfce_packages` per XFCE, LightDM e le relative integrazioni - - `desktop_kde_packages` per Plasma, SDDM e le applicazioni KDE equivalenti + - `desktop_common_packages` per l'infrastruttura condivisa dalle modalita + - `desktop_minimal_packages` per applicazioni GTK/XFCE e `emptty` + - `desktop_xfce_packages` per XFCE, LightDM e le relative integrazioni + - `desktop_kde_packages` per Plasma, SDDM e le applicazioni KDE equivalenti - `desktop_sway_packages` e `desktop_hyprland_packages` per i binari specifici di ciascuna sessione -- `turnstile` per i servizi utente, inclusi `emacs` e `ssh-agent` -- `ssh-agent` con socket stabile condiviso tra shell, SSH ed Emacs in `~/.local/state/ssh-agent/socket` -- `.emacs.d` distribuito da un task dedicato Ansible con tag `emacs` +- `turnstile` per i servizi utente Void, incluso `ssh-agent` +- `ssh-agent` con socket stabile condiviso tra shell e SSH in `~/.local/state/ssh-agent/socket` +- Emacs e i relativi dotfile restano nel repo ma sono disabilitati di default tramite `emacs_enabled: false` - `tmux` con plugin gestiti da TPM al bootstrap del profilo desktop - Flatpak con remoto Flathub -- GNOME Keyring e `udiskie` nella modalita minimale; KWallet e integrazione UDisks di Plasma nella modalita KDE -- multi-monitor: sotto sway è gestito da `kanshi` (config host-specifica in `host_sway_dotfiles` su `nymph`); sotto Hyprland gli override monitor vivono in `host_hyprland_dotfiles` -- override NVIDIA Optimus su `nymph`: parametri kernel GRUB iniettati in modo idempotente in `GRUB_CMDLINE_LINUX`, wrapper `prime-run` e config WirePlumber per priorità telecamera +- GNOME Keyring e `udiskie` nella modalita minimale; KWallet e integrazione UDisks di Plasma nella modalita KDE +- multi-monitor Void: sotto sway è gestito da `kanshi`; sotto Hyprland gli override monitor vivono in `host_hyprland_dotfiles` --- @@ -203,32 +232,27 @@ ansible-playbook ansible/site.yml --limit prometheus -e server_username=myuser - # Composizione della configurazione -Deploy mirato della configurazione Emacs sui desktop Void: +Emacs è disabilitato di default. Per riattivare temporaneamente il deploy Emacs: ```bash -ansible-playbook ansible/site.yml --limit ikaros --tags emacs -ansible-playbook ansible/site.yml --limit nymph --tags emacs +ansible-playbook ansible/site.yml --limit --tags emacs -e emacs_enabled=true ``` La configurazione finale di una macchina è ottenuta combinando più livelli. ```text common configuration -+ OS configuration -+ profile configuration ++ platform configuration ++ role configuration ++ desktop configuration + host overrides ``` -Esempio per `ikaros`: +Esempi correnti: ```text -common + void + desktop + ikaros -``` - -Esempio per `nymph`: - -```text -common + void + desktop + nymph +ikaros -> common + platform_mint + role_personal_workstation + desktop_cinnamon + ikaros +nymph -> common + platform_void + role_lab + desktop_niri + nymph ``` Questo approccio consente di: @@ -236,6 +260,8 @@ Questo approccio consente di: - mantenere configurazioni condivise - applicare override specifici per host - evitare duplicazioni +- riutilizzare il profilo Void corrente su un host futuro assegnandolo a + `platform_void + graphical_desktop + role_lab + desktop_hyprland` --- @@ -247,14 +273,21 @@ I principali ruoli attualmente presenti sono: | ------------------------- | ----------------------------------- | | base | configurazione base comune | | packages_void | installazione pacchetti su Void | +| packages_mint | installazione pacchetti su Linux Mint via APT | +| packages_freebsd | installazione pacchetti su FreeBSD via pkg | | packages_ubuntu | installazione pacchetti su Ubuntu | | packages_fedora | installazione pacchetti su Fedora | | services_runit | gestione servizi runit | | services_systemd | gestione servizi systemd | +| services_freebsd | gestione servizi FreeBSD rc.conf/rc.d | | profile_desktop_common | bootstrap desktop Void condiviso | | profile_desktop_sway | sessione desktop sway / SwayFX (Wayland) | | profile_desktop_hyprland | sessione desktop Hyprland (Wayland) | +| profile_desktop_niri_freebsd | adattamenti FreeBSD per Niri | +| profile_desktop_cinnamon | impostazioni Cinnamon circoscritte | | profile_desktop_host | override desktop specifici per host | +| profile_personal_workstation | layer stabile per workstation personale | +| profile_lab | layer sperimentale/lab | | profile_workstation_dev_common | configurazione dev workstation condivisa | | profile_workstation_gnome | configurazione host workstation GNOME | | profile_workstation_dev_wsl | configurazione WSL Ubuntu per sviluppo | @@ -266,11 +299,18 @@ I principali ruoli attualmente presenti sono: # Stato attuale del playbook principale -Il playbook `ansible/site.yml` e attualmente composto da sei blocchi: +Il playbook `ansible/site.yml` e attualmente composto da blocchi per asse: ```text all -> dotfiles_common -void -> packages_void + services_runit + profile_desktop_common + profile_desktop_sway + profile_desktop_hyprland + profile_desktop_host +platform_void -> packages_void + services_runit +platform_void & graphical_desktop -> profile_desktop_common + profile_desktop_sway + profile_desktop_hyprland + profile_desktop_kde + profile_desktop_xfce + profile_desktop_host +platform_mint -> packages_mint + services_systemd +platform_mint & role_personal_workstation -> profile_personal_workstation +platform_mint & desktop_cinnamon -> profile_desktop_cinnamon +platform_freebsd -> packages_freebsd + services_freebsd +platform_freebsd & role_lab -> profile_lab +platform_freebsd & desktop_niri -> profile_desktop_niri_freebsd workstation_dev_fedora -> packages_fedora + services_systemd + profile_workstation_dev_common workstation_host_linux -> profile_workstation_gnome workstation_dev_wsl -> packages_ubuntu + services_systemd + profile_workstation_dev_common + profile_workstation_dev_wsl @@ -279,7 +319,9 @@ ubuntu_server -> packages_ubuntu + services_systemd + profile_server Questo significa che, allo stato attuale: -- i desktop Void (`ikaros`, `nymph`) restano il target operativo piu completo +- `ikaros` riceve Linux Mint/Cinnamon come target stabile +- `nymph` riceve Void Linux/Niri come target laptop scrollable-tiling +- il profilo Void resta selezionabile tramite `platform_void + graphical_desktop` per host futuri - la workstation Fedora (`deadalus-fedora`) usa il principio di composizione a gruppi con il ramo Fedora dedicato e con `gsettings` host-specifici dichiarati in inventory - il ramo WSL (`deadalus-wsl`) e predisposto con play dev dedicato - il server Ubuntu (`prometheus`) e gestito con pacchetti, servizi, dotfiles server e firewall @@ -353,12 +395,14 @@ ansible-playbook ansible/site.yml Allo stato attuale questo comando: - distribuisce i dotfiles comuni a tutti gli host -- per gli host Void applica bootstrap desktop condiviso, sessioni sway/Hyprland e override specifici per host +- per `platform_void` applica pacchetti Void e servizi runit +- per `platform_void + graphical_desktop` applica bootstrap desktop condiviso, sessioni sway/Hyprland e override specifici per host +- per `platform_mint` e `platform_freebsd` applica solo host presenti esplicitamente in quei gruppi; nell'inventory principale iniziale questi gruppi sono vuoti - per `workstation_dev_fedora` applica pacchetti Fedora, servizi systemd e profilo dev comune - per `workstation_host_linux` applica il layer host Linux GNOME - per `workstation_dev_wsl` applica pacchetti Ubuntu, servizi systemd, profilo dev comune e tweak WSL dedicati - per gli host `ubuntu_server` applica pacchetti Ubuntu, servizi systemd, profilo server, UFW, dotfiles e template dedicati -- non riavvia automaticamente il display manager; i passaggi tra `emptty`, LightDM e SDDM vanno applicati da SSH o da una TTY separata +- non riavvia automaticamente il display manager; i passaggi tra `emptty`, LightDM e SDDM vanno applicati da SSH o da una TTY separata - carica `secrets/vault.yml` solo se presente - carica `secrets/vault.local.yml` solo se presente, dopo `vault.yml`, cosi gli override locali hanno precedenza @@ -366,6 +410,7 @@ Per validare prima di applicare: ```bash ansible-playbook ansible/site.yml --syntax-check +ansible-playbook ansible/site.yml --limit ikaros,nymph --check --diff ansible-playbook ansible/site.yml --limit ikaros --check --diff ansible-playbook ansible/site.yml --limit nymph --check --diff ansible-playbook ansible/site.yml --limit deadalus-fedora --check --diff @@ -400,14 +445,14 @@ Per vedere l'elenco reale aggiornato dei tag disponibili: ansible-playbook ansible/site.yml --list-tags ``` -Per attivare XFCE o KDE su un host, impostare rispettivamente `desktop_environment: xfce` o `desktop_environment: kde` nei relativi `host_vars` ed eseguire prima un dry run. Il primo play configura il profilo ma, se un altro display manager e ancora attivo, rinvia il cambio. Da una TTY o sessione SSH separata, con la sessione grafica chiusa, applicare quindi il passaggio esplicito: - -```bash -ansible-playbook ansible/site.yml --limit -e desktop_allow_display_manager_switch=true -``` - -La stessa procedura vale per ogni passaggio tra `minimal`, `xfce` e `kde`. Gli XML XFCE sono autorevoli: applicare i relativi aggiornamenti mentre XFCE e disconnesso evita che `xfconfd` ripristini lo stato in memoria. - +Per attivare XFCE o KDE su un host, impostare rispettivamente `desktop_environment: xfce` o `desktop_environment: kde` nei relativi `host_vars` ed eseguire prima un dry run. Il primo play configura il profilo ma, se un altro display manager e ancora attivo, rinvia il cambio. Da una TTY o sessione SSH separata, con la sessione grafica chiusa, applicare quindi il passaggio esplicito: + +```bash +ansible-playbook ansible/site.yml --limit -e desktop_allow_display_manager_switch=true +``` + +La stessa procedura vale per ogni passaggio tra `minimal`, `xfce` e `kde`. Gli XML XFCE sono autorevoli: applicare i relativi aggiornamenti mentre XFCE e disconnesso evita che `xfconfd` ripristini lo stato in memoria. + Allo stato attuale `ansible/site.yml` espone questi tag: | Tag | Scopo | Ambito principale | @@ -420,12 +465,14 @@ Allo stato attuale `ansible/site.yml` espone questi tag: | `dotfiles:server` | dotfiles dedicati al profilo server | server | | `dotfiles:workstation` | dotfiles dedicati alle workstation | workstation Linux, WSL | | `emptty` | gestione display manager `emptty` | desktop Void | -| `display-manager` | selezione protetta tra `emptty`, LightDM e SDDM | desktop Void | -| `kde` | profilo KDE Plasma e relativa pulizia | desktop Void | -| `xfce` | profilo XFCE, LightDM e relativa pulizia | desktop Void | +| `display-manager` | selezione protetta tra `emptty`, LightDM e SDDM | desktop Void | +| `kde` | profilo KDE Plasma e relativa pulizia | desktop Void | +| `xfce` | profilo XFCE, LightDM e relativa pulizia | desktop Void | +| `cinnamon` | impostazioni Cinnamon circoscritte | Linux Mint desktop | | `gnome` | configurazione host GNOME | workstation host Linux, parte desktop | | `sway` | sessione/configurazione sway / SwayFX (Wayland) | desktop Void | | `hyprland` | sessione/configurazione Hyprland (Wayland) | desktop Void | +| `niri` | sessione/configurazione Niri (Wayland) | FreeBSD laptop | | `npm` | installazione pacchetti npm globali | desktop Void, workstation Linux, WSL | | `nvidia` | componenti NVIDIA desktop | desktop Void | | `packages` | installazione e aggiornamento pacchetti | tutti i profili | @@ -436,9 +483,8 @@ Allo stato attuale `ansible/site.yml` espone questi tag: Esempi pratici: ```bash -ansible-playbook ansible/site.yml --limit nymph --tags dotfiles:desktop,sway --check --diff -ansible-playbook ansible/site.yml --limit ikaros --tags sway,portal --check --diff -ansible-playbook ansible/site.yml --limit ikaros --tags hyprland,portal --check --diff +ansible-playbook ansible/site.yml --limit nymph --tags dotfiles:desktop,niri --check --diff +ansible-playbook ansible/site.yml --limit ikaros --tags cinnamon --check --diff ansible-playbook ansible/site.yml --limit deadalus-fedora --tags packages,vscode --check --diff ansible-playbook ansible/site.yml --limit prometheus --tags services,dotfiles:server --check --diff ``` @@ -458,6 +504,22 @@ ansible-playbook ansible/site.yml Dopo l'esecuzione del playbook la macchina verra configurata secondo il profilo definito e i ruoli attualmente orchestrati. +Per aggiungere un nuovo host Void che riusa il profilo desktop preservato: + +1. aggiungere l'host a `platform_void`; +2. aggiungerlo a `graphical_desktop`; +3. scegliere il ruolo, per esempio `role_lab`; +4. scegliere il desktop, per esempio `desktop_hyprland`; +5. lasciare eventuali dettagli hardware in `host_vars/.yml`. + +I gruppi legacy `void` e `desktop` sono parent di compatibilita, quindi un host +in `platform_void` e `graphical_desktop` continua a ricevere anche le variabili +Void e desktop esistenti. + +Per prove in VM sono disponibili gruppi di esempio in +`ansible/inventory/examples/platform-test-hosts.yml`, da passare esplicitamente +con `-i` insieme all'inventory principale. + Per il flusso mail desktop esiste inoltre uno script dedicato: ```bash diff --git a/ansible/inventory/examples/platform-test-hosts.yml b/ansible/inventory/examples/platform-test-hosts.yml new file mode 100644 index 0000000..fdb61df --- /dev/null +++ b/ansible/inventory/examples/platform-test-hosts.yml @@ -0,0 +1,34 @@ +--- +# Optional inventory overlay for VM tests. It is not loaded by ansible.cfg. +all: + children: + platform_mint: + hosts: + minttest: + ansible_connection: local + + platform_freebsd: + hosts: + freebsdtest: + ansible_connection: local + + graphical_desktop: + hosts: + minttest: + freebsdtest: + + role_personal_workstation: + hosts: + minttest: + + role_lab: + hosts: + freebsdtest: + + desktop_cinnamon: + hosts: + minttest: + + desktop_hyprland: + hosts: + freebsdtest: diff --git a/ansible/inventory/group_vars/all.yml b/ansible/inventory/group_vars/all.yml index 072f4b7..4fe2de1 100644 --- a/ansible/inventory/group_vars/all.yml +++ b/ansible/inventory/group_vars/all.yml @@ -7,6 +7,7 @@ user_shell: /bin/bash effective_username: "{{ username }}" effective_user_group: "{{ user_group }}" effective_user_home: "{{ user_home }}" +emacs_enabled: false xdg_user_directories: - Desktop diff --git a/ansible/inventory/group_vars/desktop.yml b/ansible/inventory/group_vars/desktop.yml index 2f970d8..2596013 100644 --- a/ansible/inventory/group_vars/desktop.yml +++ b/ansible/inventory/group_vars/desktop.yml @@ -1,6 +1,4 @@ --- -desktop_protonmail_bridge_cert_path: ~/.var/app/ch.protonmail.protonmail-bridge/config/protonmail/bridge-v3/cert.pem - desktop_environment: minimal desktop_allow_display_manager_switch: false @@ -96,10 +94,6 @@ desktop_common_dotfiles: src: .bashrc.d/20-editor-desktop.sh dest: .bashrc.d/20-editor-desktop.sh mode: "0644" - - name: Bash Emacs client fragment - src: .bashrc.d/25-emacs-client-desktop.sh - dest: .bashrc.d/25-emacs-client-desktop.sh - mode: "0644" - name: Bash VM helper fragment src: .bashrc.d/30-runvm.sh dest: .bashrc.d/30-runvm.sh @@ -172,6 +166,10 @@ desktop_minimal_managed_paths: - .local/bin/udiskie-password desktop_emacs_dotfiles: + - name: Bash Emacs client fragment + src: .bashrc.d/25-emacs-client-desktop.sh + dest: .bashrc.d/25-emacs-client-desktop.sh + mode: "0644" - name: Emacs config src: .emacs.d/ dest: .emacs.d/ @@ -241,6 +239,28 @@ desktop_hyprland_dotfiles: dest: .config/foot/ mode: preserve +desktop_niri_dotfiles: + - name: foot config + src: .config/foot/ + dest: .config/foot/ + mode: preserve + - name: dunst config + src: .config/dunst/ + dest: .config/dunst/ + mode: preserve + - name: rofi config + src: .config/rofi/ + dest: .config/rofi/ + mode: preserve + - name: waybar config + src: .config/waybar/ + dest: .config/waybar/ + mode: preserve + - name: niri config + src: .config/niri/ + dest: .config/niri/ + mode: preserve + desktop_xfce_dotfiles: - name: XFCE configuration src: .config/xfce4/ diff --git a/ansible/inventory/group_vars/desktop_cinnamon.yml b/ansible/inventory/group_vars/desktop_cinnamon.yml new file mode 100644 index 0000000..7e2ac7b --- /dev/null +++ b/ansible/inventory/group_vars/desktop_cinnamon.yml @@ -0,0 +1,29 @@ +--- +desktop_profile: cinnamon +desktop_default_session: cinnamon + +cinnamon_theme_gtk: Mint-Y-Dark-Aqua +cinnamon_theme_icons: Mint-Y-Aqua +cinnamon_font_ui: Sans 10 +cinnamon_font_monospace: Monospace 10 + +# WM-agnostic desktop dotfiles from desktop_common_dotfiles that do NOT apply to +# Cinnamon: the autostart entry is the (removed) Protonmail mail bridge, and the +# GTK theme script conflicts with Cinnamon's own dconf-managed theming. +cinnamon_desktop_dotfiles_exclude: + - XDG autostart entries + - GTK theme setup script + +cinnamon_dconf_settings: + - key: /org/cinnamon/desktop/interface/gtk-theme + value: "'{{ cinnamon_theme_gtk }}'" + - key: /org/cinnamon/desktop/interface/icon-theme + value: "'{{ cinnamon_theme_icons }}'" + - key: /org/cinnamon/desktop/interface/font-name + value: "'{{ cinnamon_font_ui }}'" + - key: /org/cinnamon/desktop/interface/monospace-font-name + value: "'{{ cinnamon_font_monospace }}'" + - key: /org/cinnamon/desktop/interface/clock-use-24h + value: "true" + - key: /org/cinnamon/desktop/wm/preferences/button-layout + value: "'menu:minimize,maximize,close'" diff --git a/ansible/inventory/group_vars/desktop_hyprland.yml b/ansible/inventory/group_vars/desktop_hyprland.yml new file mode 100644 index 0000000..6fd1bb5 --- /dev/null +++ b/ansible/inventory/group_vars/desktop_hyprland.yml @@ -0,0 +1,3 @@ +--- +desktop_profile: hyprland +desktop_default_session: hyprland diff --git a/ansible/inventory/group_vars/desktop_niri.yml b/ansible/inventory/group_vars/desktop_niri.yml new file mode 100644 index 0000000..1f0f279 --- /dev/null +++ b/ansible/inventory/group_vars/desktop_niri.yml @@ -0,0 +1,5 @@ +--- +desktop_profile: niri +desktop_sessions_enabled: + - niri +desktop_default_session: niri diff --git a/ansible/inventory/group_vars/desktop_sway.yml b/ansible/inventory/group_vars/desktop_sway.yml new file mode 100644 index 0000000..ea77d69 --- /dev/null +++ b/ansible/inventory/group_vars/desktop_sway.yml @@ -0,0 +1,2 @@ +--- +desktop_profile: sway diff --git a/ansible/inventory/group_vars/graphical_desktop.yml b/ansible/inventory/group_vars/graphical_desktop.yml new file mode 100644 index 0000000..828cdc5 --- /dev/null +++ b/ansible/inventory/group_vars/graphical_desktop.yml @@ -0,0 +1,3 @@ +--- +host_capabilities: + - graphical_desktop diff --git a/ansible/inventory/group_vars/platform_freebsd.yml b/ansible/inventory/group_vars/platform_freebsd.yml new file mode 100644 index 0000000..353f434 --- /dev/null +++ b/ansible/inventory/group_vars/platform_freebsd.yml @@ -0,0 +1,108 @@ +--- +platform_profile: freebsd +platform_family: freebsd +platform_package_manager: pkg +platform_service_manager: rc +ansible_python_interpreter: /usr/local/bin/python3 + +effective_user_group: "{{ user_group }}" +effective_user_home: "/home/{{ effective_username }}" +user_home: "/home/{{ username }}" + +freebsd_packages_base: + - bash + - bash-completion + - bat + - curl + - fzf + - git + - jq + - python3 + - ripgrep + - rsync + - tmux + - tree + - unzip + - vim + - wget + - zip + - zoxide + +freebsd_development_packages: + - clang + - cmake + - gdb + - go + - gmake + - node + - npm + - pkgconf + - py311-pip + - rust + - shellcheck + +freebsd_desktop_common_packages: + - dbus + - dconf + - firefox + - fontconfig + - gnome-keyring + - libsecret + - mpv + - pinentry-gnome + - pipewire + - polkit + - thunderbird + - wireplumber + - xdg-desktop-portal + +freebsd_hyprland_packages: + - alacritty + - cliphist + - dunst + - foot + - grim + - hypridle + - hyprland + - hyprlock + - hyprpaper + - rofi-wayland + - seatd + - slurp + - waybar + - wl-clipboard + - xdg-desktop-portal-gtk + - xdg-desktop-portal-hyprland + - xwayland + +freebsd_niri_packages: + - cliphist + - dunst + - foot + - grim + - niri + - rofi-wayland + - seatd + - slurp + - waybar + - wl-clipboard + - xdg-desktop-portal-gtk + +freebsd_lab_packages: + - lldb + - llvm + - podman + - qemu + - smartmontools + +freebsd_rc_conf: + - name: dbus_enable + value: "YES" + - name: seatd_enable + value: "YES" + +freebsd_enabled_services: + - dbus + - seatd + +freebsd_xdg_config_dir: /usr/local/etc/xdg diff --git a/ansible/inventory/group_vars/platform_mint.yml b/ansible/inventory/group_vars/platform_mint.yml new file mode 100644 index 0000000..7aaa3f2 --- /dev/null +++ b/ansible/inventory/group_vars/platform_mint.yml @@ -0,0 +1,100 @@ +--- +platform_profile: mint +platform_family: debian +platform_package_manager: apt +platform_service_manager: systemd + +# syncthing runs per-user via the packaged system unit template +# (Debian/Mint ship syncthing@.service, parametrised by username). +enabled_services: + - "syncthing@{{ username }}.service" + +mint_manage_flatpak: true +mint_flatpak_remote_name: flathub +mint_flatpak_remote_url: https://dl.flathub.org/repo/flathub.flatpakrepo + +mint_packages_base: + - ca-certificates + - curl + - flatpak + - gpg + - htop + - make + - python3-pip + - ripgrep + - rsync + - shellcheck + +mint_development_packages: + - build-essential + - clang + - clang-tools + - cmake + - gdb + - golang + - nodejs + - npm + - pkg-config + - python3-venv + +mint_desktop_common_packages: + - dconf-cli + - deja-dup + - firefox + - fonts-liberation + - fonts-noto-color-emoji + - git-delta + - gnome-keyring + - libsecret-tools + - mpv + - pinentry-gnome3 + - pinentry-gtk2 + - rclone + - syncthing + - thunderbird + - tmux + - xdg-user-dirs + - yt-dlp + +mint_emacs_packages: + - autoconf + - automake + - emacs + - hunspell + - hunspell-it + - libfreetype-dev + - libpoppler-glib-dev + - libpoppler-private-dev + - libtool-bin + - libvterm-dev + - libx11-dev + +mint_cinnamon_packages: + - cinnamon + - cinnamon-control-center + - cinnamon-screensaver + - lightdm + - slick-greeter + - xdg-desktop-portal + - xdg-desktop-portal-gtk + +mint_personal_workstation_packages: + - libreoffice + - meld + - pdfarranger + - vim + +mint_flatpak_packages: + - ch.protonmail.protonmail-bridge + - com.calibre_ebook.calibre + - com.spotify.Client + - org.telegram.desktop + +# Nerd Fonts referenced by the desktop configs deployed on Mint. Debian has no +# equivalent of Void's nerd-fonts-ttf package, so they are fetched from the +# upstream ryanoasis/nerd-fonts release. +mint_nerd_fonts_version: v3.3.0 +mint_nerd_fonts: + - Hack + - UbuntuSans + - NerdFontsSymbolsOnly diff --git a/ansible/inventory/group_vars/platform_void.yml b/ansible/inventory/group_vars/platform_void.yml new file mode 100644 index 0000000..8be723a --- /dev/null +++ b/ansible/inventory/group_vars/platform_void.yml @@ -0,0 +1,5 @@ +--- +platform_profile: void +platform_family: void +platform_package_manager: xbps +platform_service_manager: runit diff --git a/ansible/inventory/group_vars/role_lab.yml b/ansible/inventory/group_vars/role_lab.yml new file mode 100644 index 0000000..c848bf4 --- /dev/null +++ b/ansible/inventory/group_vars/role_lab.yml @@ -0,0 +1,11 @@ +--- +machine_role: lab +role_profile: lab +role_stability: experimental +experimental_profile: true + +lab_workspace_directories: + - path: "{{ user_home }}/Lab" + mode: "0755" + - path: "{{ user_home }}/Scratch" + mode: "0755" diff --git a/ansible/inventory/group_vars/role_personal_workstation.yml b/ansible/inventory/group_vars/role_personal_workstation.yml new file mode 100644 index 0000000..b1e30bf --- /dev/null +++ b/ansible/inventory/group_vars/role_personal_workstation.yml @@ -0,0 +1,24 @@ +--- +machine_role: personal_workstation +role_profile: personal_workstation +role_stability: stable + +personal_workstation_directories: + - path: "{{ user_home }}/Documents" + mode: "0755" + - path: "{{ user_home }}/Downloads" + mode: "0755" + - path: "{{ user_home }}/Org" + mode: "0755" + - path: "{{ user_home }}/Remotes" + mode: "0755" + +personal_workstation_dotfiles: + - src: .gitignore_global + dest: .gitignore_global + mode: "0644" + - src: .themes.gitignore + dest: .themes.gitignore + mode: "0644" + +personal_workstation_flatpak_packages: [] diff --git a/ansible/inventory/group_vars/void.yml b/ansible/inventory/group_vars/void.yml index 23bfe14..117495f 100644 --- a/ansible/inventory/group_vars/void.yml +++ b/ansible/inventory/group_vars/void.yml @@ -23,7 +23,6 @@ void_packages_base: - go - hugo - ImageMagick - - isync - libtool - linux - linux-headers @@ -33,8 +32,6 @@ void_packages_base: - lm_sensors - man-pages-devel - man-pages-posix - - msmtp - - mu4e - nodejs - ntfs-3g - pipewire @@ -103,13 +100,15 @@ desktop_common_packages: - cups-pk-helper - flatpak - libsecret - - pinentry-emacs - sane - sane-airscan - turnstile - xdg-desktop-portal - xdg-user-dirs +desktop_emacs_packages: + - pinentry-emacs + desktop_minimal_packages: - alacritty - blueman @@ -222,6 +221,28 @@ desktop_hyprland_packages: - xdg-desktop-portal-hyprland - xorg-server-xwayland +desktop_niri_packages: + - cliphist + - dunst + - foot + - foot-terminfo + - gtklock + - grim + - niri + - rofi + - slurp + - SwayOSD + - Waybar + - wl-clipboard + - xdg-desktop-portal-gtk + - xorg-server-xwayland + +void_lab_packages: + - llvm + - podman + - qemu + - smartmontools + profile_packages: - bash-language-server - bluez @@ -231,7 +252,6 @@ profile_packages: - deluge-gtk - delve - dnsmasq - - emacs-pgtk - poppler-glib - poppler-utils - fontconfig-devel @@ -273,3 +293,6 @@ profile_packages: - yaru - yaru-plus - zstd + +profile_emacs_packages: + - emacs-pgtk diff --git a/ansible/inventory/host_vars/ikaros.yml b/ansible/inventory/host_vars/ikaros.yml index dfb2bb3..326f0ef 100644 --- a/ansible/inventory/host_vars/ikaros.yml +++ b/ansible/inventory/host_vars/ikaros.yml @@ -1,20 +1,11 @@ --- hostname: ikaros -desktop_sessions_enabled: - - sway - - hyprland - -desktop_default_session: hyprland -desktop_default_session_env: wayland - host_packages: - - openssh - - mesa-dri - - vulkan-loader - - mesa-vulkan-radeon - - mesa-vaapi - - xf86-video-amdgpu + - openssh-client + - openssh-server + - mesa-vulkan-drivers + - xserver-xorg-video-amdgpu host_ufw_rules: - rule: allow @@ -34,4 +25,4 @@ host_sshd_allow_users: host_authorized_ssh_keys: "{{ vault_ikaros_authorized_ssh_keys | default([]) }}" host_enabled_services: - - sshd + - ssh diff --git a/ansible/inventory/host_vars/nymph.yml b/ansible/inventory/host_vars/nymph.yml index 40a4cc7..dc2672c 100644 --- a/ansible/inventory/host_vars/nymph.yml +++ b/ansible/inventory/host_vars/nymph.yml @@ -1,50 +1,7 @@ --- hostname: nymph -desktop_sessions_enabled: - - sway - - hyprland - -desktop_default_session: hyprland -desktop_default_session_env: wayland -desktop_emptty_session_error_logging: rotate - -host_packages: - - nvidia580 - - linux-mainline-headers - - mesa-dri - - vulkan-loader - - mesa-vulkan-intel - - intel-video-accel - - power-profiles-daemon - - tlp - - tlp-rdw - - upower - -host_enabled_services: - - tlp - -host_sway_dotfiles: - - src: .config/sway/host.conf - dest: .config/sway/host.conf - mode: "0644" - - src: .config/sway/session-env - dest: .config/sway/session-env - mode: "0644" - - src: .config/kanshi/ - dest: .config/kanshi/ - mode: preserve - - src: .config/wireplumber/wireplumber.conf.d/60-camera-priority.conf - dest: .config/wireplumber/wireplumber.conf.d/60-camera-priority.conf - mode: "0644" - -host_hyprland_dotfiles: - - src: .config/hypr/host.conf - dest: .config/hypr/host.conf - mode: "0644" - - src: .config/hypr/session-env - dest: .config/hypr/session-env - mode: "0644" - - src: .config/wireplumber/wireplumber.conf.d/60-camera-priority.conf - dest: .config/wireplumber/wireplumber.conf.d/60-camera-priority.conf - mode: "0644" +# Void Linux/Niri laptop target. Keep host-specific packages empty until hardware +# support is verified on the installed system. +host_packages: [] +host_enabled_services: [] diff --git a/ansible/inventory/hosts.yml b/ansible/inventory/hosts.yml index f5e0ba1..d9d4ba5 100644 --- a/ansible/inventory/hosts.yml +++ b/ansible/inventory/hosts.yml @@ -1,7 +1,24 @@ --- all: children: + platform_void: + hosts: + nymph: + ansible_connection: local + + platform_mint: + hosts: + ikaros: + ansible_connection: local + + platform_freebsd: + hosts: {} + void: + children: + platform_void: + + graphical_desktop: hosts: ikaros: ansible_connection: local @@ -9,12 +26,35 @@ all: ansible_connection: local desktop: + children: + graphical_desktop: + + role_personal_workstation: hosts: ikaros: ansible_connection: local + + role_lab: + hosts: nymph: ansible_connection: local + desktop_sway: + hosts: {} + + desktop_hyprland: + hosts: {} + + desktop_niri: + hosts: + nymph: + ansible_connection: local + + desktop_cinnamon: + hosts: + ikaros: + ansible_connection: local + ubuntu: children: workstation_dev_wsl: diff --git a/ansible/roles/packages_freebsd/tasks/main.yml b/ansible/roles/packages_freebsd/tasks/main.yml new file mode 100644 index 0000000..23bde2d --- /dev/null +++ b/ansible/roles/packages_freebsd/tasks/main.yml @@ -0,0 +1,34 @@ +--- +- name: Install packages on FreeBSD + tags: [packages] + community.general.pkgng: + name: >- + {{ + ( + (freebsd_packages_base | default([])) + + (freebsd_development_packages | default([])) + + ( + (freebsd_desktop_common_packages | default([])) + if 'graphical_desktop' in group_names + else [] + ) + + ( + (freebsd_hyprland_packages | default([])) + if 'desktop_hyprland' in group_names + else [] + ) + + ( + (freebsd_niri_packages | default([])) + if 'desktop_niri' in group_names + else [] + ) + + ( + (freebsd_lab_packages | default([])) + if 'role_lab' in group_names + else [] + ) + + (host_packages | default([])) + ) + | unique + }} + state: present diff --git a/ansible/roles/packages_mint/tasks/main.yml b/ansible/roles/packages_mint/tasks/main.yml new file mode 100644 index 0000000..df40d33 --- /dev/null +++ b/ansible/roles/packages_mint/tasks/main.yml @@ -0,0 +1,88 @@ +--- +- name: Refresh apt package cache on Linux Mint + tags: [packages] + ansible.builtin.apt: + update_cache: true + cache_valid_time: 3600 + +- name: Install packages on Linux Mint + tags: [packages] + ansible.builtin.apt: + name: >- + {{ + ( + (common_packages | default([])) + + (mint_packages_base | default([])) + + (mint_development_packages | default([])) + + ( + (mint_desktop_common_packages | default([])) + if 'graphical_desktop' in group_names + else [] + ) + + ( + (mint_emacs_packages | default([])) + if ( + 'graphical_desktop' in group_names + and (emacs_enabled | default(false) | bool) + ) + else [] + ) + + ( + (mint_cinnamon_packages | default([])) + if 'desktop_cinnamon' in group_names + else [] + ) + + ( + (mint_personal_workstation_packages | default([])) + if 'role_personal_workstation' in group_names + else [] + ) + + (host_packages | default([])) + ) + | unique + }} + state: present + +- name: Ensure Flathub remote is configured on Linux Mint + tags: [packages] + community.general.flatpak_remote: + name: "{{ mint_flatpak_remote_name | default('flathub') }}" + state: present + flatpakrepo_url: "{{ mint_flatpak_remote_url | default('https://dl.flathub.org/repo/flathub.flatpakrepo') }}" + when: + - mint_manage_flatpak | default(true) + - >- + ( + (mint_flatpak_packages | default([])) + + (personal_workstation_flatpak_packages | default([])) + ) | length > 0 + +- name: Install Linux Mint Flatpak applications + tags: [packages] + community.general.flatpak: + name: >- + {{ + ( + (mint_flatpak_packages | default([])) + + ( + (personal_workstation_flatpak_packages | default([])) + if 'role_personal_workstation' in group_names + else [] + ) + ) + | unique + }} + state: present + remote: "{{ mint_flatpak_remote_name | default('flathub') }}" + method: system + when: + - mint_manage_flatpak | default(true) + - >- + ( + (mint_flatpak_packages | default([])) + + ( + (personal_workstation_flatpak_packages | default([])) + if 'role_personal_workstation' in group_names + else [] + ) + ) | length > 0 diff --git a/ansible/roles/packages_void/tasks/main.yml b/ansible/roles/packages_void/tasks/main.yml index 78c31ce..75829ee 100644 --- a/ansible/roles/packages_void/tasks/main.yml +++ b/ansible/roles/packages_void/tasks/main.yml @@ -76,6 +76,14 @@ ) else [] ) + + ( + (desktop_niri_packages | default([])) + if ( + (desktop_environment | default('minimal')) == 'minimal' + and 'niri' in (desktop_sessions_enabled | default([])) + ) + else [] + ) | unique }} @@ -88,6 +96,7 @@ (desktop_minimal_packages | default([])) + (desktop_sway_packages | default([])) + (desktop_hyprland_packages | default([])) + + (desktop_niri_packages | default([])) + (desktop_xfce_packages | default([])) + (desktop_kde_packages | default([])) ) @@ -105,8 +114,11 @@ (common_packages | default([])) + (void_packages_base | default([])) + (profile_packages | default([])) + + ((profile_emacs_packages | default([])) if (emacs_enabled | default(false) | bool) else []) + (desktop_common_packages | default([])) + + ((desktop_emacs_packages | default([])) if (emacs_enabled | default(false) | bool) else []) + (packages_void_selected_desktop_packages | default([])) + + ((void_lab_packages | default([])) if 'role_lab' in group_names else []) + (host_packages | default([])) ) | unique diff --git a/ansible/roles/profile_desktop_cinnamon/tasks/main.yml b/ansible/roles/profile_desktop_cinnamon/tasks/main.yml new file mode 100644 index 0000000..2e7b712 --- /dev/null +++ b/ansible/roles/profile_desktop_cinnamon/tasks/main.yml @@ -0,0 +1,229 @@ +--- +- name: Ensure Cinnamon user config directories exist + tags: [dotfiles, dotfiles:desktop, cinnamon] + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + loop: + - "{{ user_home }}/.config" + - "{{ user_home }}/.local" + - "{{ user_home }}/.local/share" + - "{{ user_home }}/.local/bin" + - "{{ user_home }}/.local/state" + - "{{ user_home }}/.bashrc.d" + - "{{ user_home }}/.tmux" + - "{{ user_home }}/.tmux/bin" + - "{{ user_home }}/.tmux/plugins" + +- name: Apply Cinnamon dconf settings + tags: [cinnamon] + community.general.dconf: + key: "{{ item.key }}" + value: "{{ item.value }}" + state: present + become: true + become_user: "{{ username }}" + environment: + HOME: "{{ user_home }}" + loop: "{{ cinnamon_dconf_settings | default([]) }}" + loop_control: + label: "{{ item.key }}" + +- name: Ensure Emacs config directory exists + tags: [dotfiles, dotfiles:desktop, emacs] + ansible.builtin.file: + path: "{{ user_home }}/.emacs.d" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + when: emacs_enabled | default(false) | bool + +- name: Ensure GnuPG directory exists + tags: [dotfiles, dotfiles:desktop, git] + ansible.builtin.file: + path: "{{ user_home }}/.gnupg" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0700" + +- name: Ensure private user directories exist + tags: [dotfiles, dotfiles:desktop] + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0700" + loop: + - "{{ user_home }}/.ssh" + - "{{ user_home }}/.local/state/ssh/sockets" + +- name: Copy Emacs desktop dotfiles + tags: [dotfiles, dotfiles:desktop, emacs] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ desktop_emacs_dotfiles | default([]) }}" + when: emacs_enabled | default(false) | bool + loop_control: + label: "{{ item.dest }}" + +- name: Copy WM-agnostic common desktop dotfiles + tags: [dotfiles, dotfiles:desktop] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: >- + {{ + desktop_common_dotfiles + | default([]) + | rejectattr('name', 'in', cinnamon_desktop_dotfiles_exclude | default([])) + | list + }} + loop_control: + label: "{{ item.dest }}" + +- name: Copy gpg-agent configuration + tags: [dotfiles, dotfiles:desktop, git] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/.gnupg/gpg-agent.conf" + dest: "{{ user_home }}/.gnupg/gpg-agent.conf" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0600" + +- name: Render git configuration with private values + tags: [dotfiles, dotfiles:desktop, git] + ansible.builtin.template: + src: desktop/.gitconfig.j2 + dest: "{{ user_home }}/.gitconfig" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0644" + +- name: Bootstrap tmux plugin manager checkout + tags: [dotfiles, dotfiles:desktop, tmux] + ansible.builtin.git: + repo: https://github.com/tmux-plugins/tpm + dest: "{{ user_home }}/.tmux/plugins/tpm" + version: master + update: true + become_user: "{{ username }}" + environment: + HOME: "{{ user_home }}" + +- name: Install tmux plugins through TPM + tags: [dotfiles, dotfiles:desktop, tmux] + ansible.builtin.command: + cmd: "{{ user_home }}/.tmux/plugins/tpm/bin/install_plugins" + become_user: "{{ username }}" + environment: + HOME: "{{ user_home }}" + register: cinnamon_tmux_plugin_install + changed_when: >- + (cinnamon_tmux_plugin_install.stdout | default('')) is search('download success') or + (cinnamon_tmux_plugin_install.stderr | default('')) is search('download success') + +- name: Install desktop npm packages + tags: [packages, npm] + community.general.npm: + name: "{{ item.name }}" + global: true + state: "{{ item.state | default('present') }}" + become: true + loop: "{{ desktop_npm_packages | default([]) }}" + when: desktop_npm_packages | length > 0 + loop_control: + label: "{{ item.name }}" + +- name: Ensure /usr/src is writable for source builds + tags: [packages] + ansible.builtin.file: + path: /usr/src + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + +- name: Build and install the gf debugger frontend from source + tags: [packages] + ansible.builtin.include_tasks: + file: "{{ role_path }}/../profile_desktop_common/tasks/source_tool.yml" + apply: + tags: [packages] + loop: >- + {{ + desktop_source_tools + | default([]) + | selectattr('name', 'equalto', 'gf') + | list + }} + loop_control: + loop_var: source_tool + label: "{{ source_tool.name }}" + +- name: Ensure Nerd Fonts base directory exists + tags: [packages, fonts] + ansible.builtin.file: + path: /usr/local/share/fonts/nerd-fonts + state: directory + owner: root + group: root + mode: "0755" + become: true + +- name: Ensure per-font Nerd Fonts directories exist + tags: [packages, fonts] + ansible.builtin.file: + path: "/usr/local/share/fonts/nerd-fonts/{{ item }}" + state: directory + owner: root + group: root + mode: "0755" + become: true + loop: "{{ mint_nerd_fonts | default([]) }}" + +- name: Download Nerd Font archives + tags: [packages, fonts] + ansible.builtin.get_url: + url: "https://github.com/ryanoasis/nerd-fonts/releases/download/{{ mint_nerd_fonts_version }}/{{ item }}.zip" + dest: "/usr/local/share/fonts/nerd-fonts/{{ item }}.zip" + owner: root + group: root + mode: "0644" + become: true + loop: "{{ mint_nerd_fonts | default([]) }}" + loop_control: + label: "{{ item }}" + +- name: Extract Nerd Font archives + tags: [packages, fonts] + ansible.builtin.unarchive: + src: "/usr/local/share/fonts/nerd-fonts/{{ item }}.zip" + dest: "/usr/local/share/fonts/nerd-fonts/{{ item }}" + remote_src: true + owner: root + group: root + become: true + loop: "{{ mint_nerd_fonts | default([]) }}" + loop_control: + label: "{{ item }}" + register: cinnamon_nerd_fonts_extract + +- name: Refresh system font cache after installing Nerd Fonts + tags: [packages, fonts] + ansible.builtin.command: fc-cache -f + become: true + changed_when: false + when: cinnamon_nerd_fonts_extract is changed diff --git a/ansible/roles/profile_desktop_common/tasks/main.yml b/ansible/roles/profile_desktop_common/tasks/main.yml index 07db78f..be83a57 100644 --- a/ansible/roles/profile_desktop_common/tasks/main.yml +++ b/ansible/roles/profile_desktop_common/tasks/main.yml @@ -9,7 +9,7 @@ or (desktop_sessions_enabled | default([]) | length > 0) - >- (desktop_environment | default('minimal')) != 'minimal' - or (desktop_sessions_enabled | default([]) | difference(['sway', 'hyprland']) | length == 0) + or (desktop_sessions_enabled | default([]) | difference(['sway', 'hyprland', 'niri']) | length == 0) - >- (desktop_environment | default('minimal')) != 'minimal' or desktop_default_session in (desktop_sessions_enabled | default([])) @@ -315,32 +315,18 @@ group: "{{ user_group }}" mode: "{{ item.mode }}" loop: "{{ desktop_emacs_dotfiles | default([]) }}" + when: emacs_enabled | default(false) | bool loop_control: label: "{{ item.dest }}" -- name: Render desktop templates with private values - tags: [dotfiles, dotfiles:desktop] +- name: Render git configuration with private values + tags: [dotfiles, dotfiles:desktop, git] ansible.builtin.template: - src: "{{ item.src }}" - dest: "{{ user_home }}/{{ item.dest }}" + src: desktop/.gitconfig.j2 + dest: "{{ user_home }}/.gitconfig" owner: "{{ username }}" group: "{{ user_group }}" - mode: "{{ item.mode }}" - loop: - - src: desktop/.gitconfig.j2 - dest: .gitconfig - mode: "0644" - - src: desktop/.mbsyncrc.j2 - dest: .mbsyncrc - mode: "0600" - - src: desktop/.msmtprc.j2 - dest: .msmtprc - mode: "0600" - - src: desktop/email.el.j2 - dest: .emacs.d/lisp/misc/email.el - mode: "0644" - loop_control: - label: "{{ item.dest }}" + mode: "0644" - name: Define managed tmux plugin directories tags: [dotfiles, dotfiles:desktop, tmux] @@ -451,19 +437,6 @@ - path: /usr/src mode: "0755" -- name: Ensure maildir directories exist - tags: [dotfiles, dotfiles:desktop] - ansible.builtin.file: - path: "{{ item }}" - state: directory - owner: "{{ username }}" - group: "{{ user_group }}" - mode: "0700" - loop: - - "{{ user_home }}/Maildir" - - "{{ user_home }}/Maildir/iCloudAccount" - - "{{ user_home }}/Maildir/ProtonMailAccount" - - name: Make Qt apps follow the GTK theme tags: [theme] ansible.builtin.copy: @@ -592,7 +565,7 @@ label: "{{ item.name }}" - name: Install desktop Python tools with uv - tags: [packages, emacs] + tags: [packages] ansible.builtin.command: cmd: "uv tool install --upgrade {{ item }}" become: true diff --git a/ansible/roles/profile_desktop_hyprland_freebsd/files/hyprland-portals.conf b/ansible/roles/profile_desktop_hyprland_freebsd/files/hyprland-portals.conf new file mode 100644 index 0000000..9ba090c --- /dev/null +++ b/ansible/roles/profile_desktop_hyprland_freebsd/files/hyprland-portals.conf @@ -0,0 +1,4 @@ +[preferred] +default=gtk +org.freedesktop.impl.portal.Screenshot=hyprland +org.freedesktop.impl.portal.ScreenCast=hyprland diff --git a/ansible/roles/profile_desktop_hyprland_freebsd/tasks/main.yml b/ansible/roles/profile_desktop_hyprland_freebsd/tasks/main.yml new file mode 100644 index 0000000..842dc31 --- /dev/null +++ b/ansible/roles/profile_desktop_hyprland_freebsd/tasks/main.yml @@ -0,0 +1,58 @@ +--- +- name: Ensure FreeBSD Hyprland user config directories exist + tags: [dotfiles, dotfiles:desktop, hyprland] + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + loop: + - "{{ user_home }}/.config" + - "{{ user_home }}/.config/alacritty" + - "{{ user_home }}/.config/dunst" + - "{{ user_home }}/.config/foot" + - "{{ user_home }}/.config/hypr" + - "{{ user_home }}/.config/rofi" + - "{{ user_home }}/.config/waybar" + - "{{ user_home }}/.local" + - "{{ user_home }}/.local/bin" + +- name: Copy common Hyprland desktop dotfiles on FreeBSD + tags: [dotfiles, dotfiles:desktop, hyprland] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ desktop_hyprland_dotfiles | default([]) }}" + loop_control: + label: "{{ item.dest }}" + +- name: Render FreeBSD Hyprland session launcher + tags: [packages, services, hyprland] + ansible.builtin.template: + src: start-hyprland-session.j2 + dest: /usr/local/bin/start-hyprland-session + owner: root + group: wheel + mode: "0755" + +- name: Ensure FreeBSD xdg-desktop-portal config directory exists + tags: [packages, services, hyprland, portal] + ansible.builtin.file: + path: "{{ freebsd_xdg_config_dir | default('/usr/local/etc/xdg') }}/xdg-desktop-portal" + state: directory + owner: root + group: wheel + mode: "0755" + +- name: Configure xdg-desktop-portal backend preferences for FreeBSD Hyprland + tags: [packages, services, hyprland, portal] + ansible.builtin.copy: + src: hyprland-portals.conf + dest: "{{ freebsd_xdg_config_dir | default('/usr/local/etc/xdg') }}/xdg-desktop-portal/hyprland-portals.conf" + owner: root + group: wheel + mode: "0644" diff --git a/ansible/roles/profile_desktop_hyprland_freebsd/templates/start-hyprland-session.j2 b/ansible/roles/profile_desktop_hyprland_freebsd/templates/start-hyprland-session.j2 new file mode 100644 index 0000000..7653ad0 --- /dev/null +++ b/ansible/roles/profile_desktop_hyprland_freebsd/templates/start-hyprland-session.j2 @@ -0,0 +1,24 @@ +#!/bin/sh + +[ -r /etc/profile ] && . /etc/profile +[ -r "$HOME/.profile" ] && . "$HOME/.profile" + +export XDG_CURRENT_DESKTOP=Hyprland +export XDG_SESSION_DESKTOP=Hyprland +export XDG_SESSION_TYPE=wayland + +export MOZ_ENABLE_WAYLAND=1 +export QT_QPA_PLATFORM='wayland;xcb' +export _JAVA_AWT_WM_NONREPARENTING=1 +export SDL_VIDEODRIVER=wayland +export GDK_BACKEND='wayland,x11' + +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" + +[ -r "$HOME/.config/hypr/session-env" ] && . "$HOME/.config/hypr/session-env" + +if command -v dbus-run-session >/dev/null 2>&1; then + exec dbus-run-session Hyprland +fi + +exec Hyprland diff --git a/ansible/roles/profile_desktop_niri/files/niri-portals.conf b/ansible/roles/profile_desktop_niri/files/niri-portals.conf new file mode 100644 index 0000000..1af058f --- /dev/null +++ b/ansible/roles/profile_desktop_niri/files/niri-portals.conf @@ -0,0 +1,4 @@ +[preferred] +default=gtk +org.freedesktop.impl.portal.Screenshot=gtk +org.freedesktop.impl.portal.ScreenCast=gtk diff --git a/ansible/roles/profile_desktop_niri/files/niri.desktop b/ansible/roles/profile_desktop_niri/files/niri.desktop new file mode 100644 index 0000000..1e53c3f --- /dev/null +++ b/ansible/roles/profile_desktop_niri/files/niri.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=Niri +Comment=Niri scrollable-tiling (Wayland) +Exec=/usr/local/bin/start-niri +Type=Application diff --git a/ansible/roles/profile_desktop_niri/tasks/main.yml b/ansible/roles/profile_desktop_niri/tasks/main.yml new file mode 100644 index 0000000..502529d --- /dev/null +++ b/ansible/roles/profile_desktop_niri/tasks/main.yml @@ -0,0 +1,81 @@ +--- +- name: Ensure niri config directories exist + tags: [dotfiles, dotfiles:desktop, niri] + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + loop: + - "{{ user_home }}/.config/foot" + - "{{ user_home }}/.config/dunst" + - "{{ user_home }}/.config/rofi" + - "{{ user_home }}/.config/waybar" + - "{{ user_home }}/.config/niri" + when: + - (desktop_environment | default('minimal')) == 'minimal' + - "'niri' in (desktop_sessions_enabled | default([]))" + +- name: Install allowed emptty Wayland sessions + tags: [packages, services, emptty, niri] + ansible.builtin.copy: + src: niri.desktop + dest: /etc/emptty/wayland-sessions/niri.desktop + owner: root + group: root + mode: "0644" + when: + - (desktop_environment | default('minimal')) == 'minimal' + - "'niri' in (desktop_sessions_enabled | default([]))" + +- name: Install Niri session launcher in /usr/local/bin + tags: [packages, services, niri] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/.local/bin/start-niri" + dest: /usr/local/bin/start-niri + owner: root + group: root + mode: "0755" + when: + - (desktop_environment | default('minimal')) == 'minimal' + - "'niri' in (desktop_sessions_enabled | default([]))" + +- name: Ensure /etc/xdg/xdg-desktop-portal exists + tags: [packages, services, niri, portal] + ansible.builtin.file: + path: /etc/xdg/xdg-desktop-portal + state: directory + owner: root + group: root + mode: "0755" + when: + - (desktop_environment | default('minimal')) == 'minimal' + - "'niri' in (desktop_sessions_enabled | default([]))" + +- name: Configure xdg-desktop-portal backend preferences for niri + tags: [packages, services, niri, portal] + ansible.builtin.copy: + src: niri-portals.conf + dest: /etc/xdg/xdg-desktop-portal/niri-portals.conf + owner: root + group: root + mode: "0644" + when: + - (desktop_environment | default('minimal')) == 'minimal' + - "'niri' in (desktop_sessions_enabled | default([]))" + +- name: Copy niri desktop dotfiles + tags: [dotfiles, dotfiles:desktop, niri] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ desktop_niri_dotfiles | default([]) }}" + loop_control: + label: "{{ item.dest }}" + when: + - (desktop_environment | default('minimal')) == 'minimal' + - "'niri' in (desktop_sessions_enabled | default([]))" diff --git a/ansible/roles/profile_desktop_niri_freebsd/tasks/main.yml b/ansible/roles/profile_desktop_niri_freebsd/tasks/main.yml new file mode 100644 index 0000000..51d1f58 --- /dev/null +++ b/ansible/roles/profile_desktop_niri_freebsd/tasks/main.yml @@ -0,0 +1,41 @@ +--- +- name: Ensure FreeBSD Niri user config directories exist + tags: [dotfiles, dotfiles:desktop, niri] + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + loop: + - "{{ user_home }}/.config" + - "{{ user_home }}/.config/dunst" + - "{{ user_home }}/.config/foot" + - "{{ user_home }}/.config/niri" + - "{{ user_home }}/.config/rofi" + - "{{ user_home }}/.config/waybar" + - "{{ user_home }}/.local" + - "{{ user_home }}/.local/bin" + - "{{ user_home }}/.local/state" + - "{{ user_home }}/.local/state/ssh-agent" + +- name: Copy common Niri desktop dotfiles on FreeBSD + tags: [dotfiles, dotfiles:desktop, niri] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ desktop_niri_dotfiles | default([]) }}" + loop_control: + label: "{{ item.dest }}" + +- name: Render FreeBSD Niri session launcher + tags: [packages, services, niri] + ansible.builtin.template: + src: start-niri-session.j2 + dest: /usr/local/bin/start-niri-session + owner: root + group: wheel + mode: "0755" diff --git a/ansible/roles/profile_desktop_niri_freebsd/templates/start-niri-session.j2 b/ansible/roles/profile_desktop_niri_freebsd/templates/start-niri-session.j2 new file mode 100644 index 0000000..2101951 --- /dev/null +++ b/ansible/roles/profile_desktop_niri_freebsd/templates/start-niri-session.j2 @@ -0,0 +1,24 @@ +#!/bin/sh + +[ -r /etc/profile ] && . /etc/profile +[ -r "$HOME/.profile" ] && . "$HOME/.profile" + +export XDG_CURRENT_DESKTOP=niri +export XDG_SESSION_DESKTOP=niri +export XDG_SESSION_TYPE=wayland + +export MOZ_ENABLE_WAYLAND=1 +export QT_QPA_PLATFORM='wayland;xcb' +export _JAVA_AWT_WM_NONREPARENTING=1 +export SDL_VIDEODRIVER=wayland +export GDK_BACKEND='wayland,x11' + +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" + +[ -r "$HOME/.config/niri/session-env" ] && . "$HOME/.config/niri/session-env" + +if command -v dbus-run-session >/dev/null 2>&1; then + exec dbus-run-session niri --session +fi + +exec niri --session diff --git a/ansible/roles/profile_lab/tasks/main.yml b/ansible/roles/profile_lab/tasks/main.yml new file mode 100644 index 0000000..074f3d3 --- /dev/null +++ b/ansible/roles/profile_lab/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: Ensure lab workspace directories exist + tags: [dotfiles] + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ lab_workspace_directories | default([]) }}" + loop_control: + label: "{{ item.path }}" diff --git a/ansible/roles/profile_personal_workstation/tasks/main.yml b/ansible/roles/profile_personal_workstation/tasks/main.yml new file mode 100644 index 0000000..f7b00c5 --- /dev/null +++ b/ansible/roles/profile_personal_workstation/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: Ensure personal workstation directories exist + tags: [dotfiles, dotfiles:workstation] + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ personal_workstation_directories | default([]) }}" + loop_control: + label: "{{ item.path }}" + +- name: Copy personal workstation dotfiles + tags: [dotfiles, dotfiles:workstation] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/workstation/{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ personal_workstation_dotfiles | default([]) }}" + loop_control: + label: "{{ item.dest }}" diff --git a/ansible/roles/services_freebsd/tasks/main.yml b/ansible/roles/services_freebsd/tasks/main.yml new file mode 100644 index 0000000..36b5aef --- /dev/null +++ b/ansible/roles/services_freebsd/tasks/main.yml @@ -0,0 +1,20 @@ +--- +- name: Configure FreeBSD rc.conf values + tags: [services, packages] + community.general.sysrc: + name: "{{ item.name }}" + value: "{{ item.value }}" + state: present + loop: "{{ freebsd_rc_conf | default([]) }}" + loop_control: + label: "{{ item.name }}" + +- name: Enable FreeBSD rc services + tags: [services, packages] + ansible.builtin.service: + name: "{{ item }}" + enabled: true + state: started + loop: "{{ freebsd_enabled_services | default([]) + host_enabled_services | default([]) }}" + loop_control: + label: "{{ item }}" diff --git a/ansible/roles/services_systemd/tasks/main.yml b/ansible/roles/services_systemd/tasks/main.yml index 51ba75b..43a3482 100644 --- a/ansible/roles/services_systemd/tasks/main.yml +++ b/ansible/roles/services_systemd/tasks/main.yml @@ -18,4 +18,3 @@ loop: "{{ host_enabled_services | default([]) }}" loop_control: label: "{{ item }}" - diff --git a/ansible/site.yml b/ansible/site.yml index a6ddef3..928d77e 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -1,36 +1,101 @@ --- -- hosts: all +- name: Configure common user environment + hosts: all become: true pre_tasks: - name: Load local vault variables when available tags: [always] ansible.builtin.include_vars: file: "{{ playbook_dir }}/../secrets/vault.yml" - when: lookup('ansible.builtin.fileglob', playbook_dir + '/../secrets/vault.yml', errors='ignore', wantlist=True) | length > 0 + when: >- + lookup('ansible.builtin.fileglob', playbook_dir + '/../secrets/vault.yml', + errors='ignore', wantlist=True) | length > 0 - name: Load machine-local vault variables when available tags: [always] ansible.builtin.include_vars: file: "{{ playbook_dir }}/../secrets/vault.local.yml" - when: lookup('ansible.builtin.fileglob', playbook_dir + '/../secrets/vault.local.yml', errors='ignore', wantlist=True) | length > 0 + when: >- + lookup('ansible.builtin.fileglob', playbook_dir + '/../secrets/vault.local.yml', + errors='ignore', wantlist=True) | length > 0 roles: - dotfiles_common -- hosts: void +- name: Configure Void platform + hosts: platform_void become: true roles: - packages_void - services_runit + +- name: Configure Void graphical desktop + hosts: platform_void:&graphical_desktop + become: true + + roles: - profile_desktop_common - profile_desktop_sway - profile_desktop_hyprland + - profile_desktop_niri - profile_desktop_kde - profile_desktop_xfce - profile_desktop_host -- hosts: workstation_dev_fedora +- name: Configure lab role on Void + hosts: platform_void:&role_lab + become: true + + roles: + - profile_lab + +- name: Configure Linux Mint platform + hosts: platform_mint + become: true + + roles: + - packages_mint + - services_systemd + +- name: Configure personal workstation role on Linux Mint + hosts: platform_mint:&role_personal_workstation + become: true + + roles: + - profile_personal_workstation + +- name: Configure Cinnamon desktop on Linux Mint + hosts: platform_mint:&desktop_cinnamon + become: true + + roles: + - profile_desktop_cinnamon + +- name: Configure FreeBSD platform + hosts: platform_freebsd + become: true + + roles: + - packages_freebsd + - services_freebsd + +- name: Configure lab role on FreeBSD + hosts: platform_freebsd:&role_lab + become: true + + roles: + - profile_lab + +- name: Configure Niri desktop on FreeBSD + hosts: platform_freebsd:&desktop_niri + become: true + + roles: + - profile_desktop_niri_freebsd + +- name: Configure Fedora workstation development layer + hosts: workstation_dev_fedora become: true roles: @@ -38,13 +103,15 @@ - services_systemd - profile_workstation_dev_common -- hosts: workstation_host_linux +- name: Configure native Linux workstation host layer + hosts: workstation_host_linux become: true roles: - profile_workstation_gnome -- hosts: workstation_dev_wsl +- name: Configure WSL workstation development layer + hosts: workstation_dev_wsl become: true roles: @@ -53,7 +120,8 @@ - profile_workstation_dev_common - profile_workstation_dev_wsl -- hosts: ubuntu_server +- name: Configure Ubuntu server + hosts: ubuntu_server become: true roles: diff --git a/ansible/templates/desktop/.gitconfig.j2 b/ansible/templates/desktop/.gitconfig.j2 index 3db770a..3a2d06d 100644 --- a/ansible/templates/desktop/.gitconfig.j2 +++ b/ansible/templates/desktop/.gitconfig.j2 @@ -29,9 +29,19 @@ [mergetool] prompt = false +[mergetool "meld"] + cmd = meld "$LOCAL" "$BASE" "$REMOTE" --output "$MERGED" + trustExitCode = false + [diff] tool = meld +[difftool] + prompt = false + +[difftool "meld"] + cmd = meld "$LOCAL" "$REMOTE" + [color] ui = always diff --git a/ansible/templates/desktop/.mbsyncrc.j2 b/ansible/templates/desktop/.mbsyncrc.j2 deleted file mode 100644 index 7746945..0000000 --- a/ansible/templates/desktop/.mbsyncrc.j2 +++ /dev/null @@ -1,47 +0,0 @@ -##################### iCloud Account ################################## -IMAPStore iCloud-remote - Host imap.mail.me.com - Port 993 - User {{ vault_icloud_email }} - PassCmd "secret-tool lookup icloud-mail icloud" - AuthMechs * - TLSType IMAPS - TLSVersions +1.2 +1.3 - PipelineDepth 1 - -MaildirStore iCloud-local - Path ~/Maildir/iCloudAccount/ - Inbox ~/Maildir/iCloudAccount/INBOX - SubFolders Verbatim - -Channel iCloud - Far :iCloud-remote: - Near :iCloud-local: - Patterns * - Create Both - Expunge Both - SyncState * - -##################### Protonmail Account ################################## -IMAPStore protonmail-remote - Host 127.0.0.1 - Port 1143 - User {{ vault_protonmail_email }} - PassCmd "secret-tool lookup protonmail-bridge protonmail" - AuthMechs * - TLSType STARTTLS - PipelineDepth 1 - CertificateFile {{ desktop_protonmail_bridge_cert_path }} - -MaildirStore protonmail-local - Path ~/Maildir/ProtonMailAccount/ - Inbox ~/Maildir/ProtonMailAccount/INBOX - SubFolders Verbatim - -Channel Protonmail - Far :protonmail-remote: - Near :protonmail-local: - Patterns * - Create Both - Expunge Both - SyncState * diff --git a/ansible/templates/desktop/.msmtprc.j2 b/ansible/templates/desktop/.msmtprc.j2 deleted file mode 100644 index ee9b357..0000000 --- a/ansible/templates/desktop/.msmtprc.j2 +++ /dev/null @@ -1,51 +0,0 @@ -# Set default values for all following accounts. -defaults - -# Always use TLS -tls on - -# Set a list of trusted CAs for TLS. The default is to use system settings, -# but you can select your own file. -tls_trust_file /etc/ssl/certs/ca-certificates.crt -logfile ~/.cache/msmtp.log - -# Account iCloud -account icloud - -# Host name of the SMTP server -host smtp.mail.me.com - -# Use the mail submission port 587 instead of the SMTP port 25 -port 587 - -# Envelop-from address -from {{ vault_icloud_email }} - -# Authentication. The password is given using one of five methods -auth on -user {{ vault_icloud_email }} -passwordeval "secret-tool lookup icloud-mail icloud" - -# Account Protonmail -account protonmail - -# Hostname of the Protonmail bridge -host 127.0.0.1 - -# Port of the Protonmail bridge -port 1025 - -# Envelop-from address -from {{ vault_protonmail_email }} - -# Security -tls on -tls_trust_file {{ desktop_protonmail_bridge_cert_path }} - -# Authentication -auth on -user {{ vault_protonmail_email }} -passwordeval "secret-tool lookup protonmail-bridge protonmail" - -# Set a default account -account default : icloud diff --git a/ansible/templates/desktop/email.el.j2 b/ansible/templates/desktop/email.el.j2 deleted file mode 100644 index 4415acf..0000000 --- a/ansible/templates/desktop/email.el.j2 +++ /dev/null @@ -1,53 +0,0 @@ -;;; email.el -*- - -(use-package mu4e - :ensure nil - :load-path "/usr/share/emacs/site-lisp/mu4e/" - :defer 20 ; Wait until 20 seconds after startup - :config - ;; This is set to 't' to avoid mail syncing issues when using mbsync - (setq mu4e-change-filenames-when-moving t) - - ;; Refresh mail using isync every 10 minutes - (setq mu4e-update-interval (* 10 60)) - (setq mu4e-get-mail-command "~/.emacs.d/scripts/email_sync.sh") - (setq mu4e-maildir "~/Maildir") - - ;; Configure email accounts - (setq mu4e-contexts - (list - ;; Protonmail Account - (make-mu4e-context - :name "Protonmail" - :match-func - (lambda (msg) - (when msg - (string-prefix-p "/ProtonMailAccount" (mu4e-message-field msg :maildir)))) - :vars '((user-mail-address . "{{ vault_protonmail_email }}") - (user-full-name . "{{ vault_personal_full_name }}") - (mu4e-drafts-folder . "/ProtonMailAccount/Drafts") - (mu4e-sent-folder . "/ProtonMailAccount/Sent") - (mu4e-refile-folder . "/ProtonMailAccount/All Mail") - (mu4e-trash-folder . "/ProtonMailAccount/Trash"))) - - ;; iCloud Account - (make-mu4e-context - :name "iCloud Mail" - :match-func - (lambda (msg) - (when msg - (string-prefix-p "/iCloudAccount" (mu4e-message-field msg :maildir)))) - :vars '((user-mail-address . "{{ vault_icloud_email }}") - (user-full-name . "{{ vault_personal_full_name }}") - (mu4e-drafts-folder . "/iCloudAccount/Drafts") - (mu4e-sent-folder . "/iCloudAccount/Sent Messages") - (mu4e-refile-folder . "/iCloudAccount/INBOX") - (mu4e-trash-folder . "/iCloudAccount/Junk"))))) - - (setq sendmail-program "/usr/bin/msmtp" - mail-user-agent 'mu4e-user-agent - read-mail-command 'mu4e - send-mail-function 'sendmail-send-it - message-sendmail-f-is-evil t - message-sendmail-extra-arguments '("--read-envelope-from") - message-send-mail-function 'message-send-mail-with-sendmail)) diff --git a/dotfiles/desktop/.bashrc.d/20-editor-desktop.sh b/dotfiles/desktop/.bashrc.d/20-editor-desktop.sh index 0e1b4e5..7aec4f1 100644 --- a/dotfiles/desktop/.bashrc.d/20-editor-desktop.sh +++ b/dotfiles/desktop/.bashrc.d/20-editor-desktop.sh @@ -1,2 +1,2 @@ export EDITOR=vim -export VISUAL=emacs +export VISUAL=vim diff --git a/dotfiles/desktop/.config/niri/config.kdl b/dotfiles/desktop/.config/niri/config.kdl new file mode 100644 index 0000000..32dcf59 --- /dev/null +++ b/dotfiles/desktop/.config/niri/config.kdl @@ -0,0 +1,88 @@ +// Minimal niri profile for the laptop. +// niri arranges windows in scrollable columns, which keeps small laptop screens usable. + +input { + keyboard { + xkb { + layout "us" + variant "intl" + } + } + + touchpad { + tap + natural-scroll + } +} + +layout { + gaps 12 + center-focused-column "on-overflow" + + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + default-column-width { proportion 0.5; } + + focus-ring { + width 4 + active-color "#54d6ff" + inactive-color "#505050" + } +} + +spawn-at-startup "waybar" + +prefer-no-csd +screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" + +binds { + Mod+Shift+Slash { show-hotkey-overlay; } + + Mod+Return hotkey-overlay-title="Open a Terminal" { spawn "foot"; } + Mod+D hotkey-overlay-title="Run an Application" { spawn "rofi" "-show" "drun"; } + Mod+B hotkey-overlay-title="Open Browser" { spawn "firefox"; } + + Mod+Q repeat=false { close-window; } + Mod+O repeat=false { toggle-overview; } + + Mod+H { focus-column-left; } + Mod+J { focus-window-down; } + Mod+K { focus-window-up; } + Mod+L { focus-column-right; } + + Mod+Ctrl+H { move-column-left; } + Mod+Ctrl+J { move-window-down; } + Mod+Ctrl+K { move-window-up; } + Mod+Ctrl+L { move-column-right; } + + Mod+U { focus-workspace-down; } + Mod+I { focus-workspace-up; } + Mod+Ctrl+U { move-column-to-workspace-down; } + Mod+Ctrl+I { move-column-to-workspace-up; } + + Mod+1 { focus-workspace 1; } + Mod+2 { focus-workspace 2; } + Mod+3 { focus-workspace 3; } + Mod+4 { focus-workspace 4; } + Mod+5 { focus-workspace 5; } + Mod+Ctrl+1 { move-column-to-workspace 1; } + Mod+Ctrl+2 { move-column-to-workspace 2; } + Mod+Ctrl+3 { move-column-to-workspace 3; } + Mod+Ctrl+4 { move-column-to-workspace 4; } + Mod+Ctrl+5 { move-column-to-workspace 5; } + + Mod+R { switch-preset-column-width; } + Mod+F { maximize-column; } + Mod+Shift+F { fullscreen-window; } + Mod+V { toggle-window-floating; } + + Mod+Minus { set-column-width "-10%"; } + Mod+Equal { set-column-width "+10%"; } + + Print { screenshot; } + Mod+Shift+E { quit; } +} diff --git a/dotfiles/desktop/.config/niri/session-env b/dotfiles/desktop/.config/niri/session-env new file mode 100644 index 0000000..4563f20 --- /dev/null +++ b/dotfiles/desktop/.config/niri/session-env @@ -0,0 +1 @@ +# Per-host Niri environment overrides. Empty by default. diff --git a/dotfiles/desktop/.emacs.d/init.el b/dotfiles/desktop/.emacs.d/init.el index 8f89275..07e93df 100644 --- a/dotfiles/desktop/.emacs.d/init.el +++ b/dotfiles/desktop/.emacs.d/init.el @@ -42,7 +42,6 @@ 'misc/doom-modeline 'misc/which-key 'misc/gptel - 'misc/email 'misc/rss 'misc/terminal 'misc/vcs diff --git a/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el b/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el index da0df80..1992bdd 100644 --- a/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el +++ b/dotfiles/desktop/.emacs.d/lisp/core/keybindings.el @@ -59,12 +59,6 @@ (with-eval-after-load 'vterm (define-key vterm-mode-map (kbd "C-c C-t") #'vterm-copy-mode)) -;; -------- mu4e -------- -(autoload 'mu4e "mu4e" nil t) -(autoload 'mu4e-compose-new "mu4e" nil t) -(global-set-key (kbd "C-x m") #'mu4e-compose-new) -(define-key fscotto/open (kbd "m") #'mu4e) - ;; -------- elfeed -------- (autoload 'elfeed "elfeed" nil t) (define-key fscotto/open (kbd "f") #'fscotto/elfeed-load-db-and-open) diff --git a/dotfiles/desktop/.emacs.d/lisp/lang/python.el b/dotfiles/desktop/.emacs.d/lisp/lang/python.el index 5a345fb..b357d77 100644 --- a/dotfiles/desktop/.emacs.d/lisp/lang/python.el +++ b/dotfiles/desktop/.emacs.d/lisp/lang/python.el @@ -1,6 +1,8 @@ ;;; python.el -*- lexical-binding: t; -*- -(require 'reformatter) +(use-package reformatter + :ensure t + :demand t) (with-eval-after-load 'project (add-to-list 'project-vc-extra-root-markers "pyproject.toml") diff --git a/dotfiles/desktop/.emacs.d/lisp/misc/rss.el b/dotfiles/desktop/.emacs.d/lisp/misc/rss.el index 24c9bfc..11363e8 100644 --- a/dotfiles/desktop/.emacs.d/lisp/misc/rss.el +++ b/dotfiles/desktop/.emacs.d/lisp/misc/rss.el @@ -29,6 +29,20 @@ :hook (elfeed-show-mode . visual-line-mode)) +(use-package evil-collection + :ensure t + :after (evil elfeed) + :config + ;; Enable Vim-style keybindings only for elfeed (search + entry views), + ;; leaving the rest of the configuration on evil's defaults. + (evil-collection-init (list 'elfeed)) + ;; Restore the custom "v" -> mpv binding, which evil's normal-state visual + ;; selection would otherwise shadow inside elfeed buffers. + (evil-collection-define-key 'normal 'elfeed-search-mode-map + "v" #'elfeed-play-with-mpv) + (evil-collection-define-key 'normal 'elfeed-show-mode-map + "v" #'elfeed-play-with-mpv)) + (use-package elfeed-org :ensure t :after elfeed diff --git a/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el b/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el index 44854c5..ec25651 100644 --- a/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el +++ b/dotfiles/desktop/.emacs.d/lisp/misc/which-key.el @@ -24,7 +24,7 @@ "C-c p" "Project" "C-c d" "Debug" "C-c g" "Git" - "C-c e" "Email / Elfeed") + "C-c e" "Elfeed") ;; -------------------------------------------------------------------------- ;; Open (C-c o …) @@ -33,7 +33,6 @@ "C-c o d" "Dirvish" "C-c o f" "RSS (Elfeed)" "C-c o l" "LLM chat (gptel)" - "C-c o m" "mu4e (Email Client)" "C-c o T" "Terminal (multi-vterm)" "C-c o z" "Ztree diff") diff --git a/dotfiles/desktop/.emacs.d/scripts/email_sync.sh b/dotfiles/desktop/.emacs.d/scripts/email_sync.sh deleted file mode 100755 index 1b4c212..0000000 --- a/dotfiles/desktop/.emacs.d/scripts/email_sync.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env sh - -mbsync -a & pid1=$! -wait $pid1 - -mu index - diff --git a/dotfiles/desktop/.local/bin/start-niri b/dotfiles/desktop/.local/bin/start-niri new file mode 100755 index 0000000..e393473 --- /dev/null +++ b/dotfiles/desktop/.local/bin/start-niri @@ -0,0 +1,27 @@ +#!/bin/sh + +[ -r /etc/profile ] && . /etc/profile +[ -r "$HOME/.profile" ] && . "$HOME/.profile" + +export XDG_CURRENT_DESKTOP=niri +export XDG_SESSION_DESKTOP=niri +export XDG_SESSION_TYPE=wayland + +export MOZ_ENABLE_WAYLAND=1 +export QT_QPA_PLATFORM='wayland;xcb' +export _JAVA_AWT_WM_NONREPARENTING=1 +export SDL_VIDEODRIVER=wayland +export GDK_BACKEND='wayland,x11' + +export SSH_AUTH_SOCK="$HOME/.local/state/ssh-agent/socket" + +# Per-host session environment (GPU / Wayland tuning, etc.) +[ -r "$HOME/.config/niri/session-env" ] && . "$HOME/.config/niri/session-env" + +exec dbus-run-session sh -eu -c ' + umask 077 + printf "%s\n" "$DBUS_SESSION_BUS_ADDRESS" > "$HOME/.dbus-session-bus-address" + gpgconf --launch gpg-agent + "$HOME/.local/bin/update-turnstile-env" + exec niri --session +'