#!/usr/bin/env sh # this script is compatible with following shells: # dash, bash, zsh VERBOSE=1 NAME="$0" [ -n "$ZSH_VERSION" -o -n "$BASH" ] || VERBOSE=0 # no colors for you note() { local IFS=" " printf "%s\n" "$*" } warn() { note "$@" >&2 } die() { warn "$NAME:" "$@" exit 1 } backup() { : "${1:?missing arugment}" note "backing up $1" mkdir -p "${backup_dir:?backup_dir unset}/$(dirname "$1")" [ ! -e "$backup_dir/$1" ] || die "backup already exists" mv "$1" "$backup_dir/$1" } hardlink() { : "${1:?missing arugment}" : "${2:?missing arugment}" if [ -e "$1" ]; then [ ! "$1" -ef "$2" ] || return 0 if [ -h "$1" ]; then note "removing symbolic link $1" rm "$1" || die 'failed to remove symbolic link' fi if [ -s "$1" ]; then backup "$1" || die "$1 already exists" fi fi ln "$2" "$1" || die "failed to hardlink $1" } softlink_nix() { : "${1:?missing arugment}" : "${2:?missing arugment}" if [ -e "$1" ]; then if [ -h "$1" ]; then [ "$(readlink "$1")" != "$2" ] || return 0 note "removing symbolic link $1" rm "$1" || die 'failed to remove symbolic link' else die "$1 already exists and is not a symbolic link" fi fi ln -s "$2" "$1" || die "failed to symlink $1" } list_files() { find "${1:-.}" -maxdepth 1 -printf "%P\n" | while read -r f; do [ "${#f}" -gt 0 ] || continue printf "%s\n" "$f" done } softlink_pseudo() { : "${1:?missing arugment}" : "${2:?missing arugment}" [ -d "$2" ] || die "$1 is not a directory to softlink" [ -d "$1" ] || mkdir "$1" || die "failed to mkdir $1" list_files "$2" | while read -r f; do local d1="$1/$f" local d2="$2/$f" if [ -d "$d2" ]; then if [ "$d1" != ".vim/bundle" ]; then # buggy on Windows [ "${VERBOSE:-0}" -lt 1 ] || warn $'\e[34m / \e[0m' "$d1 $d2" softlink_pseudo "$d1" "$d2" || exit $? fi elif [ -f "$d2" ]; then [ "${VERBOSE:-0}" -lt 1 ] || warn $'\e[34m * \e[0m' "$d1" hardlink "$d1" "$d2" || exit $? else die "i don't know how to pseudo-symlink $d2" fi done || exit $? } find_new_files() { : "${1:?missing arugment}" list_files "$1" | while read -r f; do local d1="$1/$f" local d2="$2/$f" [ "$d1" != ".vim/.netrwhist" ] || continue [ "$d1" != ".vim/backup" ] || continue [ "$d1" != ".vim/bundle" ] || continue [ "$d1" != ".vim/swp" ] || continue [ "$d1" != ".vim/undo" ] || continue if [ -d "$d2" ]; then find_new_files "$d1" "$d2" elif [ ! "$d1" -ef "$d2" ]; then if [ "${VERBOSE:-0}" -lt 1 ]; then warn " + $d1" else #warn "new destination file. consider manually moving it:" warn $'\e[32m + \e[0m' "$d1" fi fi done } softlink() { if [ -n "$MSYSTEM" ]; then # MSYS2 does not have nor emulate symbolic links. softlink_pseudo "$@" find_new_files "$@" # to make up for git status not seeing new files else softlink_nix "$@" fi } which readlink >/dev/null || die 'failed sanity check (check your $PATH)' rc="$(readlink -f "$(dirname "$NAME")" )" [ -d "$rc" ] || die 'failed to determine rc directory' cd "${HOME:?HOME variable empty or unset}" || die 'failed to change directory' backup_dir="$rc/backup-$(date -u '+%s')" [ ! -d "$backup_dir" ] || die 'backup directory already exists' for f in .bashrc .zshrc .-shrc .prezto-compinit .ls_colors \ .vimrc .inputrc .Xresources .screenrc .tmux.conf; do hardlink "$f" "$rc/home/${f#.}" done for d in sh .vim .mpv; do softlink "$d" "$rc/${d#.}" done # ensure that .bashrc gets executed if [ ! -e .bash_profile ] || ! grep -qF .bashrc .bash_profile; then echo >> .bash_profile echo '[ ! -f ~/.bashrc ] || . ~/.bashrc' >> .bash_profile fi is_empty() { local f="${1:?is_empty requires an argument}" find "$f" -type f | while read -r f; do return 1 done || return 1 # just in case pipes mess things up return 0 } # delete any directory structure that may have been included with the OS. # note that i'm careful not to delete them if they contain even a single file, # but you might still want to remove this if you're adapting my install script. for d in Desktop Documents Downloads Music Pictures Public Templates Video Videos; do [ -d "$d" ] || continue if is_empty "$d"; then rm -r "$d" # doesn't really matter if it fails else note "not removing $d because it contains files" fi done # create instead my preferred directory structure. mkdir -p opt/local/bin src work play