270 lines
5.5 KiB
Bash
Executable file
270 lines
5.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# TODO check for duplicate lines in bindings
|
|
|
|
set -e
|
|
|
|
newline=$'\n'
|
|
esc=$'\e'
|
|
csi="$esc["
|
|
reset="${csi}0m"
|
|
|
|
bold="${csi}1m"
|
|
dim="${csi}2m"
|
|
|
|
default="${csi}39m"
|
|
red="${csi}31m"
|
|
green="${csi}32m"
|
|
yellow="${csi}33m"
|
|
|
|
|
|
##### STATUS #####
|
|
|
|
|
|
status_buffer=""
|
|
status_source_active=""
|
|
status_count_total=0
|
|
status_count_managed=0
|
|
status_count_unmanaged=0
|
|
status_count_nonexistent=0
|
|
|
|
status_target_begin() {
|
|
status_buffer=""
|
|
status_source_active=""
|
|
}
|
|
|
|
status_target_end() {
|
|
tilde_expanded_target=${1/\~/$HOME}
|
|
|
|
if [ ! -z "$status_source_active" ] ; then
|
|
status_buffer="${bold}${green}*${default} $1${reset}${status_buffer}"
|
|
((status_count_managed=status_count_managed+1))
|
|
else
|
|
if [ -e "$tilde_expanded_target" ] ; then
|
|
status_buffer="${yellow}*${default} $1${status_buffer}"
|
|
((status_count_unmanaged=status_count_unmanaged+1))
|
|
else
|
|
status_buffer="${dim}* $1${reset}${status_buffer}"
|
|
((status_count_nonexistent=status_count_nonexistent+1))
|
|
fi
|
|
fi
|
|
|
|
echo "$status_buffer"
|
|
echo
|
|
|
|
((status_count_total=status_count_total+1))
|
|
}
|
|
|
|
status_target_source() {
|
|
tilde_expanded_target=${1/\~/$HOME}
|
|
|
|
if [ -L "$tilde_expanded_target" ] ; then
|
|
symlink_target=$(readlink "$tilde_expanded_target")
|
|
|
|
if [ "$symlink_target" = "${PWD}/$2" ] ; then
|
|
status_source_active="y"
|
|
status_buffer="${status_buffer}${newline} $2"
|
|
else
|
|
status_buffer="${status_buffer}${newline} ${dim}$2${reset}"
|
|
fi
|
|
else
|
|
status_buffer="${status_buffer}${newline} ${dim}$2${reset}"
|
|
fi
|
|
|
|
if [ ! -e "$2" ] ; then
|
|
status_buffer="${status_buffer} ${bold}${yellow}!${reset}"
|
|
fi
|
|
}
|
|
|
|
status_finished() {
|
|
cat <<EOF
|
|
${bold}${status_count_total}${reset} targets, \
|
|
${bold}${status_count_managed}${reset} managed, \
|
|
${bold}${status_count_unmanaged}${reset} unmanaged, \
|
|
${bold}${status_count_nonexistent}${reset} non-existent
|
|
EOF
|
|
}
|
|
|
|
|
|
##### INSTALL #####
|
|
|
|
|
|
install_target_source() {
|
|
tilde_expanded_target=${1/\~/$HOME}
|
|
|
|
if [ -z "$install_done" ] && [ "$tilde_expanded_target" = "$install_target" ] ; then
|
|
# if no source is provided, select the first option, otherwise
|
|
# check for a match
|
|
if [ -z "$install_source" ] || [ "$install_source" = "$2" ] ; then
|
|
echo "${dim}$ ln -sf ${PWD}/$2 $tilde_expanded_target${reset}"
|
|
ln -sf "${PWD}/$2" "$tilde_expanded_target"
|
|
install_done="y"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
install_finished() {
|
|
if [ -z $install_done ] ; then
|
|
echo "${bold}${red}error${reset}: no suitable target/source combination found."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
|
|
##### PROCESS INTERFACE #####
|
|
|
|
|
|
# start processing a target
|
|
#
|
|
# expects 1 argument: target path
|
|
process_target_begin() {
|
|
case $mode in
|
|
("status")
|
|
status_target_begin $1
|
|
;;
|
|
("install")
|
|
true
|
|
;;
|
|
(*)
|
|
echo "Invalid mode: '$mode'"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# stop processing a target
|
|
#
|
|
# expects 1 argument: target path
|
|
process_target_end() {
|
|
case $mode in
|
|
("status")
|
|
status_target_end "$1"
|
|
;;
|
|
("install")
|
|
true
|
|
;;
|
|
(*)
|
|
echo "Invalid mode: '$mode'"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# process a target and source pair
|
|
#
|
|
# expects 2 argument: target path, source path
|
|
process_target_source() {
|
|
case $mode in
|
|
("status")
|
|
status_target_source "$1" "$2"
|
|
;;
|
|
("install")
|
|
install_target_source "$1" "$2"
|
|
;;
|
|
(*)
|
|
echo "Invalid mode: '$mode'"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
}
|
|
|
|
# finish processing
|
|
#
|
|
# expects no arguments
|
|
process_finished() {
|
|
case $mode in
|
|
("status")
|
|
status_finished
|
|
;;
|
|
("install")
|
|
install_finished
|
|
;;
|
|
(*)
|
|
echo "Invalid mode: '$mode'"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
##### MAIN #####
|
|
|
|
case $1 in
|
|
(""|"status")
|
|
mode="status"
|
|
;;
|
|
("install")
|
|
mode="install"
|
|
|
|
if [ -z "$2" ] || [ "$2" = "--help" ]; then
|
|
echo "usage: manage.sh install [target] (source)"
|
|
exit 1
|
|
fi
|
|
|
|
install_target=$2
|
|
install_source=$3
|
|
|
|
;;
|
|
("help"|"--help")
|
|
if [ -z $2 ] ; then
|
|
cat <<EOF
|
|
usage: manage.sh [command] [options]
|
|
|
|
Commands:
|
|
|
|
status View all dotfiles
|
|
install Install new dotfiles
|
|
EOF
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Unrecognized command: '$1'"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
|
|
bindings_file="bindings"
|
|
|
|
line_nr=1
|
|
target_file=""
|
|
|
|
while read -r line ; do
|
|
case $line in
|
|
("-> "*)
|
|
if [ -z "$target_file" ] ; then
|
|
echo "Parsing error: source given without target at line $line_nr"
|
|
exit 1
|
|
fi
|
|
|
|
source_file=${line#"-> "}
|
|
|
|
process_target_source "$target_file" "$source_file"
|
|
;;
|
|
("")
|
|
if [ ! -z "$target_file" ] ; then
|
|
process_target_end "$target_file"
|
|
fi
|
|
|
|
target_file=""
|
|
;;
|
|
(*)
|
|
target_file="$line"
|
|
|
|
process_target_begin "$target_file"
|
|
;;
|
|
esac
|
|
|
|
# echo $line
|
|
((line_nr=line_nr+1))
|
|
done < "$bindings_file"
|
|
|
|
# process last item
|
|
if [ ! -z "$target_file" ] ; then
|
|
process_target_end "$target_file"
|
|
fi
|
|
|
|
process_finished
|