#!/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 } _linkall() { local file="$1" if [[ -d "$file" && "${file##*/}" == .@(config|local) ]]; 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 } ## 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 <&2 echo "Aborted." exit 1 ;; esac done shift $((OPTIND-1)) # [[ -d ~/.bin ]] || _run mkdir -p ~/.bin PATH="$DOTFILES/.bin:$PATH" CWD=$(cd $(dirname $0) && pwd -P) for topic in ${@:-$(find "$ENABLED_DIR" -maxdepth 1 -type l)}; do [[ -d $topic ]] || continue tpath="$CWD/$topic" tparentpath="$(dirname $tpath)" tname="${tparentpath##*/}_${tpath##*/}" echo -e "${green}${tname//_//}${nc}" # Link binaries for bin in $tpath/bin/*; do [[ "$link" && -x "$bin" ]] && _link "$bin" "$HOME/.bin/" done if [[ $link ]]; then # Symlink dotfiles from topic parent directory for file in "$tparentpath"/.[a-zA-Z]*; do _linkall "$file" done # Symlink dotfiles from topic directories (2 levels deep) for file in "$tpath"/.[a-zA-Z]*; do _linkall "$file" done fi # Link topic to .enabled.d linkpath="${ENABLED_DIR}/${tpath##*/}" if [[ -h "$linkpath" ]]; then [[ "$update" && -x ${linkpath}/update ]] && _run "$linkpath/update" else # Register topic as 'enabled' (( $# > 0 )) && _run ln -svf "$tpath" "$ENABLED_DIR/$tname" # Run install script [[ "$install" && -x $tpath/install ]] && _run "$tpath/install" fi done # vim:set ft=sh: