2017-02-12 11:41:03 +01:00
|
|
|
#!/usr/bin/env bash
|
2016-12-04 14:16:21 +01:00
|
|
|
|
|
|
|
# Handles dotfiles
|
|
|
|
# Yes there are tons of similar scipts yet I wanted no more nor less than what I needed
|
|
|
|
|
|
|
|
# Config
|
|
|
|
|
|
|
|
if [ -z "$DOTHOME" ]; then
|
|
|
|
DOTHOME="$HOME"
|
|
|
|
fi
|
|
|
|
if [ -z "$DOTREPO" ]; then
|
|
|
|
DOTREPO="$HOME/.dotfiles"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Common functions
|
|
|
|
|
|
|
|
# From http://stackoverflow.com/a/12498485
|
|
|
|
function relativePath {
|
|
|
|
# both $1 and $2 are absolute paths beginning with /
|
|
|
|
# returns relative path to $2/$target from $1/$source
|
|
|
|
source=$1
|
|
|
|
target=$2
|
|
|
|
|
|
|
|
common_part=$source # for now
|
|
|
|
result="" # for now
|
|
|
|
|
|
|
|
while [[ "${target#$common_part}" == "${target}" ]]; do
|
|
|
|
# no match, means that candidate common part is not correct
|
|
|
|
# go up one level (reduce common part)
|
|
|
|
common_part="$(dirname $common_part)"
|
|
|
|
# and record that we went back, with correct / handling
|
|
|
|
if [[ -z $result ]]; then
|
|
|
|
result=".."
|
|
|
|
else
|
|
|
|
result="../$result"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
if [[ $common_part == "/" ]]; then
|
|
|
|
# special case for root (no common path)
|
|
|
|
result="$result/"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# since we now have identified the common part,
|
|
|
|
# compute the non-common part
|
|
|
|
forward_part="${target#$common_part}"
|
|
|
|
|
|
|
|
|
|
|
|
# and now stick all parts together
|
|
|
|
if [[ -n $result ]] && [[ -n $forward_part ]]; then
|
|
|
|
result="$result$forward_part"
|
|
|
|
elif [[ -n $forward_part ]]; then
|
|
|
|
# extra slash removal
|
|
|
|
# result="${forward_part:1}" # Removes the . in the beginning...
|
|
|
|
result="${forward_part#/}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "$result"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Script common functions
|
|
|
|
|
|
|
|
function _dotfiles-install-dir { # dir
|
|
|
|
local dir
|
|
|
|
local absSource
|
|
|
|
local absTarget
|
|
|
|
local relTarget
|
|
|
|
|
|
|
|
dir="${1%/}"
|
|
|
|
dir="${dir#/}"
|
|
|
|
|
2016-12-30 15:27:02 +01:00
|
|
|
ls -A "$DOTREPO/$dir" | while read file; do
|
2016-12-04 14:16:21 +01:00
|
|
|
if [[ -z "$dir" && $(echo $file | grep '^\(\.\|LICENSE\|README\)') ]]; then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
if [[ $(echo $file | grep '^.dfrecur$') ]]; then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -z "$dir" ]; then
|
|
|
|
absSource="$DOTHOME/.$file"
|
|
|
|
absTarget="$DOTREPO/$file"
|
|
|
|
else
|
|
|
|
absSource="$DOTHOME/.$dir/$file"
|
|
|
|
absTarget="$DOTREPO/$dir/$file"
|
|
|
|
fi
|
|
|
|
relTarget="$(relativePath "$DOTHOME/$dir" "$absTarget")"
|
|
|
|
recurIndicator="$absTarget/.dfrecur"
|
|
|
|
|
|
|
|
if [[ -h "$absTarget" ]]; then
|
|
|
|
if [ -e "$absSource" ]; then
|
|
|
|
if [ -h "$absSource" ]; then
|
|
|
|
cmd="cp --no-dereference --force $absTarget $absSource"
|
|
|
|
if [ $DRY_RUN ]; then
|
|
|
|
echo $cmd
|
|
|
|
else
|
|
|
|
yes | $cmd
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "[ERROR] $absSource already exists, but is not a link"
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
cmd="cp --no-dereference --force $absTarget $absSource"
|
|
|
|
if [ $DRY_RUN ]; then
|
|
|
|
echo $cmd
|
|
|
|
else
|
|
|
|
yes | $cmd
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
elif [[ -f "$absTarget" || ( -d $absTarget && ! -f $recurIndicator ) ]]; then
|
|
|
|
if [ -e "$absSource" ]; then
|
|
|
|
if [ -h "$absSource" ]; then
|
|
|
|
cmd="ln --symbolic --no-dereference --force $relTarget $absSource"
|
|
|
|
if [ $DRY_RUN ]; then
|
|
|
|
echo $cmd
|
|
|
|
else
|
|
|
|
$cmd
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "[ERROR] $absSource already exists, but is not a symbolic link"
|
|
|
|
fi
|
|
|
|
else
|
2016-12-05 21:19:58 +01:00
|
|
|
cmd="ln --symbolic --no-dereference $relTarget $absSource"
|
2016-12-04 14:16:21 +01:00
|
|
|
if [ $DRY_RUN ]; then
|
|
|
|
echo $cmd
|
|
|
|
else
|
|
|
|
$cmd
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
elif [[ -d "$absTarget" && -f $recurIndicator ]]; then
|
|
|
|
if [ -e "$absSource" ]; then
|
|
|
|
if [ -d "$absSource" ]; then
|
|
|
|
# echo "Directory $absSource already exists"
|
|
|
|
_dotfiles-install-dir $dir/$file
|
|
|
|
else
|
|
|
|
echo "[ERROR] $absSource already exists, but is not a directory"
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
cmd="mkdir $absSource"
|
|
|
|
if [ $DRY_RUN ]; then
|
|
|
|
echo $cmd
|
|
|
|
else
|
|
|
|
$cmd
|
|
|
|
fi
|
|
|
|
_dotfiles-install-dir $dir/$file
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "[WARNING] Skipped $absTarget"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# Script functions
|
|
|
|
|
2017-02-12 11:41:03 +01:00
|
|
|
function dotfiles_link_help {
|
|
|
|
echo "Usage: $0 link DOTFILE"
|
|
|
|
echo
|
|
|
|
echo "Arguments:"
|
|
|
|
echo " DOTFILE Path to the dotfile"
|
|
|
|
return 0
|
|
|
|
|
|
|
|
}
|
|
|
|
function dotfiles_link { # file
|
|
|
|
if [ -z $1 ]; then
|
|
|
|
dotfiles_link_help
|
|
|
|
return 1
|
|
|
|
fi
|
2016-12-05 21:19:58 +01:00
|
|
|
absSource="$(realpath $1 2> /dev/null)"
|
|
|
|
if [[ $? != 0 || ! -e "$absSource" ]]; then
|
|
|
|
echo "[ERROR] $1: no such file or directory"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
relSource="$(relativePath $DOTHOME $absSource)"
|
|
|
|
|
|
|
|
absTarget="$DOTREPO/$relSource"
|
|
|
|
relTarget="$(relativePath "$DOTHOME/$dir" "$absTarget")"
|
|
|
|
|
|
|
|
if [ -f "$absTarget" ]; then
|
|
|
|
echo "[ERROR/UNIMPLEMENTED] $relSource is already linked to ... something"
|
|
|
|
return 2
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -f "$absSource" ]; then
|
|
|
|
if [ -d "$(dirname "$absTarget")" ]; then
|
|
|
|
cmd="mv $absSource $absTarget"
|
|
|
|
cmd2="ln --symbolic --no-dereference $relTarget $absSource"
|
|
|
|
if [ $DRY_RUN ]; then
|
|
|
|
echo $cmd
|
|
|
|
echo $cmd2
|
|
|
|
else
|
|
|
|
$cmd
|
|
|
|
$cmd2
|
|
|
|
fi
|
|
|
|
|
|
|
|
else
|
|
|
|
echo "[UNIMPLEMENTED] Linking a file in a directory that don't already exists"
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "[UNIMPLEMENTED] Linking things other than a file"
|
|
|
|
return 12
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-02-12 11:41:03 +01:00
|
|
|
function dotfiles_install {
|
2016-12-04 14:16:21 +01:00
|
|
|
_dotfiles-install-dir /
|
|
|
|
}
|
|
|
|
|
2017-02-12 11:41:03 +01:00
|
|
|
function dotfiles_help {
|
|
|
|
command="$1"
|
|
|
|
if [ -n "$command" ]; then
|
|
|
|
if type "dotfiles_${command}_help" &> /dev/null; then
|
|
|
|
shift
|
|
|
|
"dotfiles_${command}_help" "$@"
|
|
|
|
return $?
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
echo "Usage: $0 COMMAND"
|
|
|
|
echo
|
|
|
|
echo "Commands:"
|
|
|
|
echo " install Install dotfiles from repository"
|
|
|
|
echo " link Add dotfile to repository"
|
|
|
|
echo " help Get help with commands"
|
|
|
|
echo
|
|
|
|
echo "Environment variables:"
|
|
|
|
echo " DOTHOME Where to install dotfiles"
|
|
|
|
echo " DOTREPO Where do the dotfiles comes from"
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
# MAIN
|
|
|
|
command="$1"
|
|
|
|
shift
|
|
|
|
if type "dotfiles_$command" &> /dev/null; then
|
|
|
|
"dotfiles_$command" "$@"
|
|
|
|
else
|
|
|
|
dotfiles_help
|
|
|
|
fi
|
|
|
|
|
2016-12-05 21:19:58 +01:00
|
|
|
# TODO dotfiles-{link,unlink,clean,uninstall}, better handling of DRY_RUN (use functions probably), clarify source/target thingy
|
2016-12-04 14:16:21 +01:00
|
|
|
# Link and Unlink should have a clever behavior regarding
|
|
|
|
# recusive folders
|
|
|
|
# Ex : linking config/i3 should make config recursible
|
|
|
|
# Ex : linking config if some files in it are linked should unlink those
|