helm/bootstrap
2017-01-03 03:56:24 -05:00

156 lines
4 KiB
Bash
Executable file

#!/usr/bin/env bash
# My (idempotent) dotfile deployment script.
#
# You pass the directories of "topics" to it to install them. It will:
# 1. symlink $topic/bin/* to ~/.bin/
# 2. symlink $topic/.* => ~/ and $topic/.*/* => ~/.$1/
# 3. run $topic/install the first time
# 4. run $topic/update on consecutive runs
#
# NOTE: Be sure to add ~/.bin to PATH
#
# Options:
# -i Don't run install scripts
# -u Don't run update scripts
# -l Don't symlink dotfiles or bin scripts
# -d Do a dry run (only output commands, no changes)
# -y Overwrite conflicts (no prompts)
# -p Prompt on file conflict (to overwrite)
# -L Refresh links; the same as -ui
# -S Server mode; only install the bare minimum
# -U Update mode; run update scripts only
set -e
source "$(cd $(dirname $0) && pwd -P)/shell/common.sh"
shopt -s nullglob
#
blue="\033[34m"
magenta="\033[35m"
green="\033[32m"
orange="\033[33m"
grey="\033[36m"
red="\033[31m"
nc="\033[0m"
#
_run() {
local cmd="${@//$DOTFILES\//}"
cmd="${cmd//$HOME/~}"
local clr=""
case $cmd in
*~/.bin/) clr="${magenta}" ;;
ln*) clr="" ;;
mkdir*) clr="${blue}" ;;
*) clr="${orange}"
esac
echo -e " $PREFIX$clr$cmd$nc"
[[ $DRYRUN ]] || { $@ | sed 's/^/ => /'; }
}
_link() {
if [[ -f "$2" || ( -d "$2" && -f "$2/${1##*/}" ) ]]; then
if [[ $yes ]]; then
[[ $yes = 1 ]] && choice=y || choice=n
else
read -n 1 -p "? ${1##*/} exists in $2 -- overwrite? [y/n] " choice
echo
fi
case $choice in
y|Y) _run rm -rf "$2"
PREFIX="${red}OVERWRITE:${nc} " _run ln -svf "$1" "$2"
;;
*) PREFIX="${red}ABORTED:${nc} " DRYRUN=1 _run ln -svf "$1" "$2"
;;
esac
else
_run ln -svf "$1" "$2"
fi
}
##
install=1
link=1
update=1
yes=0
while getopts iuldypLSUh opt; do
case $opt in
d) DRYRUN=1 ;;
i) install= ;;
l) link= ;;
p) yes= ;;
u) update= ;;
y) yes=1 ;;
S) SERVER=1 ;;
U) install=
yes=0
;;
L) update=
install=
yes=0
;;
h) cat <<EOL
Usage: $0 [-iuldypLSU] [topic1] [topic2] [...]
-i Don't run install scripts
-u Don't run update scripts
-l Don't symlink dotfiles or bin scripts
-d Do a dry run (only output commands, no changes)
-y Overwrite conflicts (no prompts)
-p Prompt on file conflict (to overwrite)
-L Refresh links; the same as -ui
-S Server mode; only install the bare minimum
-U Update mode; run update scripts only
EOL
exit
;;
*) >&2 echo "Aborted."
exit 1 ;;
esac
done
shift $((OPTIND-1))
#
[[ -d ~/.bin ]] || _run mkdir -p ~/.bin
PATH="$DOTFILES/.bin:$PATH"
for topic in ${@:-$(find "$ENABLED_DIR" -maxdepth 1 -type l)}; do
[[ -d $topic ]] || continue
tpath=$(realpath "$topic")
tname="$(basename $(dirname $tpath))_${tpath##*/}"
echo -e "${green}${tname//_//}${nc}"
# Link binaries
for bin in $tpath/bin/*; do
[[ "$link" && -x "$bin" ]] && _link "$bin" "$HOME/.bin/"
done
# Symlink dotfiles from topic directories (2 levels deep)
if [[ $link ]]; then
for file in "$tpath"/.[a-zA-Z]*; do
if [[ -d $file && "${file##*/}" == .config ]]; then
for subfile in "$file"/*; do
base="$HOME/${file##*/}/"
[[ -d $base ]] || _run mkdir -p "$base"
_link "$subfile" "$base"
done
elif [[ -e $file ]]; then
_link "$file" "$HOME/"
fi
done
fi
# Link topic to .enabled.d
if [[ -h "$ENABLED_DIR/$tname" ]]; then
[[ "$update" && -x $tpath/update ]] && _run "$tpath/update"
else
# Register topic as 'enabled'
_run ln -svf "$tpath" "$ENABLED_DIR/$tname"
# Run install script
[[ "$install" && -x $tpath/install ]] && _run "$tpath/install"
fi
done
# vim:set ft=sh: