#!/usr/bin/env bash if [ -z "$(which realpath)" ]; then realpath() { rpath=$1 if [ "${rpath[0]}" == "/" ]; then echo $rpath; elif [ "${rpath:0:1}" == "~" ]; then echo $HOME/${rpath:2} elif [ "${rpath:0:2}" == ".." ]; then echo $(dirname $(pwd))/${rpath:3} elif [ "${rpath:0:1}" == "." ]; then echo $(pwd)/${rpath:2} else echo $(pwd)/$rpath fi } fi stow() { local stowrepo=$1 local stowtarget=$2 [ "$VERBOSE" -gt 1 ] && echo "Entering $stowrepo..." local files=() while read line; do if [ "$line" != "." -a "$line" != ".." ]; then files+=("$line") fi done < <(ls -a $stowrepo) [ "$VERBOSE" -gt 1 ] && echo "Filelist: ${files[@]}" for file in "${files[@]}"; do local file=$(basename "$file") local ctarget="$stowtarget/$file" local csource="$stowrepo/$file" if [ -e "$ctarget" ]; then if [ -L "$ctarget" -a "$(readlink -f "$ctarget")" == "$(realpath "$csource")" ]; then # Link already exists. Skip [ $VERBOSE -gt 0 ] && echo "Skipping $ctarget..." elif [ ! -L "$ctarget" -a -d "$ctarget" -a -d "$csource" ]; then # Dictionary exists. Enter stow "$csource" "$ctarget" else # No can do. echo "Aborting. $ctarget exists, but is not owned by dotstow"; exit 1 fi else if [ "$SIMULATE" -gt 0 ] || ln -s "$(realpath "$csource")" "$ctarget"; then [ $VERBOSE -gt 0 ] && echo "Linking $ctarget to $csource" else echo "Could not link $ctarget to $csource"; exit 1 fi fi done [ "$VERBOSE" -gt 1 ] && echo "Leaving $stowrepo..." } destow() { local stowrepo=$1 local stowtarget=$2 [ "$VERBOSE" -gt 1 ] && echo "Entering $stowrepo..." local files=() while read line; do if [ "$line" != "." -a "$line" != ".." ]; then files+=("$line") fi done < <(ls -a $stowrepo) [ "$VERBOSE" -gt 1 ] && echo "Filelist: ${files[@]}" for file in "${files[@]}"; do local file=$(basename "$file") local ctarget="$stowtarget/$file" local csource="$stowrepo/$file" if [ ! -e "$ctarget" ]; then # Target doesn't exists. skip [ $VERBOSE -gt 0 ] && echo "$ctarget does not exist. Skipping..." elif [ ! -L "$ctarget" ]; then if [ -d "$ctarget" -a -d "$csource" ]; then destow "$csource" "$ctarget" else echo "$ctarget exists, but is not owned by dotstow (Not a link)"; exit 1 fi elif [ "$(readlink -f "$ctarget")" != "$(realpath "$csource")" ]; then [ "$VERBOSE" -gt 0 ] && echo "$(readlink -f "$ctarget")" != "$(realpath "$csource")" echo "$ctarget exists, but is not owned by dotstow (Wrong link)"; exit 1 else if [ "$SIMULATE" -gt 0 ] || rm -f "$ctarget"; then [ $VERBOSE -gt 0 ] && echo "Unlinking $ctarget" else echo "Could not unlink $ctarget"; exit 1 fi fi done [ "$VERBOSE" -gt 1 ] && echo "Leaving $stowrepo..." } restow() { destow "$1" "$2" stow "$1" "$2" } TARGET="$HOME" VERBOSE=0 REPO="$(dirname $0)" COMMAND=stow HELP=0 SIMULATE=0 while getopts DSRvhnt: opt; do case $opt in D) COMMAND=destow ;; S) COMMAND=stow ;; R) COMMAND=restow ;; t) TARGET="$OPTARG" ;; v) let VERBOSE++ ;; h) HELP=1 ;; n) SIMULATE=1 ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG required an argument." >&2 ;; esac done shift $[ $OPTIND-1 ] TARGET=${TARGET/%\//} # Remove trailing slashes if [ "$HELP" -eq 1 -o "${#@}" -eq 0 ]; then echo -e "Usage: ./dotstow.sh [-DSRvhn] [-t target] stows..." echo -e "\t-D: Destow" echo -e "\t-S: Stow" echo -e "\t-R: Restow" echo -e "\t-t: target folder (default ~)" echo -e "\t-v: verbose" echo -e "\t-h: show this help" echo -e "\t-n: simulated/dry-run" echo -e "\tstows: stow folders relative to dotstow.sh" fi for stow in $@; do if [ ! -d "$REPO/$stow" ]; then echo "Stow $stow not found." >&2 exit 2 fi $COMMAND "$REPO/$stow" "$TARGET" done [ "$SIMULATE" -gt 0 ] && echo "Warning: Simulated. No actual changes to the filesystem have been done."