#!/usr/bin/env sh # this script is compatible with following shells: # ash, dash, bash, zsh VERBOSE="${VERBOSE:-1}" NAME="$0" die() { printf '%s:' "$NAME" printf ' %s' "$@" printf '\n' exit 1 } >&2 backup() { : "${1:?missing argument}" printf '%s\n' "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 argument}" : "${2:?missing argument}" if [ -e "$1" ]; then [ ! "$1" -ef "$2" ] || return 0 if [ -h "$1" ]; then printf '%s\n' "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 argument}" : "${2:?missing argument}" if [ -e "$1" ]; then if [ -h "$1" ]; then [ "$(readlink "$1")" != "$2" ] || return 0 printf '%s\n' "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 argument}" : "${2:?missing argument}" [ -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" -lt 1 ] || printf '\033[34m / \033[0m %s %s\n' "$d1" "$d2" >&2 softlink_pseudo "$d1" "$d2" || exit fi elif [ -f "$d2" ]; then [ "$VERBOSE" -lt 1 ] || printf '\033[34m * \033[0m %s\n' "$d1" >&2 hardlink "$d1" "$d2" || exit else die "i don't know how to pseudo-symlink $d2" fi done || exit } find_new_files() { : "${1:?missing argument}" : "${2:?missing argument}" 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 local ind= [ ! -d "$d1" ] || ind=/ if [ "$VERBOSE" -lt 1 ]; then printf ' + %s%s\n' "$d1" "$ind" >&2 else #printf 'new destination file. consider manually moving it:\n' >&2 printf '\033[32m + \033[0m %s%s\n' "$d1" "$ind" >&2 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 printf '%s\n' '[ ! -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 printf '%s\n' "not removing $d because it contains files" fi done # create instead my preferred directory structure. mkdir -p opt/local/bin src work play