Krolyxon
Commit 136d805

Branches

Refs →

aurorainstall.sh

454 lines · 13.4 KB · Bourne Again Shell (bash)

1#!/usr/bin/env bash
2#
3# aurora installer (krolyxon's desktop)
4#
5# READ THIS FIRST:
6# This sets up MY personal desktop (Arch + Hyprland + aurora), built around my own
7# hardware (Lenovo Legion, Intel + NVIDIA hybrid, linux-zen) and my habits.
8# It is NOT a general purpose installer and I'm not trying to make it one.
9#
10# Only run it on a FRESHLY INSTALLED, UNCONFIGURED Arch Linux system.
11# It installs a lot of packages, moves your existing configs out of the way,
12# changes your login shell and can enable system services.
13#
14# If you just want a piece of the setup, copy the files you like instead.
15#
16# Usage:
17# ./install.sh interactive
18# ./install.sh --yes pre-select everything (still asks the fresh-system question)
19# ./install.sh --check compare installed packages with packages/*.txt, changes nothing
20
21trap 'log WARN "Interrupted by user"; exit 130' INT
22
23INSTALL_STATUS="none" # none | partial | complete | failed
24AUTO_YES=0
25CHECK_ONLY=0
26BACKUP_DIR=""
27
28log() {
29 local level="$1"
30 shift
31
32 local color reset='\033[0m'
33 case "$level" in
34 INFO) color='\033[0;34m' ;; # Blue
35 WARN) color='\033[0;33m' ;; # Yellow
36 ERROR) color='\033[0;31m' ;; # Red
37 SUCCESS) color='\033[0;32m' ;; # Green
38 *) color='\033[0m' ;;
39 esac
40
41 printf '%b[%s] [%s]%b %s\n' \
42 "$color" "$(date '+%H:%M:%S')" "$level" "$reset" "$*" >&2
43}
44
45usage() {
46 sed -n '3,19s/^# \{0,1\}//p' "$0"
47}
48
49#######################
50## Arguement Parsing ##
51#######################
52for arg in "$@"; do
53 case "$arg" in
54 --yes|--ci|--non-interactive)
55 AUTO_YES=1
56 ;;
57 --check)
58 CHECK_ONLY=1
59 ;;
60 -h|--help)
61 usage
62 exit 0
63 ;;
64 *)
65 log ERROR "Unknown option: $arg"
66 usage
67 exit 1
68 ;;
69 esac
70done
71
72currentDir="$(dirname "$(readlink -f "$0")")"
73cd "$currentDir" || exit 1
74PKG_DIR="$currentDir/packages"
75
76
77###################
78## Package lists ##
79###################
80# packages/*.txt: one package per line, '#' comments.
81# A trailing '!' (e.g. "blender !") means: listed, but not pre-selected in the picker.
82
83# All packages in a list
84read_list() {
85 sed 's/#.*//' "$PKG_DIR/$1.txt" | awk 'NF { print $1 }'
86}
87
88# Packages of a list that are pre-selected in the picker
89preselected() {
90 sed 's/#.*//' "$PKG_DIR/$1.txt" | awk 'NF && $2 != "!" { print $1 }'
91}
92
93check_packages() {
94 local listed installed aur
95 listed=$(for f in "$PKG_DIR"/*.txt; do read_list "$(basename "$f" .txt)"; done | sort -u)
96 installed=$(pacman -Qqe | sort -u)
97 aur=$(pacman -Qqm | sort -u)
98
99 echo "Installed explicitly, but not in any packages/*.txt:"
100 comm -23 <(echo "$installed") <(echo "$listed") | while read -r p; do
101 if grep -qx "$p" <<< "$aur"; then echo " $p (aur)"; else echo " $p"; fi
102 done
103
104 echo
105 echo "Listed, but not installed:"
106 comm -13 <(pacman -Qq | sort -u) <(echo "$listed") | sed 's/^/ /'
107}
108
109if ((CHECK_ONLY)); then
110 check_packages
111 exit 0
112fi
113
114
115#################
116## GATEKEEPING ##
117#################
118
119## Prevent user from running this script as root
120if [[ "$EUID" -eq 0 ]]; then
121 log ERROR "This script must NOT be run as root."
122 log INFO "If you need elevated privileges, the script will ask for sudo when required."
123 exit 1
124fi
125
126if [[ ! -f /etc/arch-release ]]; then
127 log ERROR "This is not Arch Linux. These dotfiles and this script are for Arch only."
128 exit 1
129fi
130
131## Does this look like a system that is already set up?
132## (configs this repo doesn't provide, or another desktop's config)
133check_fresh_system() {
134 local foreign=() desktops=() entry
135 for entry in "$HOME"/.config/*; do
136 [[ -e "$entry" ]] || continue
137 entry="$(basename "$entry")"
138 [[ -e "$currentDir/.config/$entry" ]] || foreign+=("$entry")
139 done
140 for entry in i3 sway niri river awesome bspwm openbox qtile xfce4 \
141 kdeglobals plasma-org.kde.plasma.desktop-appletsrc gnome-session; do
142 [[ -e "$HOME/.config/$entry" ]] && desktops+=("$entry")
143 done
144
145 ((${#foreign[@]} <= 10 && ${#desktops[@]} == 0)) && return 0
146
147 printf '\033[1;31m'
148 echo "=================================================================="
149 echo " This does NOT look like a fresh Arch install."
150 echo
151 ((${#desktops[@]})) && echo " Found another desktop's config: ${desktops[*]}"
152 ((${#foreign[@]} > 10)) && echo " Found ${#foreign[@]} entries in ~/.config that this repo doesn't provide."
153 echo
154 echo " This installer is meant for a freshly installed, unconfigured"
155 echo " system. On a system you already use it WILL change things you"
156 echo " care about: your configs get moved aside, your shell changes, and"
157 echo " lots of packages get installed."
158 echo "=================================================================="
159 printf '\033[0m'
160 local answer
161 read -rp "Type 'I understand' to continue anyway: " answer
162 [[ "$answer" == "I understand" ]] || { log WARN "Aborted."; exit 1; }
163}
164check_fresh_system
165
166choose_packages() {
167 local list="$1"
168 gum choose --no-limit \
169 --selected "$(preselected "$list" | paste -sd,)" \
170 $(read_list "$list")
171}
172
173prompt_style() {
174 gum style \
175 --border rounded \
176 --padding "0 1" \
177 "$1"
178}
179
180gum_warn(){
181 gum style --bold --foreground 196 "⚠ $1"
182}
183
184gum_to_array() {
185 local -n arr="$1"
186 mapfile -t arr
187 local cleaned=()
188 for item in "${arr[@]}"; do
189 [[ -n "$item" ]] && cleaned+=("$item")
190 done
191 arr=("${cleaned[@]}")
192}
193
194confirm() {
195 local msg="$1"
196 if ((AUTO_YES)); then
197 log INFO "[auto] $msg → yes"
198 return 0
199 fi
200 gum confirm --default=false "$msg"
201}
202
203install_prerequisites() {
204 sudo pacman -S --needed --noconfirm stow gum git zsh
205}
206
207## Installs prerequisites
208log INFO "Installing prerequisites: "
209install_prerequisites
210
211
212DISCLAIMER=$(gum style \
213 --border double \
214 --border-foreground 196 \
215 --padding "1 2" \
216 --bold \
217"⚠️ DISCLAIMER
218
219These are MY personal dotfiles, built for MY machine
220(Lenovo Legion, Intel + NVIDIA hybrid, linux-zen) and the way I work.
221They are NOT general purpose. They're public as a reference,
222or for people who want exactly the same setup.
223
224Only run this on a FRESHLY INSTALLED, UNCONFIGURED Arch system.
225
226This script is provided AS IS, WITHOUT ANY WARRANTY. It will:
227• Install a lot of packages (including NVIDIA drivers if selected)
228• Move conflicting files in your \$HOME to ~/.aurora-backup/
229• Change your login shell to zsh
230• Optionally write /etc/keyd and enable keyd
231• Optionally write /etc/pam.d/{login,passwd} (GNOME keyring unlock)
232• Enable the aurora-shell.service user unit
233
234Proceed at your OWN RISK."
235)
236
237confirm "$DISCLAIMER
238
239Do you understand the risks and want to continue?" || exit 1
240
241
242#######################
243## Package selection ##
244#######################
245SELECTED_PKGS=()
246for list in utils dev gpu optional aur; do
247 case "$list" in
248 utils) prompt_style "Important utilities (Most likely go with defaults)" ;;
249 dev) prompt_style "Select Development Tools" ;;
250 gpu) prompt_style "Select GPU drivers" ;;
251 optional) prompt_style "Select Optional Desktop Packages" ;;
252 aur) prompt_style "Select AUR packages" ;;
253 esac
254
255 if ((AUTO_YES)); then
256 mapfile -t picked < <(preselected "$list")
257 else
258 gum_to_array picked < <(choose_packages "$list")
259 fi
260 SELECTED_PKGS+=("${picked[@]}")
261done
262
263
264##########################
265## Configure Everything ##
266##########################
267WARNING=$(gum style \
268 --border double \
269 --border-foreground 196 \
270 --padding "1 2" \
271 --bold \
272 "⚠️ Files in your \$HOME that conflict with this repo will be MOVED to
273~/.aurora-backup/<date>/ and replaced with symlinks from this repo.")
274
275if confirm "$WARNING
276
277Proceed with system configuration (stow, shell)?"; then
278 ###################
279 ## Stow dotfiles ##
280 ###################
281 log INFO "Detecting conflicts..."
282 mapfile -t conflicts < <(stow -t "$HOME" . --no-folding -nv 2>&1 | \
283 sed -n 's/.*existing target \(.*\) since neither.*/\1/p')
284
285 if ((${#conflicts[@]} == 0)); then
286 log INFO "No conflicts. Running stow normally..."
287 else
288 log WARN "These paths conflict and will be moved to a backup:"
289 printf ' %s\n' "${conflicts[@]}"
290 if ! confirm "Move these files to ~/.aurora-backup/ ?"; then
291 log WARN "Aborted."
292 exit 1
293 fi
294
295 # Move conflicts (relative to $HOME) into the backup dir, keeping their paths
296 BACKUP_DIR="$HOME/.aurora-backup/$(date '+%Y%m%d-%H%M%S')"
297 for path in "${conflicts[@]}"; do
298 [[ -n "$path" && "$path" != "/" ]] || continue
299 mkdir -p "$BACKUP_DIR/$(dirname "$path")"
300 mv "$HOME/$path" "$BACKUP_DIR/$path" && log INFO "Backed up $path"
301 done
302 log INFO "Backups are in $BACKUP_DIR"
303 fi
304
305 stow -t "$HOME" . --no-folding \
306 && log SUCCESS "Dotfiles stowed successfully" \
307 || log ERROR "Stow failed"
308
309 #################################
310 ## Change default shell to zsh ##
311 #################################
312 log INFO "Changing the default shell to ZSH"
313 if [[ "$SHELL" != "$(command -v zsh)" ]]; then
314 chsh -s "$(command -v zsh)" \
315 && log SUCCESS "Default shell successfully set to zsh" \
316 || log ERROR "Default shell could not be set to zsh"
317 else
318 log INFO "Skipping: zsh is already the default shell"
319 fi
320else
321 log ERROR "Aborted stow, didn't configure or install anything"
322 exit 1
323fi
324
325
326mapfile -t DESKTOP_PKGS < <(read_list desktop)
327ALL_PKGS=(
328 "${DESKTOP_PKGS[@]}"
329 "${SELECTED_PKGS[@]}"
330)
331
332########################
333## Install Everything ##
334########################
335if ((${#ALL_PKGS[@]})); then
336 if confirm "Install all the selected packages?"; then
337 log INFO "Installing selected packages..."
338
339 ## Installing paru if not installed already
340 if ! command -v paru >/dev/null 2>&1; then
341 log INFO "Installing Paru (AUR package manager)"
342 sudo pacman -S --needed --noconfirm base-devel
343 git clone https://aur.archlinux.org/paru.git
344 (cd paru && makepkg -sri)
345 rm -rf paru
346 fi
347
348 if paru -Syu --needed "${ALL_PKGS[@]}"; then
349 INSTALL_STATUS="complete"
350 else
351 INSTALL_STATUS="failed"
352 fi
353 else
354 log WARN "Package installation skipped by user"
355 INSTALL_STATUS="partial"
356 fi
357else
358 log WARN "No packages selected"
359 INSTALL_STATUS="partial"
360fi
361
362
363
364################
365## Setup Keyd ##
366################
367if command -v keyd >/dev/null 2>&1; then
368 if confirm "Configure and enable keyd? "; then
369 log INFO "Copying keyd configuration to /etc/keyd/default.conf"
370 sudo cp "$currentDir/system/etc/keyd/default.conf" /etc/keyd/
371 sudo systemctl enable --now keyd.service \
372 && log SUCCESS "Successfully enabled keyd.service" \
373 || log ERROR "Couldn't enable keyd.service"
374 fi
375fi
376
377
378############################
379## GNOME keyring on login ##
380############################
381# pam_gnome_keyring unlocks the "login" keyring with the login password (tty login and hyprlock,
382# whose PAM file includes login); passwd keeps the keyring password in sync.
383if confirm "Unlock GNOME keyring at login (writes /etc/pam.d/login and passwd)?"; then
384 log INFO "Copying PAM files to /etc/pam.d"
385 sudo cp "$currentDir/system/etc/pam.d/login" "$currentDir/system/etc/pam.d/passwd" /etc/pam.d/ \
386 && log SUCCESS "GNOME keyring unlocks at login" \
387 || log ERROR "Couldn't write /etc/pam.d"
388fi
389
390
391#########################
392## Enable aurora shell ##
393#########################
394# User unit, stowed to ~/.config/systemd/user. Hyprland starts it at login,
395# enabling it also ties it to graphical-session.target. No --now: no session yet.
396if [[ -f "$HOME/.config/systemd/user/aurora-shell.service" ]]; then
397 if confirm "Enable aurora-shell.service (the desktop shell)?"; then
398 systemctl --user daemon-reload
399 systemctl --user enable aurora-shell.service \
400 && log SUCCESS "Successfully enabled aurora-shell.service" \
401 || log ERROR "Couldn't enable aurora-shell.service (run 'systemctl --user enable aurora-shell' after logging in)"
402 fi
403else
404 log WARN "aurora-shell.service is not stowed, skipping"
405fi
406
407
408####################
409## Final dialogue ##
410####################
411BACKUP_NOTE=""
412[[ -n "$BACKUP_DIR" ]] && BACKUP_NOTE="
413
414Your old conflicting files are in:
415$BACKUP_DIR"
416
417case "$INSTALL_STATUS" in
418 complete)
419 gum style \
420 --border rounded \
421 --border-foreground 42 \
422 --padding "1 2" \
423 --bold \
424 "✔ Installation Complete!
425
426All selected packages were installed successfully.
427You may now reboot the system for all the changes to apply.$BACKUP_NOTE"
428 ;;
429 partial)
430 gum style \
431 --border rounded \
432 --border-foreground 220 \
433 --padding "1 2" \
434 --bold \
435 "⚠ Setup Finished (Partial)
436
437Some steps were skipped by user choice.
438Your system was NOT fully configured.$BACKUP_NOTE"
439 ;;
440 failed)
441 gum style \
442 --border rounded \
443 --border-foreground 196 \
444 --padding "1 2" \
445 --bold \
446 "❌ Installation Failed
447
448One or more steps did not complete successfully.
449Check the logs above.$BACKUP_NOTE"
450 ;;
451 *)
452 gum style --bold "Finished.$BACKUP_NOTE"
453 ;;
454esac