dotfiles/manage.sh
2024-01-20 23:38:37 +01:00

268 lines
5.4 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
if [ $(readlink $tilde_expanded_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