141 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			3.5 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/.* => ~/ and $topic/.(config|local)/* => ~/.\1/
 | 
						|
# 2. run $topic/install the first time
 | 
						|
# 3. run $topic/update on consecutive runs
 | 
						|
 | 
						|
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 ]] || { $@ 2>&1 | 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
 | 
						|
    -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))
 | 
						|
 | 
						|
#
 | 
						|
CWD=$(cd $(dirname $0) && pwd -P)
 | 
						|
ENABLED_DIR="$CWD/.enabled.d"
 | 
						|
pushd $CWD >/dev/null
 | 
						|
for topic in ${@:-$(ls -1 "$ENABLED_DIR" | sed 's%_%/%')}; do
 | 
						|
    [[ -d $topic ]] || continue
 | 
						|
 | 
						|
    echo -e "${green}${topic}${nc}"
 | 
						|
 | 
						|
    tpath="$CWD/$topic"
 | 
						|
    if [[ $link ]]; then
 | 
						|
        # Symlink dotfiles from topics (2 levels deep) + parent (1 level deep)
 | 
						|
        for file in "$tpath"{,../}/.[a-zA-Z]*; do
 | 
						|
            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
 | 
						|
        done
 | 
						|
    fi
 | 
						|
 | 
						|
    # Link topic to .enabled.d
 | 
						|
    linkpath="${ENABLED_DIR}/${topic//\//_}"
 | 
						|
    if [[ -h "$linkpath" ]]; then
 | 
						|
        [[ "$update" && -x ${linkpath}/update ]] && _run "$tpath/update"
 | 
						|
    else
 | 
						|
        # Register topic as 'enabled'
 | 
						|
        _run ln -svf "$tpath" "$linkpath"
 | 
						|
 | 
						|
        # Run install script
 | 
						|
        [[ "$install" && -x ${linkpath}/install ]] && _run "$tpath/install"
 | 
						|
    fi
 | 
						|
done
 | 
						|
popd >/dev/null
 | 
						|
 | 
						|
# vim:set ft=sh:
 |