From 753dfe7dc82fef25577c829810a4da0c4a6015a3 Mon Sep 17 00:00:00 2001 From: Bartal Laearsson Date: Mon, 29 Jun 2026 13:23:11 +0100 Subject: [PATCH] new version after nix --- README.md | 88 ++++++++++++++++++++++ ansible.cfg | 4 + inventory.ini | 3 + setup.yml | 34 +++++++++ tasks/dnf_packages.yml | 26 +++++++ tasks/dotfiles.yml | 27 +++++++ tasks/services.yml | 35 +++++++++ tasks/sqlcmd.yml | 43 +++++++++++ tasks/system.yml | 76 +++++++++++++++++++ tasks/tooling.yml | 119 +++++++++++++++++++++++++++++ tasks/user_config.yml | 56 ++++++++++++++ tasks/zen.yml | 112 ++++++++++++++++++++++++++++ templates/sway/config.j2 | 118 +++++++++++++++++++++++++++++ vars.yml | 157 +++++++++++++++++++++++++++++++++++++++ 14 files changed, 898 insertions(+) create mode 100644 README.md create mode 100644 ansible.cfg create mode 100644 inventory.ini create mode 100644 setup.yml create mode 100644 tasks/dnf_packages.yml create mode 100644 tasks/dotfiles.yml create mode 100644 tasks/services.yml create mode 100644 tasks/sqlcmd.yml create mode 100644 tasks/system.yml create mode 100644 tasks/tooling.yml create mode 100644 tasks/user_config.yml create mode 100644 tasks/zen.yml create mode 100644 templates/sway/config.j2 create mode 100644 vars.yml diff --git a/README.md b/README.md new file mode 100644 index 0000000..27f73f3 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# Fedora Sway workstation + +An Ansible playbook for rebuilding the two NixOS workstation hosts as a native +Fedora Sway desktop. The NixOS server host (`sta-len-nix`) and its services, +WireGuard, firewall, and Netdata configuration are intentionally excluded. + +## Target + +- Native Fedora 44 on x86_64 +- Sway with SDDM, Waybar, PipeWire, printing, SSH, and NetworkManager +- Faroese keyboard layout, Danish regional formats, and Atlantic/Faroe time +- Foot as the terminal, opening the persistent `tmux` session +- Zen as the default browser, installed from Zen's official release tarball +- Development tools, formatters, and Fedora-packaged language servers from NixOS + +## Run + +Install Ansible as the normal desktop user: + +```bash +sudo dnf install -y ansible +git clone https://codeberg.org/bartal-lsn/fedora-provisioning.git +cd fedora-provisioning +ansible-playbook setup.yml --ask-become-pass +``` + +Do not start the playbook with `sudo`. It uses privilege escalation only for +system tasks and installs Zen and user configuration into the invoking user's +home directory. Log out or reboot after the first run to enter Sway through +SDDM and pick up the new group memberships and environment. + +## Configuration ownership + +The Home Manager configuration lives in the public +`https://codeberg.org/bartal-lsn/dotfiles` repository as GNU Stow packages. +During provisioning, Ansible clones or updates that repository at +`~/dotfiles`, then runs `stow -R *` from that directory. Stow therefore +restows every package into the user's home directory. + +Commit dotfile changes to the Codeberg repository, then rerun the playbook to +pull `~/dotfiles` and refresh its links. Editor-managed binaries such as `zls`, +`omnisharp`, `jdtls`, and `lua-language-server` remain Neovim concerns because +Fedora does not package them consistently. Ansible installs Fedora's `clangd` +and `gopls`, Pyright, TypeScript language server, Black, isort, Prettier, and +StyLua. Rust and `rust-analyzer` are installed through the official rustup +installer. + +## Desktop keys + +| Key | Action | +|---|---| +| `Super+t` | Foot attached to tmux session `main` | +| `Super+b` | Zen Browser | +| `Super+d` | Rofi application launcher | +| `Super+q` | Close window | +| `Super+h/j/k/l` | Move focus | +| `Super+Shift+h/j/k/l` | Move window | +| `Super+1..0` | Switch workspace | +| `Super+Shift+1..0` | Move window to workspace | +| `Super+f` | Toggle fullscreen | +| `Super+Shift+Space` | Toggle floating | +| `Super+-` | Show scratchpad | +| `Super+Shift+-` | Move window to scratchpad | + +## Optional behavior + +The main switches live near the top of `vars.yml`: + +- `upgrade_system`: upgrade packages before provisioning +- `install_virtualization`: install Fedora's libvirt virtualization group +- `install_sqlcmd`: retain the Fedora repository's existing SQL Server CLI +- `install_typora`: install the unverified Flathub Typora wrapper + +The playbook installs OpenJDK 25 because Fedora 44 does not publish the +OpenJDK 21 RPM used by the NixOS setup. + +Fedora does not have a direct equivalent for NixOS's +`virtualisation.vmware.host.enable`; this playbook uses Fedora's supported +libvirt stack instead. Typora is optional because its Flathub wrapper is not +verified by Typora. Zen never uses Flatpak: Ansible downloads the official +release archive directly, places it under `~/.tarball-installations/zen`, and +creates the `~/.local/bin/zen` launcher. + +## Re-running + +The playbook is designed to be repeatable. Zen, Bun, Rust, Starship, npm tools, +services, and configuration files are checked before changes are made. Zen +handles browser updates itself after the initial binary installation. diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..b942516 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +inventory = inventory.ini +inject_facts_as_vars = False + diff --git a/inventory.ini b/inventory.ini new file mode 100644 index 0000000..ffd2239 --- /dev/null +++ b/inventory.ini @@ -0,0 +1,3 @@ +[workstation] +localhost ansible_connection=local ansible_python_interpreter=/usr/bin/python3 + diff --git a/setup.yml b/setup.yml new file mode 100644 index 0000000..439eda3 --- /dev/null +++ b/setup.yml @@ -0,0 +1,34 @@ +--- +- name: Configure Fedora Sway workstation + hosts: workstation + become: true + + vars_files: + - vars.yml + + pre_tasks: + - name: Verify that the target is Fedora + ansible.builtin.assert: + that: + - ansible_facts["distribution"] == "Fedora" + - ansible_facts["distribution_major_version"] == "44" + - ansible_facts["architecture"] == "x86_64" + fail_msg: "This playbook supports native Fedora 44 x86_64 workstations." + + - name: Verify that the workstation user is not root + ansible.builtin.assert: + that: + - user_name != "root" + - user_home != "/root" + fail_msg: "Run ansible-playbook as the workstation user, using --ask-become-pass for sudo." + + tasks: + - ansible.builtin.import_tasks: tasks/dnf_packages.yml + - ansible.builtin.import_tasks: tasks/system.yml + - ansible.builtin.import_tasks: tasks/services.yml + - ansible.builtin.import_tasks: tasks/tooling.yml + - ansible.builtin.import_tasks: tasks/sqlcmd.yml + when: install_sqlcmd + - ansible.builtin.import_tasks: tasks/zen.yml + - ansible.builtin.import_tasks: tasks/dotfiles.yml + - ansible.builtin.import_tasks: tasks/user_config.yml diff --git a/tasks/dnf_packages.yml b/tasks/dnf_packages.yml new file mode 100644 index 0000000..cd7f803 --- /dev/null +++ b/tasks/dnf_packages.yml @@ -0,0 +1,26 @@ +--- +- name: Enable RPM Fusion free repository + ansible.builtin.dnf: + name: "https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-{{ ansible_facts['distribution_major_version'] }}.noarch.rpm" + state: present + disable_gpg_check: true + +- name: Upgrade installed Fedora packages + ansible.builtin.dnf: + name: "*" + state: latest + update_cache: true + when: upgrade_system + +- name: Install Fedora workstation packages + ansible.builtin.dnf: + name: "{{ fedora_packages }}" + state: present + allowerasing: true + update_cache: true + +- name: Install virtualization package group + ansible.builtin.dnf: + name: "{{ virtualization_packages }}" + state: present + when: install_virtualization diff --git a/tasks/dotfiles.yml b/tasks/dotfiles.yml new file mode 100644 index 0000000..0193f67 --- /dev/null +++ b/tasks/dotfiles.yml @@ -0,0 +1,27 @@ +--- +- name: Ensure Stow target directories exist + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + owner: "{{ user_name }}" + mode: "{{ item.mode }}" + loop: + - { path: "{{ user_home }}/.config", mode: "0755" } + - { path: "{{ user_home }}/.ssh", mode: "0700" } + become: false + +- name: Clone or update the public dotfiles repository + ansible.builtin.git: + repo: "{{ dotfiles_repo }}" + dest: "{{ dotfiles_dir }}" + version: main + update: true + become: false + +- name: Install all dotfiles with GNU Stow + ansible.builtin.shell: stow -R * + args: + chdir: "{{ dotfiles_dir }}" + executable: /bin/bash + become: false + changed_when: false diff --git a/tasks/services.yml b/tasks/services.yml new file mode 100644 index 0000000..c139cac --- /dev/null +++ b/tasks/services.yml @@ -0,0 +1,35 @@ +--- +- name: Enable workstation system services + ansible.builtin.systemd_service: + name: "{{ item }}" + enabled: true + state: started + loop: + - NetworkManager.service + - cups.service + - sshd.service + +- name: Select SDDM as the display manager + ansible.builtin.file: + src: /usr/lib/systemd/system/sddm.service + dest: /etc/systemd/system/display-manager.service + state: link + force: true + +- name: Use the graphical boot target + ansible.builtin.file: + src: /usr/lib/systemd/system/graphical.target + dest: /etc/systemd/system/default.target + state: link + force: true + +- name: Reload systemd after selecting the display manager + ansible.builtin.systemd_service: + daemon_reload: true + +- name: Enable libvirt + ansible.builtin.systemd_service: + name: libvirtd.service + enabled: true + state: started + when: install_virtualization diff --git a/tasks/sqlcmd.yml b/tasks/sqlcmd.yml new file mode 100644 index 0000000..c247669 --- /dev/null +++ b/tasks/sqlcmd.yml @@ -0,0 +1,43 @@ +--- +- name: Check if sqlcmd is already installed + ansible.builtin.stat: + path: /usr/local/bin/sqlcmd + register: sqlcmd_bin + +- name: Download sqlcmd archive + ansible.builtin.get_url: + url: "{{ sqlcmd_url }}" + dest: "/tmp/{{ sqlcmd_archive }}" + when: not sqlcmd_bin.stat.exists + +- name: Create sqlcmd extraction directory + ansible.builtin.file: + path: /tmp/sqlcmd_extract + state: directory + mode: "0755" + when: not sqlcmd_bin.stat.exists + +- name: Extract sqlcmd + ansible.builtin.unarchive: + src: "/tmp/{{ sqlcmd_archive }}" + dest: /tmp/sqlcmd_extract + remote_src: true + creates: /tmp/sqlcmd_extract/sqlcmd + when: not sqlcmd_bin.stat.exists + +- name: Move sqlcmd binary to /usr/local/bin + ansible.builtin.copy: + src: /tmp/sqlcmd_extract/sqlcmd + dest: /usr/local/bin/sqlcmd + mode: "0755" + remote_src: true + when: not sqlcmd_bin.stat.exists + +- name: Clean up sqlcmd temp files + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - "/tmp/{{ sqlcmd_archive }}" + - /tmp/sqlcmd_extract + when: not sqlcmd_bin.stat.exists diff --git a/tasks/system.yml b/tasks/system.yml new file mode 100644 index 0000000..0755f2f --- /dev/null +++ b/tasks/system.yml @@ -0,0 +1,76 @@ +--- +- name: Read the configured timezone + ansible.builtin.command: timedatectl show --property=Timezone --value + register: configured_timezone + changed_when: false + +- name: Set the system timezone + ansible.builtin.command: "timedatectl set-timezone {{ system_timezone }}" + when: configured_timezone.stdout != system_timezone + +- name: Configure system locale + ansible.builtin.copy: + dest: /etc/locale.conf + mode: "0644" + content: | + LANG={{ system_locale }} + LC_ADDRESS={{ regional_locale }} + LC_IDENTIFICATION={{ regional_locale }} + LC_MEASUREMENT={{ regional_locale }} + LC_MONETARY={{ regional_locale }} + LC_NAME={{ regional_locale }} + LC_NUMERIC={{ regional_locale }} + LC_PAPER={{ regional_locale }} + LC_TELEPHONE={{ regional_locale }} + LC_TIME={{ regional_locale }} + +- name: Configure console keyboard + ansible.builtin.copy: + dest: /etc/vconsole.conf + mode: "0644" + content: | + KEYMAP=dk + +- name: Add workstation user to administrative and device groups + ansible.builtin.user: + name: "{{ user_name }}" + groups: "{{ ['wheel', 'video', 'input'] + (['libvirt'] if install_virtualization else []) }}" + append: true + shell: /usr/bin/zsh + +- name: Check transparent hugepage kernel argument + ansible.builtin.shell: | + grubby --info=ALL | awk ' + /^args=/ { + seen = 1 + if (index($0, "transparent_hugepage=never") == 0) missing = 1 + } + END { exit !(seen && !missing) } + ' + args: + executable: /bin/bash + register: transparent_hugepage_argument + changed_when: false + failed_when: false + +- name: Disable transparent hugepages in all boot entries + ansible.builtin.command: + argv: + - grubby + - --update-kernel=ALL + - --args=transparent_hugepage=never + when: transparent_hugepage_argument.rc != 0 + +- name: Configure workstation environment + ansible.builtin.copy: + dest: /etc/profile.d/fedora-workstation.sh + mode: "0644" + content: | + export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" + export GOPATH="${GOPATH:-$HOME/go}" + export PATH="$HOME/.scripts:$HOME/.local/bin:$HOME/.cargo/bin:$HOME/.bun/bin:$HOME/bin/zig:$HOME/bin/zls:$GOPATH/bin:$PATH" + export TERMINAL=foot + export BROWSER=zen + export GTK_THEME=Adwaita:dark + export MOZ_ENABLE_WAYLAND=1 + export ELECTRON_OZONE_PLATFORM_HINT=wayland diff --git a/tasks/tooling.yml b/tasks/tooling.yml new file mode 100644 index 0000000..b3aeb29 --- /dev/null +++ b/tasks/tooling.yml @@ -0,0 +1,119 @@ +--- +- name: List globally installed npm packages + ansible.builtin.command: npm list --global --depth=0 --json + register: npm_global_list + changed_when: false + failed_when: false + +- name: Install global language servers and formatters + ansible.builtin.command: "npm install --global {{ item }}" + loop: "{{ npm_global_packages }}" + when: item not in ((npm_global_list.stdout | default('{}', true) | from_json).dependencies | default({})) + +- name: Check for rustup + ansible.builtin.stat: + path: "{{ user_home }}/.cargo/bin/rustup" + become: false + register: rustup_binary + +- name: Download the official rustup installer + ansible.builtin.get_url: + url: https://sh.rustup.rs + dest: /tmp/rustup-init.sh + mode: "0755" + when: not rustup_binary.stat.exists + +- name: Install Rust stable with the official rustup installer + ansible.builtin.command: + argv: + - /tmp/rustup-init.sh + - -y + - --default-toolchain + - stable + - --profile + - default + environment: + HOME: "{{ user_home }}" + become: false + when: not rustup_binary.stat.exists + +- name: Remove the rustup installer + ansible.builtin.file: + path: /tmp/rustup-init.sh + state: absent + +- name: Check the active Rust toolchain + ansible.builtin.command: "{{ user_home }}/.cargo/bin/rustup show active-toolchain" + become: false + register: active_rust_toolchain + changed_when: false + failed_when: false + +- name: Select the Rust stable toolchain + ansible.builtin.command: "{{ user_home }}/.cargo/bin/rustup default stable" + become: false + when: active_rust_toolchain.rc != 0 or not active_rust_toolchain.stdout.startswith('stable-') + +- name: List installed rustup components + ansible.builtin.command: "{{ user_home }}/.cargo/bin/rustup component list --installed" + become: false + register: installed_rustup_components + changed_when: false + +- name: Install Rust development components + ansible.builtin.command: "{{ user_home }}/.cargo/bin/rustup component add {{ item }}" + loop: "{{ rustup_components }}" + become: false + when: installed_rustup_components.stdout_lines | select('match', '^' ~ item ~ '(-|$)') | list | length == 0 + +- name: Check for StyLua + ansible.builtin.stat: + path: "{{ user_home }}/.cargo/bin/stylua" + become: false + register: stylua_binary + +- name: Install StyLua + ansible.builtin.command: "{{ user_home }}/.cargo/bin/cargo install stylua --locked" + become: false + when: not stylua_binary.stat.exists + +- name: Check for Starship + ansible.builtin.stat: + path: "{{ user_home }}/.local/bin/starship" + become: false + register: starship_binary + +- name: Download the Starship installer + ansible.builtin.get_url: + url: https://starship.rs/install.sh + dest: /tmp/starship-install.sh + mode: "0755" + when: not starship_binary.stat.exists + +- name: Install Starship for the workstation user + ansible.builtin.command: + argv: + - /tmp/starship-install.sh + - --yes + - --bin-dir + - "{{ user_home }}/.local/bin" + become: false + when: not starship_binary.stat.exists + +- name: Check for Bun + ansible.builtin.stat: + path: "{{ user_home }}/.bun/bin/bun" + become: false + register: bun_binary + +- name: Download the Bun installer + ansible.builtin.get_url: + url: https://bun.sh/install + dest: /tmp/bun-install.sh + mode: "0755" + when: not bun_binary.stat.exists + +- name: Install Bun for the workstation user + ansible.builtin.command: /tmp/bun-install.sh + become: false + when: not bun_binary.stat.exists diff --git a/tasks/user_config.yml b/tasks/user_config.yml new file mode 100644 index 0000000..8a79d8c --- /dev/null +++ b/tasks/user_config.yml @@ -0,0 +1,56 @@ +--- +- name: Create Ansible-managed user directories + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + owner: "{{ user_name }}" + mode: "{{ item.mode }}" + loop: + - { path: "{{ user_home }}/.ssh", mode: "0700" } + - { path: "{{ user_home }}/Pictures", mode: "0755" } + become: false + +- name: Check for the Git signing public key + ansible.builtin.stat: + path: "{{ git_signing_key }}" + become: false + register: git_signing_public_key + +- name: Read the Git signing public key + ansible.builtin.slurp: + src: "{{ git_signing_key }}" + become: false + register: git_signing_public_key_contents + when: git_signing_public_key.stat.exists + +- name: Configure allowed SSH signers + ansible.builtin.copy: + dest: "{{ user_home }}/.ssh/allowed_signers" + owner: "{{ user_name }}" + mode: "0644" + content: "{{ git_email }} {{ git_signing_public_key_contents.content | b64decode | trim }}\n" + become: false + when: git_signing_public_key.stat.exists + +- name: Install Typora from Flathub + when: install_typora + block: + - name: Ensure Flathub is configured + ansible.builtin.command: + argv: + - flatpak + - remote-add + - --if-not-exists + - flathub + - https://flathub.org/repo/flathub.flatpakrepo + changed_when: false + + - name: Check for Typora + ansible.builtin.command: flatpak info io.typora.Typora + register: typora_flatpak + changed_when: false + failed_when: false + + - name: Install Typora + ansible.builtin.command: flatpak install --noninteractive flathub io.typora.Typora + when: typora_flatpak.rc != 0 diff --git a/tasks/zen.yml b/tasks/zen.yml new file mode 100644 index 0000000..7cecf46 --- /dev/null +++ b/tasks/zen.yml @@ -0,0 +1,112 @@ +--- +- name: Check for Zen Browser + ansible.builtin.stat: + path: "{{ zen_install_dir }}/zen" + become: false + register: zen_binary + +- name: Create Zen installation directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ user_name }}" + mode: "0755" + become: false + loop: + - "{{ user_home }}/.tarball-installations" + - "{{ user_home }}/.config" + - "{{ user_home }}/.local/bin" + - "{{ user_home }}/.local/share/applications" + - "{{ user_home }}/.local/share/icons/hicolor/128x128/apps" + +- name: Download the current Zen release binary + ansible.builtin.get_url: + url: "{{ zen_archive_url }}" + dest: "{{ zen_archive }}" + mode: "0644" + become: false + when: not zen_binary.stat.exists + +- name: Extract Zen Browser + ansible.builtin.unarchive: + src: "{{ zen_archive }}" + dest: "{{ user_home }}/.tarball-installations" + remote_src: true + creates: "{{ zen_install_dir }}/zen" + become: false + +- name: Link Zen into the user's PATH + ansible.builtin.file: + src: "{{ zen_install_dir }}/zen" + dest: "{{ user_home }}/.local/bin/zen" + state: link + force: true + become: false + +- name: Install Zen application icon + ansible.builtin.copy: + src: "{{ zen_install_dir }}/browser/chrome/icons/default/default128.png" + dest: "{{ user_home }}/.local/share/icons/hicolor/128x128/apps/zen.png" + remote_src: true + owner: "{{ user_name }}" + mode: "0644" + become: false + +- name: Install Zen desktop entry + ansible.builtin.copy: + dest: "{{ user_home }}/.local/share/applications/{{ zen_desktop_file }}" + owner: "{{ user_name }}" + mode: "0644" + content: | + [Desktop Entry] + Version=1.0 + Type=Application + Name=Zen Browser + Comment=Browse the web + Exec=zen %u + Icon=zen + Terminal=false + StartupNotify=true + StartupWMClass=zen + Categories=Network;WebBrowser; + MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;application/x-xpinstall;application/pdf;application/json; + Actions=new-window;new-private-window;profile-manager; + + [Desktop Action new-window] + Name=New Window + Exec=zen --new-window %u + + [Desktop Action new-private-window] + Name=New Private Window + Exec=zen --private-window %u + + [Desktop Action profile-manager] + Name=Profile Manager + Exec=zen --ProfileManager + become: false + +- name: Remove downloaded Zen archive + ansible.builtin.file: + path: "{{ zen_archive }}" + state: absent + become: false + +- name: Query default MIME handlers + ansible.builtin.command: "xdg-mime query default {{ item }}" + become: false + loop: + - text/html + - application/xhtml+xml + - x-scheme-handler/http + - x-scheme-handler/https + register: current_browser_handlers + changed_when: false + failed_when: false + +- name: Set Zen as the default browser + ansible.builtin.command: "xdg-mime default {{ zen_desktop_file }} {{ item.item }}" + become: false + loop: "{{ current_browser_handlers.results }}" + loop_control: + label: "{{ item.item }}" + when: item.stdout != zen_desktop_file diff --git a/templates/sway/config.j2 b/templates/sway/config.j2 new file mode 100644 index 0000000..fc64bb0 --- /dev/null +++ b/templates/sway/config.j2 @@ -0,0 +1,118 @@ +# Sway workstation configuration translated from NixOS behavior. +set $mod Mod4 +set $term foot -e tmux new-session -A -s main +set $browser zen +set $menu rofi -show drun + +font pango:DejaVu Sans Mono 10 + +output * scale 1 +output * bg ~/.config/sway/tux.png fill + +input type:keyboard { + xkb_layout {{ keyboard_layout }} + xkb_model pc105 +} + +input type:touchpad { + natural_scroll disabled + tap enabled +} + +gaps inner 5 +gaps outer 10 +smart_gaps on +default_border pixel 2 +default_floating_border pixel 2 + +client.focused #33ccff #33ccff #1a1b26 #33ccff #33ccff +client.focused_inactive #595959 #595959 #c0caf5 #595959 #595959 +client.unfocused #595959 #595959 #c0caf5 #595959 #595959 + +floating_modifier $mod normal + +# Applications and session +bindsym $mod+t exec $term +bindsym $mod+b exec $browser +bindsym $mod+d exec $menu +bindsym $mod+q kill +bindsym $mod+Shift+c reload +bindsym $mod+Shift+e exec swaynag -t warning -m 'Exit Sway?' -B 'Exit' 'swaymsg exit' + +# Focus movement +bindsym $mod+h focus left +bindsym $mod+j focus down +bindsym $mod+k focus up +bindsym $mod+l focus right +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# Move windows +bindsym $mod+Shift+h move left +bindsym $mod+Shift+j move down +bindsym $mod+Shift+k move up +bindsym $mod+Shift+l move right +bindsym $mod+Shift+Left move left +bindsym $mod+Shift+Down move down +bindsym $mod+Shift+Up move up +bindsym $mod+Shift+Right move right + +# Workspaces +set $ws1 1 +set $ws2 2 +set $ws3 3 +set $ws4 4 +set $ws5 5 +set $ws6 6 +set $ws7 7 +set $ws8 8 +set $ws9 9 +set $ws10 10 + +bindsym $mod+1 workspace number $ws1 +bindsym $mod+2 workspace number $ws2 +bindsym $mod+3 workspace number $ws3 +bindsym $mod+4 workspace number $ws4 +bindsym $mod+5 workspace number $ws5 +bindsym $mod+6 workspace number $ws6 +bindsym $mod+7 workspace number $ws7 +bindsym $mod+8 workspace number $ws8 +bindsym $mod+9 workspace number $ws9 +bindsym $mod+0 workspace number $ws10 + +bindsym $mod+Shift+1 move container to workspace number $ws1 +bindsym $mod+Shift+2 move container to workspace number $ws2 +bindsym $mod+Shift+3 move container to workspace number $ws3 +bindsym $mod+Shift+4 move container to workspace number $ws4 +bindsym $mod+Shift+5 move container to workspace number $ws5 +bindsym $mod+Shift+6 move container to workspace number $ws6 +bindsym $mod+Shift+7 move container to workspace number $ws7 +bindsym $mod+Shift+8 move container to workspace number $ws8 +bindsym $mod+Shift+9 move container to workspace number $ws9 +bindsym $mod+Shift+0 move container to workspace number $ws10 + +# Layout and scratchpad +bindsym $mod+s layout toggle split +bindsym $mod+e layout toggle split +bindsym $mod+f fullscreen toggle +bindsym $mod+Shift+space floating toggle +bindsym $mod+minus scratchpad show +bindsym $mod+Shift+minus move scratchpad + +# Hardware controls +bindsym XF86AudioRaiseVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindsym XF86AudioLowerVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindsym XF86AudioMute exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindsym XF86AudioMicMute exec wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindsym XF86MonBrightnessUp exec brightnessctl set 5%+ +bindsym XF86MonBrightnessDown exec brightnessctl set 5%- +bindsym Print exec grim -g "$(slurp)" "$HOME/Pictures/screenshot-$(date +%Y%m%d-%H%M%S).png" + +# Session services +exec dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP +exec /usr/libexec/lxqt-policykit-agent +exec nm-applet --indicator +exec mako +exec ~/.config/waybar/launch.sh diff --git a/vars.yml b/vars.yml new file mode 100644 index 0000000..f43d2e7 --- /dev/null +++ b/vars.yml @@ -0,0 +1,157 @@ +--- +# The playbook must be started as the desktop user, not through sudo. +user_name: "{{ lookup('env', 'USER') }}" +user_home: "{{ lookup('env', 'HOME') }}" +dotfiles_dir: "{{ user_home }}/dotfiles" +dotfiles_repo: https://codeberg.org/bartal-lsn/dotfiles.git + +system_timezone: Atlantic/Faroe +system_locale: en_US.UTF-8 +regional_locale: da_DK.UTF-8 +keyboard_layout: fo + +upgrade_system: true +install_virtualization: true +install_sqlcmd: true +install_typora: true + +fedora_packages: + # Media and documents + - ffmpeg + - fuse + - fuse-libs + - ghostscript + - libheif-tools + - libreoffice + - libtiff + - libwebp + - openjpeg + + # Development toolchains and libraries + - binutils + - clang + - clang-tools-extra + - composer + - dotnet-sdk-10.0 + - file + - gcc + - gcc-c++ + - glibc-langpack-da + - glibc-langpack-en + - golang + - gopls + - go-task + - hugo + - ibus + - java-25-openjdk-devel + - make + - maven + - ncurses-devel + - nodejs + - npm + - openssl-devel + - php + - python3 + - black + - python3-isort + - sqlite + - tree-sitter-cli + - unixODBC + - unixODBC-devel + - uv + - zig + + # Command-line workstation tools + - 7zip + - acpi + - curl + - fd-find + - findutils + - flatpak + - fish + - fzf + - gawk + - git + - jq + - kbd + - less + - lua + - neovim + - ripgrep + - stow + - tar + - tmux + - unzip + - util-linux + - vim-enhanced + - wget + - xz + - zip + - zsh + - zsh-autosuggestions + - zsh-syntax-highlighting + + # Native Sway workstation + - brightnessctl + - foot + - gnome-keyring + - gnome-keyring-pam + - grim + - mako + - network-manager-applet + - nm-connection-editor + - pamixer + - pavucontrol + - pipewire + - pipewire-alsa + - pipewire-pulseaudio + - playerctl + - polkit + - lxqt-policykit + - rofi + - rtkit + - sddm + - sddm-wayland-sway + - slurp + - sway + - swayidle + - swaylock + - waybar + - wireplumber + - wl-clipboard + - xdg-desktop-portal + - xdg-desktop-portal-gtk + - xdg-desktop-portal-wlr + - xdg-utils + + # Services and system integration + - cups + - grubby + - openssh-server + +virtualization_packages: + - "@virtualization" + +npm_global_packages: + - prettier + - pyright + - typescript + - typescript-language-server + +rustup_components: + - rust-analyzer + - rust-src + +# Direct stable release binary published by the verified Zen Browser project. +zen_archive_url: https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-x86_64.tar.xz +zen_archive: /tmp/zen.linux-x86_64.tar.xz +zen_install_dir: "{{ user_home }}/.tarball-installations/zen" +zen_desktop_file: zen.desktop + +# Existing Fedora-only tool retained from this repository. +sqlcmd_version: "1.8.1" +sqlcmd_archive: sqlcmd-linux-amd64.tar.bz2 +sqlcmd_url: "https://github.com/microsoft/go-sqlcmd/releases/download/v{{ sqlcmd_version }}/{{ sqlcmd_archive }}" + +git_email: bartal@flo.fo +git_signing_key: "{{ user_home }}/.ssh/id_ed25519.pub"