/ de-omarchy / install.sh
swadhinbiswas Fix installer: batch repo pkgs + stdin-safe AUR prompts, create /etc/environment.d, retarget all runtime fallbacks to /usr/share/de-omarchy · 8/22/2026
3eba9d4
214 lines · 8.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/bin/bash
# ============================================================================
#  de-omarchy installer — Omarchy look & feel for any Arch-based system
#
#  Safety model:
#    * backs up everything BEFORE touching anything (outside this repo)
#    * never deletes or overwrites an existing user config; new files are
#      added, one clearly-marked block is APPENDED to hyprland.lua
#    * idempotent: safe to re-run
#    * fully reversible: uninstall.sh undoes every change made here
#  It never touches pacman.conf, kernels, bootloaders, mirrors or repos.
# ============================================================================
set -euo pipefail

REPO_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
RUNTIME=/usr/share/de-omarchy
BACKUP_ROOT="${DEO_BACKUP_ROOT:-$HOME/.de-omarchy-backups}"
MARKER_START=">>> de-omarchy layer"
MARKER_END="<<< end de-omarchy layer >>>"

log()  { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m ->\033[0m %s\n' "$*"; }
die()  { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; }

# ----------------------------------------------------------------------------
# 1. Preflight
# ----------------------------------------------------------------------------
[[ $EUID -eq 0 ]] && die "Run as your normal user (sudo is invoked when needed)."

[[ -r /etc/os-release ]] || die "/etc/os-release not found — not an Arch-based system?"
. /etc/os-release
case ${ID_LIKE:-} in
  *arch*) ;; *) [[ ${ID:-} == arch ]] || die "This looks like '${ID:-unknown}', de-omarchy targets Arch-based distros." ;;
esac

for cmd in git rsync curl; do command -v $cmd >/dev/null 2>&1 || die "missing command: $cmd"; done

AUR_HELPER=""
for h in paru yay; do command -v $h >/dev/null 2>&1 && { AUR_HELPER=$h; break; }; done

ASSUME_YES=0
SKIP_BACKUP=0
SKIP_PACKAGES=0
for arg in "$@"; do
  case $arg in
    -y|--yes) ASSUME_YES=1 ;;
    --skip-backup) SKIP_BACKUP=1 ;;
    --skip-packages) SKIP_PACKAGES=1 ;;
    *) warn "unknown option: $arg" ;;
  esac
done

cat <<BANNER

  de-omarchy — apply the Omarchy desktop look on top of $(printf '%s' "${PRETTY_NAME:-this system}")

  What happens:
    1. TARGETED backup (seconds): every file this installer could touch,
       plus .ssh / zsh stack / starship — -> $BACKUP_ROOT/<timestamp>/
       (add DEO_BACKUP_FULL=1 to also snapshot all of ~/.config)
    2. Missing UI packages installed (system layer untouched)
    3. Runtime deployed to $RUNTIME
    4. Additive user config hooks installed:
         ~/.config/hypr/{deo-layer,deo-bindings,deo-autostart}.lua  (new symlinks)
         ~/.config/hypr/hyprland.lua                                (marked block APPENDED)
         ~/.config/zshrc.d/50-de-omarchy.zsh                        (new symlink;
          your .zshrc already sources this dir — zero edits to .zshrc)
    5. Omarchy state initialized + rose-pine theme applied

  NOTHING in your home directory is ever deleted or overwritten:
    * new files are only ADDED (symlinks into this repo)
    * hyprland.lua gets one clearly-marked block APPENDED; a timestamped
      copy of it is saved next to it first
    * existing ~/.config/omarchy state is merged with --ignore-existing
  NOT touched: .zshrc/.zshenv/starship.toml/kitty.conf/ssh keys, pacman.conf,
  mirrors, kernel, bootloader, display manager, monitors layout.

BANNER

if (( ! ASSUME_YES )); then
  read -rp "Proceed? [y/N] " answer
  [[ $answer =~ ^[Yy]$ ]] || die "aborted by user"
fi

# ----------------------------------------------------------------------------
# 2. Backup (Phase 0 — always first)
# ----------------------------------------------------------------------------
if (( SKIP_BACKUP )); then
  warn "skipping backup (--skip-backup) — NOT recommended"
else
  log "Creating timestamped backup"
  DEO_BACKUP_ROOT=$BACKUP_ROOT bash "$REPO_DIR/scripts/backup.sh"
fi
LATEST_BACKUP=$(ls -1dt "$BACKUP_ROOT"/*/ 2>/dev/null | head -1 || true)
[[ -n $LATEST_BACKUP ]] || die "backup missing after backup step — aborting"
log "Backup ready: $LATEST_BACKUP"

# ----------------------------------------------------------------------------
# 3. Packages (UI layer only, missing ones only)
# ----------------------------------------------------------------------------
if (( ! SKIP_PACKAGES )); then
  log "Checking UI packages"
  MISSING=()
  while read -r pkg; do
    [[ -z $pkg || $pkg == \#* ]] && continue
    pacman -Qi "$pkg" >/dev/null 2>&1 || MISSING+=("$pkg")
  done < "$REPO_DIR/packages/ui.packages"

  if (( ${#MISSING[@]} == 0 )); then
    log "All UI packages already present"
  else
    log "Installing missing UI packages: ${MISSING[*]}"
    # Repo packages first, in ONE transaction (single sudo prompt).
    REPO_PKGS=()
    for pkg in "${MISSING[@]}"; do
      pacman -Si "$pkg" >/dev/null 2>&1 && REPO_PKGS+=("$pkg")
    done
    (( ${#REPO_PKGS[@]} > 0 )) && sudo pacman -S --needed --noconfirm "${REPO_PKGS[@]}"

    # Whatever remains is AUR-only: per package, with piped answers so
    # prompts (provider selection etc.) never eat our package list.
    FAILED=""
    for pkg in "${MISSING[@]}"; do
      pacman -Qi "$pkg" >/dev/null 2>&1 && continue
      if [[ -n $AUR_HELPER ]]; then
        printf '1\n1\n1\ny\n' | "$AUR_HELPER" -S --needed --noconfirm --skipreview "$pkg" \
          || FAILED+="$pkg "
      else
        FAILED+="$pkg "
      fi
    done
    [[ -n ${FAILED:-} ]] && warn "could not auto-install: $FAILED (install manually; desktop works without them)"
  fi
fi

command -v quickshell >/dev/null 2>&1 || die "quickshell is required but not installed"

# ----------------------------------------------------------------------------
# 4. Runtime deployment to $RUNTIME
# ----------------------------------------------------------------------------
log "Deploying runtime to $RUNTIME"
sudo mkdir -p "$RUNTIME"
sudo rsync -a --delete \
  "$REPO_DIR/bin" "$REPO_DIR/shell" "$REPO_DIR/themes" \
  "$REPO_DIR/applications" "$REPO_DIR/default" "$REPO_DIR/config" \
  "$RUNTIME/"
sudo chmod +x "$RUNTIME"/bin/* 2>/dev/null || true

log "Writing /etc/environment.d/10-de-omarchy.conf"
sudo mkdir -p /etc/environment.d
printf 'OMARCHY_PATH=%s\n' "$RUNTIME" | sudo tee /etc/environment.d/10-de-omarchy.conf >/dev/null

# ----------------------------------------------------------------------------
# 5. User config hooks (additive only)
# ----------------------------------------------------------------------------
log "Installing user config hooks"

mkdir -p "$HOME/.config/hypr" "$HOME/.config/zshrc.d"

ln -sfn "$REPO_DIR/config/hypr/deo-layer.lua"     "$HOME/.config/hypr/deo-layer.lua"
ln -sfn "$REPO_DIR/config/hypr/deo-bindings.lua"  "$HOME/.config/hypr/deo-bindings.lua"
ln -sfn "$REPO_DIR/config/hypr/deo-autostart.lua" "$HOME/.config/hypr/deo-autostart.lua"
ln -sfn "$REPO_DIR/config/zshrc.d/50-de-omarchy.zsh" "$HOME/.config/zshrc.d/50-de-omarchy.zsh"

# Default omarchy user-state config (extensions/hooks/themed) — never overwrite.
if [[ -d $REPO_DIR/config/omarchy ]]; then
  mkdir -p "$HOME/.config/omarchy"
  rsync -a --ignore-existing "$REPO_DIR/config/omarchy/" "$HOME/.config/omarchy/"
fi

# Append the marked activation block to hyprland.lua (idempotent).
HYPR_MAIN="$HOME/.config/hypr/hyprland.lua"
if [[ ! -f $HYPR_MAIN ]]; then
  die "~/.config/hypr/hyprland.lua not found — install/configure Hyprland first (or point me at your entry config)"
fi
if grep -q "$MARKER_START" "$HYPR_MAIN"; then
  log "hyprland.lua already carries the de-omarchy block — skipping append"
else
  cp -a "$HYPR_MAIN" "$HYPR_MAIN.pre-de-omarchy.$(date +%Y%m%d%H%M%S)"
  cat "$REPO_DIR/config/hypr/append-block.lua" >> "$HYPR_MAIN"
  log "Appended de-omarchy block to $HYPR_MAIN (pre-change copy saved next to it)"
fi

# ----------------------------------------------------------------------------
# 6. Omarchy state init + default theme
# ----------------------------------------------------------------------------
log "Initializing Omarchy state + rose-pine theme"
export OMARCHY_PATH=$RUNTIME
mkdir -p "$HOME/.local/state/omarchy/current"
"$RUNTIME/bin/omarchy-theme-set" rose-pine || warn "theme set failed (non-fatal; run 'omarchy theme set <name>' later)"

unset OMARCHY_PATH

# ----------------------------------------------------------------------------
# 7. Done
# ----------------------------------------------------------------------------
log "Verifying installation"
bash "$REPO_DIR/scripts/verify.sh" || warn "verification reported issues above"

cat <<DONE

  de-omarchy installed.

  Try it now (without logging out):
      source ~/.config/zshrc.d/50-de-omarchy.zsh
      hyprctl reload

  Full experience after next login (env vars settle everywhere).
  Themes:   omarchy theme list   |   omarchy theme set "Tokyo Night"
  Menu:     SUPER + SHIFT + M    (upstream's SUPER+SPACE stays yours)
  Revert:   ./uninstall.sh       (restores the exact pre-install state)

DONE