-
Notifications
You must be signed in to change notification settings - Fork 33
/
install.sh
executable file
·440 lines (394 loc) · 17.3 KB
/
install.sh
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
#!/usr/bin/env bash
######################################################################
# 🧰 Lissy93/Dotfiles - All-in-One Install and Setup Script for Unix #
######################################################################
# Fetches latest changes, symlinks files, and installs dependencies #
# Then sets up ZSH, TMUX, Vim as well as OS-specific tools and apps #
# Checks all dependencies are met, and prompts to install if missing #
# For docs and more info, see: https://github.com/lissy93/dotfiles #
# #
# OPTIONS: #
# --auto-yes: Skip all prompts, and auto-accept all changes #
# --no-clear: Don't clear the screen before running #
# #
# ENVIRONMENTAL VARIABLES: #
# DOTFILES_DIR: Where to save dotfiles to (default: ~/.dotfiles) #
# DOTFILES_REPO: Git repo to USE (default: Lissy93/Dotfiles) #
# #
# IMPORTANT: Before running, read through everything very carefully! #
# #
# Licensed under MIT (C) Alicia Sykes 2022 <https://aliciasykes.com> #
######################################################################
# Set variables for reference
PARAMS=$* # User-specified parameters
CURRENT_DIR=$(cd "$(dirname ${BASH_SOURCE[0]})" && pwd)
SYSTEM_TYPE=$(uname -s) # Get system type - Linux / MacOS (Darwin)
PROMPT_TIMEOUT=15 # When user is prompted for input, skip after x seconds
START_TIME=`date +%s` # Start timer
SRC_DIR=$(dirname ${0})
# Dotfiles Source Repo and Destination Directory
REPO_NAME="${REPO_NAME:-Lissy93/Dotfiles}"
DOTFILES_DIR="${DOTFILES_DIR:-${SRC_DIR:-$HOME/.dotfiles}}"
DOTFILES_REPO="${DOTFILES_REPO:-https://github.com/${REPO_NAME}.git}"
# Config Names and Locations
TITLE="🧰 ${REPO_NAME} Setup"
SYMLINK_FILE="${SYMLINK_FILE:-symlinks.yaml}"
DOTBOT_DIR="lib/dotbot"
DOTBOT_BIN="bin/dotbot"
# Color Variables
CYAN_B='\033[1;96m'
YELLOW_B='\033[1;93m'
RED_B='\033[1;31m'
GREEN_B='\033[1;32m'
PLAIN_B='\033[1;37m'
RESET='\033[0m'
GREEN='\033[0;32m'
PURPLE='\033[0;35m'
# Clear the screen
if [[ ! $PARAMS == *"--no-clear"* ]] && [[ ! $PARAMS == *"--help"* ]] ; then
clear
fi
# If set to auto-yes - then don't wait for user reply
if [[ $PARAMS == *"--auto-yes"* ]]; then
PROMPT_TIMEOUT=1
AUTO_YES=true
fi
# Function that prints important text in a banner with colored border
# First param is the text to output, then optional color and padding
make_banner () {
bannerText=$1
lineColor="${2:-$CYAN_B}"
padding="${3:-0}"
titleLen=$(expr ${#bannerText} + 2 + $padding);
lineChar="─"; line=""
for (( i = 0; i < "$titleLen"; ++i )); do line="${line}${lineChar}"; done
banner="${lineColor}╭${line}╮\n│ ${PLAIN_B}${bannerText}${lineColor} │\n╰${line}╯"
echo -e "\n${banner}\n${RESET}"
}
# Explain to the user what changes will be made
make_intro () {
C2="\033[0;35m"
C3="\x1b[2m"
echo -e "${CYAN_B}The seup script will do the following:${RESET}\n"\
"${C2}(1) Pre-Setup Tasls\n"\
" ${C3}- Check that all requirements are met, and system is compatible\n"\
" ${C3}- Sets environmental variables from params, or uses sensible defaults\n"\
" ${C3}- Output welcome message and summary of changes\n"\
"${C2}(2) Setup Dotfiles\n"\
" ${C3}- Clone or update dotfiles from git\n"\
" ${C3}- Symlinks dotfiles to correct locations\n"\
"${C2}(3) Install packages\n"\
" ${C3}- On MacOS, prompt to install Homebrew if not present\n"\
" ${C3}- On MacOS, updates and installs apps liseted in Brewfile\n"\
" ${C3}- On Arch Linux, updates and installs packages via Pacman\n"\
" ${C3}- On Debian Linux, updates and installs packages via apt get\n"\
" ${C3}- On Linux desktop systems, prompt to install desktop apps via Flatpak\n"\
" ${C3}- Checks that OS is up-to-date and critical patches are installed\n"\
"${C2}(4) Configure system\n"\
" ${C3}- Setup Vim, and install / update Vim plugins via Plug\n"\
" ${C3}- Setup Tmux, and install / update Tmux plugins via TPM\n"\
" ${C3}- Setup ZSH, and install / update ZSH plugins via Antigen\n"\
" ${C3}- Apply system settings (via NSDefaults on Mac, dconf on Linux)\n"\
" ${C3}- Apply assets, wallpaper, fonts, screensaver, etc\n"\
"${C2}(5) Finishing Up\n"\
" ${C3}- Refresh current terminal session\n"\
" ${C3}- Print summary of applied changes and time taken\n"\
" ${C3}- Exit with appropriate status code\n\n"\
"${PURPLE}You will be prompted at each stage, before any changes are made.${RESET}\n"\
"${PURPLE}For more info, see GitHub: \033[4;35mhttps://github.com/${REPO_NAME}${RESET}"
}
# Cleanup tasks, run when the script exits
cleanup () {
# Reset tab color and title (iTerm2 only)
echo -e "\033];\007\033]6;1;bg;*;default\a"
# Unset re-used variables
unset PROMPT_TIMEOUT
unset AUTO_YES
# dinosaurs are awesome
echo "🦖"
}
# Checks if a given package is installed
command_exists () {
hash "$1" 2> /dev/null
}
# On error, displays death banner, and terminates app with exit code 1
terminate () {
make_banner "Installation failed. Terminating..." ${RED_B}
exit 1
}
# Checks if command / package (in $1) exists and then shows
# either shows a warning or error, depending if package required ($2)
system_verify () {
if ! command_exists $1; then
if $2; then
echo -e "🚫 ${RED_B}Error:${PLAIN_B} $1 is not installed${RESET}"
terminate
else
echo -e "⚠️ ${YELLOW_B}Warning:${PLAIN_B} $1 is not installed${RESET}"
fi
fi
}
# Shows a desktop notification, on compatible systems ($1 = message)
show_notification () {
if [[ $PARAMS == *"--no-notifications"* ]]; then return; fi
notif_title=$TITLE
notif_logo="${DOTFILES_DIR}/.github/logo.png"
if command_exists terminal-notifier; then
terminal-notifier -group 'dotfiles' -title $notif_title -subtitle $1 \
-message $2 -appIcon $notif_logo -contentImage $notif_logo \
-remove 'ALL' -sound 'Sosumi' &> /dev/null
elif command_exists notify-send; then
notify-send -u normal -t 15000 -i "${notif_logo}" "${notif_title}" "${1}"
fi
}
# Prints welcome banner, verifies that requirements are met
function pre_setup_tasks () {
# Show pretty starting banner
make_banner "${TITLE}" "${CYAN_B}" 1
# Set term title
echo -e "\033];${TITLE}\007\033]6;1;bg;red;brightness;30\a" \
"\033]6;1;bg;green;brightness;235\a\033]6;1;bg;blue;brightness;215\a"
# Print intro, listing what changes will be applied
make_intro
# Confirm that the user would like to proceed
echo -e "\n${CYAN_B}Are you happy to continue? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_start
if [[ ! $ans_start =~ ^[Yy]$ ]] && [[ $AUTO_YES != true ]] ; then
echo -e "\n${PURPLE}No worries, feel free to come back another time."\
"\nTerminating...${RESET}"
make_banner "🚧 Installation Aborted" ${YELLOW_B} 1
exit 0
fi
echo
# If pre-requsite packages not found, prompt to install
if ! command_exists git; then
bash <(curl -s -L 'https://alicia.url.lol/prerequisite-installs') $PARAMS
fi
# Verify required packages are installed
system_verify "git" true
system_verify "zsh" false
system_verify "vim" false
system_verify "nvim" false
system_verify "tmux" false
# If XDG variables arn't yet set, then configure defaults
if [ -z ${XDG_CONFIG_HOME+x} ]; then
echo -e "${YELLOW_B}XDG_CONFIG_HOME is not yet set. Will use ~/.config${RESET}"
export XDG_CONFIG_HOME="${HOME}/.config"
fi
if [ -z ${XDG_DATA_HOME+x} ]; then
echo -e "${YELLOW_B}XDG_DATA_HOME is not yet set. Will use ~/.local/share${RESET}"
export XDG_DATA_HOME="${HOME}/.local/share"
fi
# Ensure dotfiles source directory is set and valid
if [[ ! -d "$SRC_DIR" ]] && [[ ! -d "$DOTFILES_DIR" ]]; then
echo -e "${YELLOW_B}Destination direcory not set,"\
"defaulting to $HOME/.dotfiles\n"\
"${CYAN_B}To specify where you'd like dotfiles to be downloaded to,"\
"set the DOTFILES_DIR environmental variable, and re-run.${RESET}"
DOTFILES_DIR="${HOME}/.dotfiles"
fi
}
# Downloads / updates dotfiles and symlinks them
function setup_dot_files () {
# If dotfiles not yet present, clone the repo
if [[ ! -d "$DOTFILES_DIR" ]]; then
echo -e "${PURPLE}Dotfiles not yet present."\
"Downloading ${REPO_NAME} into ${DOTFILES_DIR}${RESET}"
echo -e "${YELLOW_B}You can change where dotfiles will be saved to,"\
"by setting the DOTFILES_DIR env var${RESET}"
mkdir -p "${DOTFILES_DIR}" && \
git clone --recursive ${DOTFILES_REPO} ${DOTFILES_DIR} && \
cd "${DOTFILES_DIR}"
else # Dotfiles already downloaded, just fetch latest changes
echo -e "${PURPLE}Pulling changes from ${REPO_NAME} into ${DOTFILES_DIR}${RESET}"
cd "${DOTFILES_DIR}" && \
git pull origin master && \
echo -e "${PURPLE}Updating submodules${RESET}" && \
git submodule update --recursive --remote --init
fi
# If git clone / pull failed, then exit with error
if ! test "$?" -eq 0; then
echo -e >&2 "${RED_B}Failed to fetch dotfiles from git${RESET}"
terminate
fi
# Set up symlinks with dotbot
echo -e "${PURPLE}Setting up Symlinks${RESET}"
cd "${DOTFILES_DIR}"
git -C "${DOTBOT_DIR}" submodule sync --quiet --recursive
git submodule update --init --recursive "${DOTBOT_DIR}"
chmod +x lib/dotbot/bin/dotbot
"${DOTFILES_DIR}/${DOTBOT_DIR}/${DOTBOT_BIN}" -d "${DOTFILES_DIR}" -c "${SYMLINK_FILE}" "${@}"
}
# Applies application-specific preferences, and runs some setup tasks
function apply_preferences () {
# If ZSH not the default shell, ask user if they'd like to set it
if [[ $SHELL != *"zsh"* ]] && command_exists zsh; then
echo -e "\n${CYAN_B}Would you like to set ZSH as your default shell? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_zsh
if [[ $ans_zsh =~ ^[Yy]$ ]] || [[ $AUTO_YES = true ]] ; then
echo -e "${PURPLE}Setting ZSH as default shell${RESET}"
chsh -s $(which zsh) $USER
fi
fi
# Prompt user to update ZSH, Tmux and Vim plugins, then reload each
echo -e "\n${CYAN_B}Would you like to install / update ZSH, Tmux and Vim plugins? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_cliplugins
if [[ $ans_cliplugins =~ ^[Yy]$ ]] || [[ $AUTO_YES = true ]] ; then
# Install / update vim plugins with Plug
echo -e "\n${PURPLE}Installing Vim Plugins${RESET}"
vim +PlugInstall +qall
# Install / update Tmux plugins with TPM
echo -e "${PURPLE}Installing TMUX Plugins${RESET}"
chmod ug+x "${XDG_DATA_HOME}/tmux/tpm"
sh "${TMUX_PLUGIN_MANAGER_PATH}/tpm/bin/install_plugins"
sh "${XDG_DATA_HOME}/tmux/plugins/tpm/bin/install_plugins"
# Install / update ZSH plugins with Antigen
echo -e "${PURPLE}Installing ZSH Plugins${RESET}"
/bin/zsh -i -c "antigen update && antigen-apply"
fi
# Apply general system, app and OS security preferences (prompt user first)
echo -e "\n${CYAN_B}Would you like to apply system preferences? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_syspref
if [[ $ans_syspref =~ ^[Yy]$ ]] || [[ $AUTO_YES = true ]]; then
if [ "$SYSTEM_TYPE" = "Darwin" ]; then
echo -e "\n${PURPLE}Applying MacOS system preferences,\
ensure you've understood before proceeding${RESET}\n"
macos_settings_dir="$DOTFILES_DIR/scripts/macos-setup"
for macScript in "macos-security.sh" "macos-preferences.sh" "macos-apps.sh"; do
chmod +x $macos_settings_dir/$macScript && \
$macos_settings_dir/$macScript --quick-exit --yes-to-all
done
else
echo -e "\n${PURPLE}Applying preferences to GNOME apps, ensure you've understood before proceeding${RESET}\n"
dconf_script="$DOTFILES_DIR/scripts/linux/dconf-prefs.sh"
chmod +x $dconf_script && $dconf_script
fi
fi
}
# Setup Brew, install / update packages, organize launchpad and checks for macOS updates
function intall_macos_packages () {
# Homebrew not installed, ask user if they'd like to download it now
if ! command_exists brew; then
echo -e "\n${CYAN_B}Would you like to install Homebrew? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_homebrewins
if [[ $ans_homebrewins =~ ^[Yy]$ ]] || [[ $AUTO_YES = true ]] ; then
echo -en "🍺 ${PURPLE}Installing Homebrew...${RESET}\n"
brew_url='https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh'
/bin/bash -c "$(curl -fsSL $brew_url)"
export PATH=/opt/homebrew/bin:$PATH
fi
fi
# Update / Install the Homebrew packages in ~/.Brewfile
if command_exists brew && [ -f "$DOTFILES_DIR/scripts/installs/Brewfile" ]; then
echo -e "\n${PURPLE}Updating homebrew and packages...${RESET}"
brew update # Update Brew to latest version
brew upgrade # Upgrade all installed casks
brew bundle --global --file $HOME/.Brewfile # Install all listed Brew apps
brew cleanup # Remove stale lock files and outdated downloads
killall Finder # Restart finder (required for some apps)
else
echo -e "${PURPLE}Skipping Homebrew as requirements not met${RESET}"
fi
# Restore launchpad structure with lporg
launchpad_layout="${DOTFILES_DIR}/config/macos/launchpad.yml"
if command_exists lporg && [ -f $launchpad_layout ]; then
echo -e "\n${CYAN_B}Would you like to restore launchpad layout? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_restorelayout
if [[ $ans_restorelayout =~ ^[Yy]$ ]] || [[ $AUTO_YES = true ]] ; then
echo -e "${PURPLE}Restoring Launchpad Layout...${RESET}"
yes "" | lporg load $launchpad_layout
fi
fi
# Check for MacOS software updates, and ask user if they'd like to install
echo -e "\n${CYAN_B}Would you like to check for OX X system updates? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_macoscheck
if [[ $ans_macoscheck =~ ^[Yy]$ ]] || [[ $AUTO_YES = true ]] ; then
echo -e "${PURPLE}Checking for software updates...${RESET}"
pending_updates=$(softwareupdate -l 2>&1)
if [[ ! $pending_updates == *"No new software available."* ]]; then
echo -e "${PURPLE}A new version of Mac OS is availbile${RESET}"
echo -e "${CYAN_B}Would you like to update to the latest version of MacOS? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_macosupdate
if [[ $ans_macosupdate =~ ^[Yy]$ ]] || [[ $AUTO_YES = true ]]; then
echo -e "${PURPLE}Updating MacOS${RESET}"
softwareupdate -i -a
fi
else
echo -e "${GREEN}System is up-to-date."\
"Running $(sw_vers -productName) version $(sw_vers -productVersion)${RESET}"
fi
fi
}
# Based on system type, uses appropriate package manager to install / updates apps
function install_packages () {
echo -e "\n${CYAN_B}Would you like to install / update system packages? (y/N)${RESET}"
read -t $PROMPT_TIMEOUT -n 1 -r ans_syspackages
if [[ ! $ans_syspackages =~ ^[Yy]$ ]] && [[ $AUTO_YES != true ]] ; then
echo -e "\n${PURPLE}Skipping package installs${RESET}"
return
fi
if [ "$SYSTEM_TYPE" = "Darwin" ]; then
# Mac OS
intall_macos_packages
elif [ -f "/etc/arch-release" ]; then
# Arch Linux
arch_pkg_install_script="${DOTFILES_DIR}/scripts/installs/arch-pacman.sh"
chmod +x $arch_pkg_install_script
$arch_pkg_install_script $PARAMS
elif [ -f "/etc/debian_version" ]; then
# Debian / Ubuntu
debian_pkg_install_script="${DOTFILES_DIR}/scripts/installs/debian-apt.sh"
chmod +x $debian_pkg_install_script
$debian_pkg_install_script $PARAMS
fi
# If running in Linux desktop mode, prompt to install desktop apps via Flatpak
flatpak_script="${DOTFILES_DIR}/scripts/installs/flatpak.sh"
if [[ $SYSTEM_TYPE == "Linux" ]] && [ ! -z $XDG_CURRENT_DESKTOP ] && [ -f $flatpak_script ]; then
chmod +x $flatpak_script
$flatpak_script $PARAMS
fi
}
# Updates current session, and outputs summary
function finishing_up () {
# Update source to ZSH entry point
source "${HOME}/.zshenv"
# Calculate time taken
total_time=$((`date +%s`-START_TIME))
if [[ $total_time -gt 60 ]]; then
total_time="$(($total_time/60)) minutes"
else
total_time="${total_time} seconds"
fi
# Print success msg and pretty picture
make_banner "✨ Dotfiles configured succesfully in $total_time" ${GREEN_B} 1
echo -e "\033[0;92m .--.\n |o_o |\n |:_/ |\n // \
\ \\ \n (| | ) \n /'\_ _/\`\\ \n \\___)=(___/\n"
# Refresh ZSH sesssion
SKIP_WELCOME=true || exec zsh
# Show popup
if command_exists terminal-notifier; then
terminal-notifier -group 'dotfiles' -title $TITLE -subtitle 'All Tasks Complete' \
-message "Your dotfiles are now configured and ready to use 🥳" \
-appIcon ./.github/logo.png -contentImage ./.github/logo.png \
-remove 'ALL' -sound 'Sosumi' &> /dev/null
fi
# Show press any key to exit
echo -e "${CYAN_B}Press any key to exit.${RESET}\n"
read -t $PROMPT_TIMEOUT -n 1 -s
# Bye
exit 0
}
# Trigger cleanup on exit
trap cleanup EXIT
# If --help flag passed in, just show the help menu
if [[ $PARAMS == *"--help"* ]]; then
make_intro
exit 0
fi
# Let's Begin!
pre_setup_tasks # Print start message, and check requirements are met
setup_dot_files # Clone / update dotfiles, and create the symlinks
install_packages # Prompt to install / update OS-specific packages
apply_preferences # Apply settings for individual applications
finishing_up # Refresh current session, print summary and exit
# All done :)