diff --git a/bin/omarchy-first-run b/bin/omarchy-first-run index 9f4826b1..f52aab0d 100755 --- a/bin/omarchy-first-run +++ b/bin/omarchy-first-run @@ -5,26 +5,41 @@ set -e -# Run user-level setup FIRST so its outcome (→ branding files, AI skill -# symlinks, xdg dirs, etc.) isn't held hostage to whether one of the -# privileged first-run steps below aborts under set -e. omarchy-setup-user -# is idempotent and gated on its own marker. +# Always: refresh per-user defaults (skel-derived configs, AI skills, XDG +# dirs, branding, MIME defaults, etc.). Idempotent via its own marker. omarchy-setup-user || true -FIRST_RUN_MODE=~/.local/state/omarchy/first-run.mode +# Online installs grant a one-time passwordless reboot from the installer. +# Clean it up after first login without prompting future users for sudo. +bash "$OMARCHY_PATH/install/first-run/cleanup-reboot-sudoers.sh" -if [[ -f $FIRST_RUN_MODE ]]; then - rm -f "$FIRST_RUN_MODE" +state_dir=~/.local/state/omarchy +mkdir -p "$state_dir" + +# System-wide one-shot. Gated on first-run.mode (created by finalize.sh during +# ISO installs). The install user is the only one whose /etc/sudoers.d/first-run +# shim grants the passwordless commands these scripts need, so only that user +# clears this marker. +SYSTEM_MARKER="$state_dir/first-run.mode" +if [[ -f $SYSTEM_MARKER ]]; then + rm -f "$SYSTEM_MARKER" - bash "$OMARCHY_PATH/install/first-run/recover-internal-monitor.sh" - bash "$OMARCHY_PATH/install/first-run/cleanup-reboot-sudoers.sh" bash "$OMARCHY_PATH/install/first-run/firewall.sh" bash "$OMARCHY_PATH/install/first-run/dns-resolver.sh" - bash "$OMARCHY_PATH/install/first-run/gnome-theme.sh" - bash "$OMARCHY_PATH/install/first-run/gtk-primary-paste.sh" + bash "$OMARCHY_PATH/install/first-run/gnome-theme-system.sh" omarchy-hook-install post-update "$OMARCHY_PATH/install/first-run/install-voxtype.hook" - sudo /bin/rm -f /etc/sudoers.d/first-run + sudo rm -f /etc/sudoers.d/first-run +fi +# Per-user one-shot. Runs on the first login for every user, including any +# users created after install. Touches only $HOME / user dbus, no sudo. +USER_MARKER="$state_dir/first-run-user.done" +if [[ ! -f $USER_MARKER ]]; then + bash "$OMARCHY_PATH/install/first-run/recover-internal-monitor.sh" + bash "$OMARCHY_PATH/install/first-run/gnome-theme-user.sh" + bash "$OMARCHY_PATH/install/first-run/gtk-primary-paste.sh" bash "$OMARCHY_PATH/install/first-run/welcome.sh" bash "$OMARCHY_PATH/install/first-run/wifi.sh" + + touch "$USER_MARKER" fi diff --git a/bin/omarchy-pkg-add b/bin/omarchy-pkg-add index 4db19e05..977d7efd 100755 --- a/bin/omarchy-pkg-add +++ b/bin/omarchy-pkg-add @@ -6,7 +6,11 @@ # omarchy:requires-sudo=true if omarchy-pkg-missing "$@"; then - sudo pacman -S --noconfirm --needed "$@" || exit 1 + if (( EUID == 0 )); then + pacman -S --noconfirm --needed "$@" || exit 1 + else + sudo pacman -S --noconfirm --needed "$@" || exit 1 + fi fi for pkg in "$@"; do diff --git a/bin/omarchy-refresh-hyprland b/bin/omarchy-refresh-hyprland index 999efa6b..d9f751d3 100755 --- a/bin/omarchy-refresh-hyprland +++ b/bin/omarchy-refresh-hyprland @@ -9,5 +9,23 @@ omarchy-refresh-config hypr/input.lua omarchy-refresh-config hypr/looknfeel.lua omarchy-refresh-config hypr/hyprland.lua omarchy-refresh-config hypr/monitors.lua -bash "$OMARCHY_PATH/install/config/omarchy-toggles.sh" -bash "$OMARCHY_PATH/install/config/detect-keyboard-layout.sh" + +mkdir -p ~/.local/state/omarchy/toggles/hypr +cp "$OMARCHY_PATH/default/hypr/toggles/flags.lua" ~/.local/state/omarchy/toggles/hypr/ + +conf=/etc/vconsole.conf +hyprlua="$HOME/.config/hypr/input.lua" +if [[ -f $conf && -f $hyprlua ]]; then + sed -i '/^[[:space:]]*kb_layout[[:space:]]*=/d' "$hyprlua" + sed -i '/^[[:space:]]*kb_variant[[:space:]]*=/d' "$hyprlua" + + if grep -q '^XKBLAYOUT=' "$conf"; then + layout=$(grep '^XKBLAYOUT=' "$conf" | cut -d= -f2 | tr -d '"') + sed -i "/^[[:space:]]*kb_options *=/i\ kb_layout = \"$layout\"," "$hyprlua" + fi + + if grep -q '^XKBVARIANT=' "$conf"; then + variant=$(grep '^XKBVARIANT=' "$conf" | cut -d= -f2 | tr -d '"') + sed -i "/^[[:space:]]*kb_options *=/i\ kb_variant = \"$variant\"," "$hyprlua" + fi +fi diff --git a/bin/omarchy-reinstall-configs b/bin/omarchy-reinstall-configs index a269f02a..ade902bd 100755 --- a/bin/omarchy-reinstall-configs +++ b/bin/omarchy-reinstall-configs @@ -17,7 +17,11 @@ cp -R $OMARCHY_PATH/config/* ~/.config/ cp $OMARCHY_PATH/default/bashrc ~/.bashrc echo '[[ -f ~/.bashrc ]] && . ~/.bashrc' | tee ~/.bash_profile >/dev/null -$(bash $OMARCHY_PATH/install/config/theme.sh) +env OMARCHY_PATH="$OMARCHY_PATH" OMARCHY_INSTALL_MODE=online bash -c ' + source "$OMARCHY_PATH/install/helpers/mode.sh" + detect_install_mode + source "$OMARCHY_PATH/install/config/theme-user.sh" +' omarchy-refresh-limine omarchy-refresh-plymouth diff --git a/bin/omarchy-setup-user b/bin/omarchy-setup-user index b2605a27..96c5971d 100755 --- a/bin/omarchy-setup-user +++ b/bin/omarchy-setup-user @@ -1,12 +1,12 @@ #!/bin/bash # omarchy:summary=Set up Omarchy for the current user (~/.config, ~/.local, etc.) -# omarchy:group=install +# omarchy:group=setup # omarchy:examples=omarchy setup user | omarchy setup user --force set -euo pipefail -if [[ $EUID -eq 0 ]]; then +if (( EUID == 0 )); then echo "Error: run omarchy-setup-user as the user being configured, not as root." >&2 exit 1 fi @@ -38,7 +38,34 @@ if [[ -f $marker && $force -eq 0 ]]; then exit 0 fi -OMARCHY_PATH="${OMARCHY_PATH:-/usr/share/omarchy}" +export OMARCHY_PATH="${OMARCHY_PATH:-/usr/share/omarchy}" +export OMARCHY_INSTALL="${OMARCHY_INSTALL:-$OMARCHY_PATH/install}" +export PATH="$OMARCHY_PATH/bin:$PATH" + +if [[ -f $OMARCHY_INSTALL/helpers/mode.sh ]]; then + source "$OMARCHY_INSTALL/helpers/mode.sh" + detect_install_mode + export_legacy_mode_flags +else + install_mode_is() { [[ ${OMARCHY_INSTALL_MODE:-online} == "$1" ]]; } + export -f install_mode_is +fi + +if [[ -n ${OMARCHY_INSTALL_LOG_FILE:-} && -f $OMARCHY_INSTALL/helpers/logging.sh ]]; then + source "$OMARCHY_INSTALL/helpers/logging.sh" +else + run_logged() { + local script="$1" + bash -eE -c 'source "$1"' bash "$script" + } +fi + +# Copy over Omarchy configs for this user. /etc/skel handles newly-created +# users, but existing users installing Omarchy need the same defaults seeded. +mkdir -p ~/.config +cp -R "$OMARCHY_PATH/config/." ~/.config/ +cp "$OMARCHY_PATH/default/bashrc" ~/.bashrc +echo '[[ -f ~/.bashrc ]] && . ~/.bashrc' > ~/.bash_profile # AI assistant skill symlinks. Each agent has its own conventional skills # directory; we drop an 'omarchy' entry into each so the skill is loaded. @@ -72,13 +99,17 @@ xdg-user-dirs-update --set DESKTOP "$HOME" rmdir ~/Templates ~/Public ~/Desktop 2>/dev/null || true touch ~/.config/gtk-3.0/bookmarks for dir in Downloads Projects Pictures Videos; do - printf 'file://%s/%s %s\n' "$HOME" "$dir" "$dir" >>~/.config/gtk-3.0/bookmarks + bookmark="file://$HOME/$dir $dir" + grep -qxF "$bookmark" ~/.config/gtk-3.0/bookmarks || echo "$bookmark" >>~/.config/gtk-3.0/bookmarks done # Hyprland keyboard layout from /etc/vconsole.conf conf=/etc/vconsole.conf hyprlua="$HOME/.config/hypr/input.lua" if [[ -f $conf && -f $hyprlua ]]; then + sed -i '/^[[:space:]]*kb_layout[[:space:]]*=/d' "$hyprlua" + sed -i '/^[[:space:]]*kb_variant[[:space:]]*=/d' "$hyprlua" + if grep -q '^XKBLAYOUT=' "$conf"; then layout=$(grep '^XKBLAYOUT=' "$conf" | cut -d= -f2 | tr -d '"') sed -i "/^[[:space:]]*kb_options *=/i\ kb_layout = \"$layout\"," "$hyprlua" @@ -89,7 +120,12 @@ if [[ -f $conf && -f $hyprlua ]]; then fi fi -# Application catalog + MIME defaults +# Reusable per-user install phase: theme, shell/user services, default keyring, +# hardware-specific user session fixes, and other current-user setup. +source "$OMARCHY_INSTALL/user/all.sh" + +# Application catalog + MIME defaults. Run after mise/node setup from user/all +# so npm-backed wrappers can be installed for each user. omarchy-refresh-applications xdg-settings set default-web-browser chromium.desktop xdg-mime default HEY.desktop x-scheme-handler/mailto diff --git a/finalize.sh b/finalize.sh index 01c9f371..7e84f4f6 100644 --- a/finalize.sh +++ b/finalize.sh @@ -52,7 +52,13 @@ for _f in "$OMARCHY_PATH/migrations"/*.sh; do [[ -f $_f ]] && touch ~/.local/state/omarchy/migrations/"$(basename "$_f")" done -source "$OMARCHY_INSTALL/packaging/all.sh" -source "$OMARCHY_INSTALL/config/all.sh" -source "$OMARCHY_INSTALL/login/all.sh" -source "$OMARCHY_INSTALL/post-install/all.sh" +# Offline installs need the privileged system first-run block on the install +# user's first login. The sudoers shim is written by system-finalize.sh; this +# per-user marker ensures only the install user consumes it. +if install_mode_is offline; then + mkdir -p ~/.local/state/omarchy + touch ~/.local/state/omarchy/first-run.mode +fi + +omarchy-setup-user --force +source "$OMARCHY_INSTALL/post-install/finished.sh" diff --git a/install.sh b/install.sh index 274784ca..bb39c4d6 100644 --- a/install.sh +++ b/install.sh @@ -35,4 +35,20 @@ _omarchy_runtime_pkg="${OMARCHY_RUNTIME_PACKAGE:-omarchy}" mapfile -t _omarchy_base_pkgs < <(grep -v '^#\|^$' "$OMARCHY_PATH/install/omarchy-base.packages") sudo pacman -Syu --noconfirm --needed "$_omarchy_runtime_pkg" "${_omarchy_base_pkgs[@]}" +# Root/system setup first; user-home setup remains in finalize.sh below. +sudo env \ + OMARCHY_INSTALL_MODE="${OMARCHY_INSTALL_MODE:-}" \ + OMARCHY_ONLINE_INSTALL="${OMARCHY_ONLINE_INSTALL:-}" \ + OMARCHY_CHROOT_INSTALL="${OMARCHY_CHROOT_INSTALL:-}" \ + OMARCHY_PATH="$OMARCHY_PATH" \ + OMARCHY_INSTALL="$OMARCHY_INSTALL" \ + OMARCHY_INSTALL_LOG_FILE="$OMARCHY_INSTALL_LOG_FILE" \ + OMARCHY_START_TIME="${OMARCHY_START_TIME:-}" \ + OMARCHY_START_EPOCH="${OMARCHY_START_EPOCH:-}" \ + OMARCHY_USER_NAME="${OMARCHY_USER_NAME:-}" \ + OMARCHY_USER_EMAIL="${OMARCHY_USER_EMAIL:-}" \ + OMARCHY_MIRROR="${OMARCHY_MIRROR:-}" \ + OMARCHY_INSTALL_USER="$USER" \ + bash "$OMARCHY_PATH/system-finalize.sh" + exec bash "$OMARCHY_PATH/finalize.sh" diff --git a/install/config/all.sh b/install/config/all.sh index d9d2aefe..b8393bb5 100644 --- a/install/config/all.sh +++ b/install/config/all.sh @@ -1,21 +1,9 @@ -run_logged $OMARCHY_INSTALL/config/theme.sh -run_logged $OMARCHY_INSTALL/config/git.sh -run_logged $OMARCHY_INSTALL/config/gpg.sh +run_logged $OMARCHY_INSTALL/config/theme-system.sh run_logged $OMARCHY_INSTALL/config/increase-lockout-limit.sh run_logged $OMARCHY_INSTALL/config/lockscreen-pam.sh -run_logged $OMARCHY_INSTALL/config/sleep-lock.sh -run_logged $OMARCHY_INSTALL/config/increase-file-watchers.sh -run_logged $OMARCHY_INSTALL/config/increase-fd-limit.sh -run_logged $OMARCHY_INSTALL/config/xcompose.sh -run_logged $OMARCHY_INSTALL/config/mise-work.sh run_logged $OMARCHY_INSTALL/config/fix-powerprofilesctl-shebang.sh run_logged $OMARCHY_INSTALL/config/docker.sh -run_logged $OMARCHY_INSTALL/config/localdb.sh -run_logged $OMARCHY_INSTALL/config/fast-shutdown.sh run_logged $OMARCHY_INSTALL/config/input-group.sh -run_logged $OMARCHY_INSTALL/config/pi.sh -run_logged $OMARCHY_INSTALL/config/powerprofilesctl-rules.sh -run_logged $OMARCHY_INSTALL/config/wifi-powersave-rules.sh # Service enables centralized; run after all drop-in files are in place. run_logged $OMARCHY_INSTALL/config/enable-services.sh @@ -23,6 +11,7 @@ run_logged $OMARCHY_INSTALL/config/enable-services.sh run_logged $OMARCHY_INSTALL/config/hardware/network.sh run_logged $OMARCHY_INSTALL/config/hardware/set-wireless-regdom.sh run_logged $OMARCHY_INSTALL/config/hardware/fix-fkeys.sh +run_logged $OMARCHY_INSTALL/config/hardware/fix-synaptic-touchpad.sh run_logged $OMARCHY_INSTALL/config/hardware/bluetooth.sh run_logged $OMARCHY_INSTALL/config/hardware/nvidia.sh run_logged $OMARCHY_INSTALL/config/hardware/vulkan.sh @@ -39,11 +28,8 @@ run_logged $OMARCHY_INSTALL/config/hardware/intel/sof-firmware.sh run_logged $OMARCHY_INSTALL/config/hardware/asus/fix-asus-ptl-display-backlight.sh run_logged $OMARCHY_INSTALL/config/hardware/asus/fix-asus-ptl-b9406-display.sh run_logged $OMARCHY_INSTALL/config/hardware/asus/fix-asus-ptl-b9406-touchpad.sh -run_logged $OMARCHY_INSTALL/config/hardware/asus/fix-audio-mixer.sh -run_logged $OMARCHY_INSTALL/config/hardware/asus/fix-mic.sh run_logged $OMARCHY_INSTALL/config/hardware/asus/fix-z13-touchpad.sh -run_logged $OMARCHY_INSTALL/config/hardware/framework/fix-f13-amd-audio-input.sh run_logged $OMARCHY_INSTALL/config/hardware/framework/qmk-hid.sh run_logged $OMARCHY_INSTALL/config/hardware/apple/fix-spi-keyboard.sh @@ -55,5 +41,4 @@ run_logged $OMARCHY_INSTALL/config/hardware/lenovo/fix-yoga-pro7-bass-speakers.s run_logged $OMARCHY_INSTALL/config/hardware/fix-bcm43xx.sh run_logged $OMARCHY_INSTALL/config/hardware/fix-surface-keyboard.sh run_logged $OMARCHY_INSTALL/config/hardware/fix-yt6801-ethernet-adapter.sh -run_logged $OMARCHY_INSTALL/config/hardware/fix-synaptic-touchpad.sh run_logged $OMARCHY_INSTALL/config/hardware/fix-tuxedo-backlight.sh diff --git a/install/first-run/cleanup-reboot-sudoers.sh b/install/first-run/cleanup-reboot-sudoers.sh index 9a3ebf75..d29065ed 100644 --- a/install/first-run/cleanup-reboot-sudoers.sh +++ b/install/first-run/cleanup-reboot-sudoers.sh @@ -1 +1 @@ -sudo /bin/rm -f /etc/sudoers.d/99-omarchy-installer-reboot +sudo -n rm -f /etc/sudoers.d/99-omarchy-installer-reboot 2>/dev/null || true diff --git a/install/helpers/chroot.sh b/install/helpers/chroot.sh index 96430ede..acefb81b 100644 --- a/install/helpers/chroot.sh +++ b/install/helpers/chroot.sh @@ -1,15 +1,9 @@ -# In offline (ISO chroot) mode systemd isn't running, so skip --now. +# Installs are followed by reboot, so enable units without starting/reloading +# running services during the install. chrootable_systemctl_enable() { - if install_mode_is offline; then - sudo systemctl enable $1 - else - sudo systemctl enable --now $1 - fi + sudo systemctl enable $1 } -# Like chrootable_systemctl_enable but never passes --now. Use for services -# we shouldn't (re)start mid-install (iwd interrupts the network; docker and -# power-profiles-daemon should defer to first boot). chrootable_systemctl_enable_only() { sudo systemctl enable $1 } diff --git a/install/login/all.sh b/install/login/all.sh index 341068f6..45ff5ad6 100644 --- a/install/login/all.sh +++ b/install/login/all.sh @@ -1,6 +1 @@ -run_logged $OMARCHY_INSTALL/login/default-keyring.sh -run_logged $OMARCHY_INSTALL/login/sddm.sh -if install_mode_is online; then - run_logged $OMARCHY_INSTALL/login/hibernation.sh -fi -run_logged $OMARCHY_INSTALL/login/limine-snapper.sh +source $OMARCHY_INSTALL/login/system.sh diff --git a/install/login/default-keyring.sh b/install/login/default-keyring.sh index 459a0cb4..63f70798 100644 --- a/install/login/default-keyring.sh +++ b/install/login/default-keyring.sh @@ -4,7 +4,8 @@ DEFAULT_FILE="$KEYRING_DIR/default" mkdir -p "$KEYRING_DIR" -cat << EOF > "$KEYRING_FILE" +if [[ ! -f $KEYRING_FILE ]]; then + cat > "$KEYRING_FILE" < "$DEFAULT_FILE" +if [[ ! -f $DEFAULT_FILE ]]; then + cat > "$DEFAULT_FILE" </dev/null < /etc/sudoers.d/99-omarchy-installer-reboot <"$TMP/install/packaging/all.sh" <<'SCRIPT' +cat >"$TMP/install/user/all.sh" <<'SCRIPT' run_logged "$OMARCHY_INSTALL/packaging/marker.sh" +install_mode_is offline +echo user-marker >>"$OMARCHY_INSTALL_LOG_FILE" +stop_install_log +touch "$HOME/finalizer-completed" SCRIPT cat >"$TMP/install/packaging/marker.sh" <<'SCRIPT' echo packaging-marker SCRIPT -cat >"$TMP/install/config/all.sh" <<'SCRIPT' -echo config-marker >>"$OMARCHY_INSTALL_LOG_FILE" +for script in icons webapps tuis npm; do + cat >"$TMP/install/packaging/$script.sh" <<'SCRIPT' +: SCRIPT +done -cat >"$TMP/install/login/all.sh" <<'SCRIPT' -install_mode_is offline -echo login-marker >>"$OMARCHY_INSTALL_LOG_FILE" -SCRIPT - -cat >"$TMP/install/post-install/all.sh" <<'SCRIPT' +cat >"$TMP/install/post-install/finished.sh" <<'SCRIPT' stop_install_log touch "$HOME/finalizer-completed" +return 0 2>/dev/null || exit 0 SCRIPT +cat >"$TMP/omarchy/default/bashrc" <<'EOF' +# test bashrc +EOF +cat >"$TMP/omarchy/default/alacritty/Alacritty.desktop" <<'EOF' +[Desktop Entry] +Name=Alacritty +Type=Application +Exec=true +EOF +cat >"$TMP/omarchy/default/hypr/toggles/flags.lua" <<'EOF' +return {} +EOF +: >"$TMP/omarchy/default/nautilus-python/extensions/localsend.py" +: >"$TMP/omarchy/default/nautilus-python/extensions/transcode.py" +cat >"$TMP/omarchy/icon.txt" <<'EOF' +icon +EOF +cat >"$TMP/omarchy/logo.txt" <<'EOF' +logo +EOF +cat >"$TMP/omarchy/applications/test.desktop" <<'EOF' +[Desktop Entry] +Name=Test +Type=Application +Exec=true +EOF +: >"$TMP/omarchy/applications/icons/Test.png" + +for cmd in gtk-update-icon-cache update-desktop-database xdg-mime xdg-settings xdg-user-dirs-update; do + cat >"$TMP/omarchy/bin/$cmd" <<'SCRIPT' +#!/bin/bash +: +SCRIPT + chmod +x "$TMP/omarchy/bin/$cmd" +done + if grep -Eq '^[[:space:]]*(source|\.)[[:space:]].*helpers/all\.sh' "$ROOT/finalize.sh"; then echo "finalize.sh must not source helpers/all.sh" >&2 exit 1 @@ -73,8 +120,8 @@ if ! grep -q 'packaging-marker' "$TMP/omarchy-install.log"; then exit 1 fi -if ! grep -q 'login-marker' "$TMP/omarchy-install.log"; then - echo "expected sourced target scripts to run" >&2 +if ! grep -q 'user-marker' "$TMP/omarchy-install.log"; then + echo "expected sourced user scripts to run" >&2 exit 1 fi