diff --git a/.chezmoi.toml.tmpl b/.chezmoi.toml.tmpl index 92191a3..6e5b809 100644 --- a/.chezmoi.toml.tmpl +++ b/.chezmoi.toml.tmpl @@ -13,3 +13,5 @@ gaming = {{ $gaming }} email = {{ $email | quote }} {{ $name := promptStringOnce . "name" "What is your name (git)" }} name = {{ $name | quote }} +{{ $osProber := promptBoolOnce . "os_prober" "Enable GRUB os-prober to detect other operating systems?" }} +os_prober = {{ $osProber }} diff --git a/assets/dconf_gtk.ini b/assets/dconf_gtk.ini new file mode 100644 index 0000000..036a62f --- /dev/null +++ b/assets/dconf_gtk.ini @@ -0,0 +1,8 @@ +[/] +accent-color='red' +color-scheme='prefer-dark' +cursor-size=24 +cursor-theme='breeze_cursors' +font-name='CaskaydiaCove Nerd Font 12' +gtk-theme='adw-gtk3-dark' +icon-theme='Papirus-Dark' diff --git a/dot_bashrc b/dot_bashrc index f15bdfa..45d8c74 100644 --- a/dot_bashrc +++ b/dot_bashrc @@ -26,6 +26,19 @@ function ca() { chezmoi apply "$(chezmoi target-path "${1:-.}")" } +isbusy() { + local path="${1:-}" + if [ -z "$path" ]; then + echo "Usage: isbusy " >&2 + return 1 + fi + if ! path="$(realpath -e -- "$path" 2>/dev/null)"; then + echo "isbusy: cannot resolve '$1'" >&2 + return 1 + fi + sudo lsof +f -- "$path" +} + ## Aliases # Replace ls with eza if [ -f /usr/bin/eza ]; then diff --git a/dot_config/fish/config.fish b/dot_config/fish/config.fish index faac67a..c71aaa2 100644 --- a/dot_config/fish/config.fish +++ b/dot_config/fish/config.fish @@ -144,6 +144,20 @@ function ca chezmoi apply (chezmoi target-path $path) end +function isbusy + set -l path "$argv[1]" + if test -z "$path" + echo "Usage: isbusy " >&2 + return 1 + end + set path (realpath -e -- "$path" 2>/dev/null) + or begin + echo "isbusy: cannot resolve '$argv[1]'" >&2 + return 1 + end + sudo lsof +f -- "$path" +end + ## Aliases # Replace ls with eza if type -q eza diff --git a/dot_config/opencode/encrypted_opencode.jsonc.age b/dot_config/opencode/encrypted_opencode.jsonc.age new file mode 100644 index 0000000..7cb2b3f --- /dev/null +++ b/dot_config/opencode/encrypted_opencode.jsonc.age @@ -0,0 +1,57 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IG1sa2VtNzY4eDI1NTE5IHV2VUZTWGI2 +eEdnVkpqQlBmYU15WmJFNEhSbmdjU3BkUlpxWWptdmVXSFY5REw0UXJ5d0JoRSs5 +aUh4dTd0RXhGekVyMlJIK3lxekFpb3BiN2pSOTZiU3lObTkxZ0tLbXhxRFdmMGUr +bFphVTVxaE9QOXdOUzRtZkxWV2wrZEJRZlJSdTVpS3VrYUdMT1daYTAxRytJbHFi +RStzbjJRZ1BxUW1SQlVienIrdlF2NUVFcTNoZXU4OEpPdjN0am1zamVTMjd4aUpn +d2tRbHBVZFVCNGhFUk9DWnZEYTN3K3A0WjN3ZXNqOFhoNVV3aWEwelgwaXRxcStY +RnVYQTNBRG03WXh5bWlXc1FFODBnZ29ZZlp5YURZeXc1Z2N2Tk1WQ1FqU1B6cU04 +L1dtVkt4aDhLMzdLN3MyYVdlZkpBVFZwRnJsUlhQSnZ0VmswUitEZC9kd0J2Z2Zn +T3AwTEVVNDk3b2xqbkZXWk5DNDEvYS9GMm1DQUhvSWRSQWE3N1BZelZIRTExWGFH +emlJbGdIU1B5NDlENVZrdlR2S2psWFZYMWFYUkw3QkNjYzBIbGpoWlduZUVMTlVh +emh3QzRXRi8rTHZkKzRTaXduMXUvM00vTzJ5bi9vOXpRbUhGYUVqSnRoZ2xDdkJ1 +eUg2cmtSbU9kTHlWNDdtNHQ3blkzYUk2UUFpaXBGZ2JuZG1LT2tERm9PY01WSTFO +OTJsZGlCcmJrcDV0TkdVaVdFczQ3bTlWcDN3dVFlcVoxbVFjTkNDN2pNMUdNTThw +QVhXeWhiWTBVWXZjQ3lGU3RJRWdFSGxOd0tVWUFwUlNUVURxY2syZUIwcEVsMVNp +NUhhb09GaFhtMzZ5cDMxREo1VU5hVytyM0R3VHRzTVdVL294TnNSWkZDYWpyNzRt +WmpLY0VndXltelIyRmVIMElwOU13bGlXSjhhTTh4SjYyTXZSTmVPd1lmanJFa3Nz +enZuT3dUVkRiMFdsQXUybzEwSzAwU2gwdytHU0xrNXNrM1dCQTdGVy9jRWtmcmlP +WlZLUFB1aEVXVEl1R1paZE92U0l3UEk4cXVXQWd3WDZjV0E3QmgxemNJRTJyMDlZ +Q2x0a0xBNEVvaVZYcGdqVHFadU44MTdsTDhKbWgwQlQzOE1aUlZQNkpud0VCRytl +eXYxeE1sYWozdGZrYXJCRzJtcW5yQi9KaTR2bEEwYlBkUzBERFUxZkxPcy9rRFNQ +cHRHd2FDRlliQXBXSlRMd2Jab1g1QUxVM2tRNTE2aG9JcUJuTWxZZFl4WEVBY2tJ +cjljNTdDc3I4OGprMll4SFU3OXQ1UWNGalNzME9kVVI2K1VncHBHZHRyandXV0Y2 +WXBqWGNxOFFhVld6K1hJelZJdzBSVFNoem5jbXZUTVBoZmNqVXl1TTl3YTNjTXk3 +UFF0V0RMWnVRbVlQck51dDZXdzZiSTBhWFg3YTc2Q2tHVGhSV25VSitXdVd6QnRF +elVObUdBRVJ4cmVyd0dqcGdDQmhUd1RiRC9xeHA1R1dwVHFtRnN1OFY5OTV3YU5i +T3JPOVdGYTVtRmNZaW5GbGFoRWQ3eWFEVnlwbFI1L01JV0NacjYvV0MyUklCdFFq +SGE3L0xmQWVhNXloZ3o0eHJTYkM2bXFFM0p5ZUdjMGQyMkk1ODIybU5uYysrWDlN +U29Ud01Yd0kyRGZKeGU4SWlnbDVLSUMybFpYb282RTcxSERYY1gyd0xLYWNKTzFh +OTNSV0UrWEtHaUswSFBRQnF5QUp5OG04M3prNDBFQXdUVzY2NDc3bTBkbmJJTG5R +VzNxYUQwTzI1TG1GNTEwbEFaLysxZWY2SVlzYlJRQlVKenZEK2dYVVlhZFJKbmdR +bzN4NmhOMWU0S25RNFRSNVpxTjM4YnRpRE9OVkZDdlVSanRTc1hISWFzcDV1UCtY +QkN0ZVEwZysvb1ltZ29BeDV1WWxjTEVaRTVuQ3l0Ly9jdGRqSEpRcVJUaGxEUQo1 +THVkUnQwRFpBdVptN3Y5ZGJKY2dCVmxmNWVIS3Y0NTZQeUg5T2llNmlFCi0tLSBS +Z3pHeGp1eDAzU2dDVUFOY08xMGREcGs2WVgwYXNXRXN2VDdQbldoQ1A4Cg5angDK +/Amq4FxZci93/4y6X9A4In1WqkUlweEEeRo6BUzCvBcSYQZF+cgYt97ZO1ypXpqU +Ps6+b/OyDCnkLs4H+Rj2GiHT+lL0ZvMitkwQpodUenpJiyGsZArGjm6zYYSNx1at +L5HT4a2UEjQvJPc8mSVpLeE1fZftyJigfjUuuQ/SZOh99HdDqvjzxPkukgXqN2EZ +YCdjvGZ3ZnAc/L+6JU+f3aN4+Urga3KFQvNw+PlFapoH0OgStXZfwyWKLvSDWks0 +PjbDLPLukKwpwhlXw47R4kYmvKnnImXQHwcI4OJOBonbI2agx7QanQCdnPxCJ4tK +9e7mNGAH/ipcQpX3tXiJYFHygqSzs/7Ts5SqTuZbpSdS5I4p+lDhIIGGNnH31AN3 +fh2th0r7HJSM1GMCGLef3BZw9F45cC0Jy16LLaT6LckL53pB23TqLU0wP20mDiSh +q8ygt2EhJ4ALS+rzOOkHYWWw8G7kVm97MX1jMzVBKENcqN/tY3gOI3btadZJX6Zu +b887FN1SiQZfjpXohkf6V4NpKy8UbMqOF6099zyPXW6f6sjFbwLZ8vxsC6HA6yxD +XjysJqJCNdnlU8pp+7H2q10GuBpPlOMTa3H5onOleok6bmGbsF3W+2qwOOkkmOdV +8RckRfls/DA62N8o/HduSBSUIip0PFr1/qSX5oge3ltXksMWbSOrH2M3LLPBGqlh +Va4Fjmx1YhTGJ/1nUPYaZQAAIaBJI7vjCwFjDm5Z2WD3uH1KcQ3fBV9tnD7gg54j +a3gbiMD7Ls7DKOxkQyBK/nGD6VrJJNKaMMtBY7wO+ob0eJS04oB+9KTt9XWZ998J +QGlKP2E1JcQ1+TSR/i/LKpRxW56Wf1memg/QZ7fc001waNMEtPWtrO1497TYe2K0 +/0D3YnKe1Qq0GnULm2TPHv+W0lZ4ACeaSEkIfPCYviRg3Vk1aEvr/DPFNebbjkcO +Gz+7fyCTSluv9oAVnUz+rhtwCbqSFqZmsgaNB5h5dnMrfKGz/1mouYyamq5oxlau +bUvfatCrNp1QmUyFThGkU2JuaNapAmk8ALstAh4GYJYDhXphH3b/uOaRWrsEXQNs +H2lQ1+spJTzkElpq5aIcQLWvbVrdhsfme1IpxX5HzLET3QNVvIJUjRn2xv7VyOKH +ywLO9YfQm1SegKlzZDy1knjyrSXYQHUQeaJjVS/rgur08V7gHrZUKbCl9sjmdVMI +xXH9RZ+Ci8lW0TTgpxjHc8a967uchKC9KlmSoOKA89lU13xbdPUzjrxhM+dk+zRP +Ao0R2HeWZqqXOJlVHSeEAqsS/owm +-----END AGE ENCRYPTED FILE----- diff --git a/run_once_10-install-base.sh.tmpl b/run_once_10-install-base.sh.tmpl index f20aa8d..0f58b8a 100755 --- a/run_once_10-install-base.sh.tmpl +++ b/run_once_10-install-base.sh.tmpl @@ -4,6 +4,8 @@ set -euo pipefail +warn() { echo ">>> [base] WARNING: $*" >&2; } + SYS="{{ .system | default "desktop" }}" DISTRO_ID="{{ .chezmoi.osRelease.id | default "" }}" @@ -16,14 +18,14 @@ case "$DISTRO_ID" in openssh upower expac unzip less curl wget gawk zip tar \ btop fastfetch yazi eza bat fzf fd jq go npm python-pipx \ fish zoxide starship sshfs man-db man-pages p7zip ripgrep resvg \ - lazygit exiftool + lazygit exiftool testdisk if [ "$SYS" != "server" ]; then sudo pacman -Syu --noconfirm --needed \ dbeaver mariadb \ jdk-openjdk maven rustup \ dotnet-sdk docker docker-compose - rustup default stable >/dev/null 2>&1 || true + rustup default stable >/dev/null 2>&1 || warn "rustup default stable failed" fi # AUR helper @@ -57,7 +59,7 @@ case "$DISTRO_ID" in sudo apt-get install -y \ openjdk-17-jdk maven rustup npm golang-go \ dotnet-sdk-8.0 docker-compose - rustup default stable >/dev/null 2>&1 || true + rustup default stable >/dev/null 2>&1 || warn "rustup default stable failed" fi ;; diff --git a/run_once_20-install-desktop.sh.tmpl b/run_once_20-install-desktop.sh.tmpl index 74c31ab..cf3cfba 100755 --- a/run_once_20-install-desktop.sh.tmpl +++ b/run_once_20-install-desktop.sh.tmpl @@ -1,20 +1,24 @@ #!/bin/bash -# run_once_20-install-gui.sh +# run_once_20-install-desktop.sh # Hyprland and other DE/shell packages set -euo pipefail + SYS="{{ .system | default "desktop" }}" DISTRO_ID="{{ .chezmoi.osRelease.id | default "" }}" +SRC="{{ .chezmoi.sourceDir }}" if [ "$SYS" = "server" ]; then - echo ">>> [gui] system=server, skipping" + echo ">>> [desktop] system=server, skipping" exit 0 fi +warn() { echo ">>> [desktop] WARNING: $*" >&2; } + case "$DISTRO_ID" in arch) - echo ">>> [gui] arch, system=$SYS" + echo ">>> [desktop] arch, system=$SYS" # System packages sudo pacman -Syu --noconfirm --needed \ @@ -36,25 +40,34 @@ case "$DISTRO_ID" in # Dank Shell - sed workaround to pass args to installer sudo -v && curl -fsSL https://install.danklinux.com | sed 's#\./installer$#./installer "$@"#' | sh -s -- -c hyprland -t ghostty --include-deps dms-greeter,danksearch,dankcalendar -y + + # Apply dconf defaults + DCONF_INI="$SRC/assets/dconf_gtk.ini" + if [ -f "$DCONF_INI" ]; then + echo ">>> [desktop] applying GNOME interface defaults (dconf load)" + dconf load /org/gnome/desktop/interface/ < "$DCONF_INI" \ + || warn "dconf load failed (DBus session may be unavailable)" + fi + # Firefox theming - pipx install pywalfox - ~/.local/bin/pywalfox install + pipx install pywalfox || warn "pipx install pywalfox failed" + ~/.local/bin/pywalfox install || warn "pywalfox install failed (Firefox may not be configured)" mkdir -p ~/.cache/wal touch ~/.cache/wal/dank-pywalfox.json ln -sf ~/.cache/wal/dank-pywalfox.json ~/.cache/wal/colors.json ;; ubuntu) - echo ">>> [gui] ubuntu, system=$SYS" + echo ">>> [desktop] ubuntu, system=$SYS" sudo apt-get install -y \ kdeconnect dosfstools gnome-disk-utility \ cava ddcutil guvcview ;; *) - echo ">>> [gui] unsupported distro: ${DISTRO_ID:-unknown}, skipping" + echo ">>> [desktop] unsupported distro: ${DISTRO_ID:-unknown}, skipping" exit 0 ;; esac -echo ">>> [gui] done" +echo ">>> [desktop] done" diff --git a/run_once_50-configure-user.sh.tmpl b/run_once_50-configure-user.sh.tmpl index 17327c2..4a414ef 100755 --- a/run_once_50-configure-user.sh.tmpl +++ b/run_once_50-configure-user.sh.tmpl @@ -5,6 +5,8 @@ set -euo pipefail +warn() { echo ">>> [configure-user] WARNING: $*" >&2; } + if ! command -v fish >/dev/null 2>&1; then echo ">>> [configure-user] fish not installed; skipping" exit 0 @@ -19,4 +21,4 @@ if [ "$current_shell" = "$(command -v fish)" ]; then fi echo ">>> [configure-user] changing shell for $USER_NAME to $(command -v fish)" -sudo chsh -s "$(command -v fish)" "$USER_NAME" || true +sudo chsh -s "$(command -v fish)" "$USER_NAME" || warn "chsh failed for $USER_NAME (may need /etc/shells entry)" diff --git a/run_once_55-configure-root.sh.tmpl b/run_once_55-configure-root.sh.tmpl index a4a24da..2dcd70f 100755 --- a/run_once_55-configure-root.sh.tmpl +++ b/run_once_55-configure-root.sh.tmpl @@ -4,6 +4,8 @@ set -euo pipefail +warn() { echo ">>> [configure-root] WARNING: $*" >&2; } + SRC="{{ .chezmoi.sourceDir }}" ROOT_HOME="/root" @@ -48,7 +50,7 @@ if command -v fish >/dev/null 2>&1; then current="$(getent passwd root | cut -d: -f7)" if [ "$current" != "$(command -v fish)" ]; then echo ">>> [configure-root] chsh root → fish" - sudo chsh -s "$(command -v fish)" root || true + sudo chsh -s "$(command -v fish)" root || warn "chsh failed for root (may need /etc/shells entry)" else echo ">>> [configure-root] root shell already fish" fi diff --git a/run_once_60-configure-system.sh.tmpl b/run_once_60-configure-system.sh.tmpl index 9177903..9975a54 100755 --- a/run_once_60-configure-system.sh.tmpl +++ b/run_once_60-configure-system.sh.tmpl @@ -4,9 +4,12 @@ set -euo pipefail +warn() { echo ">>> [configure] WARNING: $*" >&2; } + SYS="{{ .system | default "desktop" }}" DISTRO_ID="{{ .chezmoi.osRelease.id | default "" }}" SRC="{{ .chezmoi.sourceDir }}" +OS_PROBER="{{ .os_prober | default false }}" echo ">>> [configure] distro=$DISTRO_ID, system=$SYS, source=$SRC" services=( @@ -39,6 +42,19 @@ case "$DISTRO_ID" in else echo ">>> [configure] /boot/grub/themes missing — skipping grub theme install" fi + + if [ "$OS_PROBER" = "true" ]; then + echo ">>> [configure] enabling GRUB os-prober" + sudo sed -i -E 's/^#?GRUB_DISABLE_OS_PROBER=.*/GRUB_DISABLE_OS_PROBER=false/' /etc/default/grub + if ! grep -q '^GRUB_DISABLE_OS_PROBER=' /etc/default/grub; then + echo 'GRUB_DISABLE_OS_PROBER=false' | sudo tee -a /etc/default/grub >/dev/null + fi + echo ">>> [configure] grub.cfg regenerating with os-prober entries" + sudo grub-mkconfig -o /boot/grub/grub.cfg \ + || warn "grub-mkconfig failed (os-prober entries may not be applied)" + else + echo ">>> [configure] GRUB os-prober disabled (per user choice)" + fi fi ;; diff --git a/run_once_70-configure-laptop.sh.tmpl b/run_once_70-configure-laptop.sh.tmpl index d78b886..ca17e8a 100755 --- a/run_once_70-configure-laptop.sh.tmpl +++ b/run_once_70-configure-laptop.sh.tmpl @@ -4,6 +4,8 @@ set -euo pipefail +warn() { echo ">>> [configure-laptop] WARNING: $*" >&2; } + SYS="{{ .system | default "desktop" }}" DISTRO_ID="{{ .chezmoi.osRelease.id | default "" }}" @@ -26,7 +28,7 @@ case "$DISTRO_ID" in sudo apt-get install -y tlp tlp-rdw power-profiles-daemon sudo systemctl enable tlp # tlp and power-profiles-daemon conflict on most hardware — mask the latter - sudo systemctl mask power-profiles-daemon || true + sudo systemctl mask power-profiles-daemon || warn "systemctl mask power-profiles-daemon failed (tlp conflict may cause issues)" ;; *)