Krolyxon
Commit 2495d96

Branches

Refs →

aurorainstall.sh

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