Krolyxon
Commit a466635

Branches

Refs →

aurorainstall.sh

440 lines · 12.7 KB · Bourne Again Shell (bash)

1#!/usr/bin/env bash
2#
3# krolyxon's dotfiles installer
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 ~/.dotfiles-backup/
229• Change your login shell to zsh
230• Optionally write /etc/keyd and enable keyd
231• Enable the aurora.service user unit
232
233Proceed at your OWN RISK."
234)
235
236confirm "$DISCLAIMER
237
238Do you understand the risks and want to continue?" || exit 1
239
240
241#######################
242## Package selection ##
243#######################
244SELECTED_PKGS=()
245for list in utils dev gpu optional aur; do
246 case "$list" in
247 utils) prompt_style "Important utilities (Most likely go with defaults)" ;;
248 dev) prompt_style "Select Development Tools" ;;
249 gpu) prompt_style "Select GPU drivers" ;;
250 optional) prompt_style "Select Optional Desktop Packages" ;;
251 aur) prompt_style "Select AUR packages" ;;
252 esac
253
254 if ((AUTO_YES)); then
255 mapfile -t picked < <(preselected "$list")
256 else
257 gum_to_array picked < <(choose_packages "$list")
258 fi
259 SELECTED_PKGS+=("${picked[@]}")
260done
261
262
263##########################
264## Configure Everything ##
265##########################
266WARNING=$(gum style \
267 --border double \
268 --border-foreground 196 \
269 --padding "1 2" \
270 --bold \
271 "⚠️ Files in your \$HOME that conflict with this repo will be MOVED to
272~/.dotfiles-backup/<date>/ and replaced with symlinks from this repo.")
273
274if confirm "$WARNING
275
276Proceed with system configuration (stow, shell)?"; then
277 ###################
278 ## Stow dotfiles ##
279 ###################
280 log INFO "Detecting conflicts..."
281 mapfile -t conflicts < <(stow . --no-folding -nv 2>&1 | \
282 sed -n 's/.*existing target \(.*\) since neither.*/\1/p')
283
284 if ((${#conflicts[@]} == 0)); then
285 log INFO "No conflicts. Running stow normally..."
286 else
287 log WARN "These paths conflict and will be moved to a backup:"
288 printf ' %s\n' "${conflicts[@]}"
289 if ! confirm "Move these files to ~/.dotfiles-backup/ ?"; then
290 log WARN "Aborted."
291 exit 1
292 fi
293
294 # Move conflicts (relative to $HOME) into the backup dir, keeping their paths
295 BACKUP_DIR="$HOME/.dotfiles-backup/$(date '+%Y%m%d-%H%M%S')"
296 for path in "${conflicts[@]}"; do
297 [[ -n "$path" && "$path" != "/" ]] || continue
298 mkdir -p "$BACKUP_DIR/$(dirname "$path")"
299 mv "$HOME/$path" "$BACKUP_DIR/$path" && log INFO "Backed up $path"
300 done
301 log INFO "Backups are in $BACKUP_DIR"
302 fi
303
304 stow . --no-folding \
305 && log SUCCESS "Dotfiles stowed successfully" \
306 || log ERROR "Stow failed"
307
308 #################################
309 ## Change default shell to zsh ##
310 #################################
311 log INFO "Changing the default shell to ZSH"
312 if [[ "$SHELL" != "$(command -v zsh)" ]]; then
313 chsh -s "$(command -v zsh)" \
314 && log SUCCESS "Default shell successfully set to zsh" \
315 || log ERROR "Default shell could not be set to zsh"
316 else
317 log INFO "Skipping: zsh is already the default shell"
318 fi
319else
320 log ERROR "Aborted stow, didn't configure or install anything"
321 exit 1
322fi
323
324
325mapfile -t DESKTOP_PKGS < <(read_list desktop)
326ALL_PKGS=(
327 "${DESKTOP_PKGS[@]}"
328 "${SELECTED_PKGS[@]}"
329)
330
331########################
332## Install Everything ##
333########################
334if ((${#ALL_PKGS[@]})); then
335 if confirm "Install all the selected packages?"; then
336 log INFO "Installing selected packages..."
337
338 ## Installing paru if not installed already
339 if ! command -v paru >/dev/null 2>&1; then
340 log INFO "Installing Paru (AUR package manager)"
341 sudo pacman -S --needed --noconfirm base-devel
342 git clone https://aur.archlinux.org/paru.git
343 (cd paru && makepkg -sri)
344 rm -rf paru
345 fi
346
347 if paru -Syu --needed "${ALL_PKGS[@]}"; then
348 INSTALL_STATUS="complete"
349 else
350 INSTALL_STATUS="failed"
351 fi
352 else
353 log WARN "Package installation skipped by user"
354 INSTALL_STATUS="partial"
355 fi
356else
357 log WARN "No packages selected"
358 INSTALL_STATUS="partial"
359fi
360
361
362
363################
364## Setup Keyd ##
365################
366if command -v keyd >/dev/null 2>&1; then
367 if confirm "Configure and enable keyd? "; then
368 log INFO "Copying keyd configuration to /etc/keyd/default.conf"
369 sudo cp "$currentDir/system/etc/keyd/default.conf" /etc/keyd/
370 sudo systemctl enable --now keyd.service \
371 && log SUCCESS "Successfully enabled keyd.service" \
372 || log ERROR "Couldn't enable keyd.service"
373 fi
374fi
375
376
377#########################
378## Enable aurora shell ##
379#########################
380# User unit, stowed to ~/.config/systemd/user. Hyprland starts it at login,
381# enabling it also ties it to graphical-session.target. No --now: no session yet.
382if [[ -f "$HOME/.config/systemd/user/aurora.service" ]]; then
383 if confirm "Enable aurora.service (the desktop shell)?"; then
384 systemctl --user daemon-reload
385 systemctl --user enable aurora.service \
386 && log SUCCESS "Successfully enabled aurora.service" \
387 || log ERROR "Couldn't enable aurora.service (run 'systemctl --user enable aurora' after logging in)"
388 fi
389else
390 log WARN "aurora.service is not stowed, skipping"
391fi
392
393
394####################
395## Final dialogue ##
396####################
397BACKUP_NOTE=""
398[[ -n "$BACKUP_DIR" ]] && BACKUP_NOTE="
399
400Your old conflicting files are in:
401$BACKUP_DIR"
402
403case "$INSTALL_STATUS" in
404 complete)
405 gum style \
406 --border rounded \
407 --border-foreground 42 \
408 --padding "1 2" \
409 --bold \
410 "✔ Installation Complete!
411
412All selected packages were installed successfully.
413You may now reboot the system for all the changes to apply.$BACKUP_NOTE"
414 ;;
415 partial)
416 gum style \
417 --border rounded \
418 --border-foreground 220 \
419 --padding "1 2" \
420 --bold \
421 "⚠ Setup Finished (Partial)
422
423Some steps were skipped by user choice.
424Your system was NOT fully configured.$BACKUP_NOTE"
425 ;;
426 failed)
427 gum style \
428 --border rounded \
429 --border-foreground 196 \
430 --padding "1 2" \
431 --bold \
432 "❌ Installation Failed
433
434One or more steps did not complete successfully.
435Check the logs above.$BACKUP_NOTE"
436 ;;
437 *)
438 gum style --bold "Finished.$BACKUP_NOTE"
439 ;;
440esac