commit 77c80b256bcf0684865dc53830574fba9226ca02
parent 4cf6b17654dd6209367c3303cce464f106f27f07
Author: Alex Balgavy <a.balgavy@gmail.com>
Date: Sun, 3 Nov 2019 13:16:02 -0500
conf: support unlinking, style changes
Former-commit-id: ebeb704fc1382ab9600cf532604099c74b1d225f
Diffstat:
A | dot.map | | | 56 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | scripts/conf | | | 193 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
2 files changed, 202 insertions(+), 47 deletions(-)
diff --git a/dot.map b/dot.map
@@ -0,0 +1,56 @@
+# Custom stuff I write
+bin: ~/.bin
+scripts: ~/.scripts
+
+# Utilities
+compton: ~/.config/compton
+ctags.d: ~/.ctags.d
+gdb:
+- gdbinit: ~/.gdbinit
+git:
+- gitconfig: ~/.gitconfig
+i3: ~/.config/i3
+irssi: ~/.config/irssi
+karabiner: ~/.config/karabiner
+lf: ~/.config/lf
+newsboat: ~/.newsboat
+oh-my-zsh: ~/.oh-my-zsh
+polybar: ~/.config/polybar
+radio:
+- radio-config: ~/.radio-config
+ranger: ~/.config/ranger
+rtv: ~/.config/rtv
+screen:
+- screenrc: ~/.screenrc
+tmux:
+- tmux.conf: ~/.tmux.conf
+ghci: ~/.ghci
+
+# X server
+xinitrc: ~/.xinitrc
+xprofile: ~/.xprofile
+Xresources: ~/.Xresources
+
+# Emacs config
+emacs:
+- emacs.d: ~/.emacs.d
+- emacs: ~/emacs
+
+# All shell config
+shell:
+- aliases: ~/.aliases
+- functions: ~/.functions
+- secret_env_variables: ~/.secret_env_variables
+- zprofile: ~/.zprfile
+- zshrc: ~/.zshrc
+
+# Vim config
+vim:
+- after: ~/.vim/after
+- autoload: ~/.vim/autoload
+- colors: ~/.vim/colors
+- compiler: ~/.vim/compiler
+- ftdetect: ~/.vim/ftdetect
+- plugin: ~/.vim/plugin
+- ultisnips: ~/.vim/ultisnips
+- vimrc: ~/.vimrc
diff --git a/scripts/conf b/scripts/conf
@@ -1,32 +1,45 @@
#!/usr/bin/env bash
+# TODO: handle multiple nesting levels, convert to posix shell
+
+# Set the dir for your dotfiles, mine comes from the environment
+DOTFILES="${DOTFILES}"
+
die() {
echo "$1" >&2
exit 1
}
-[ -z "$DOTFILES" ] && die '$DOTFILES variable not set.'
-cd "$DOTFILES" || die "Can't read $DOTFILES"
-link() {
+# Don't want $DOTFILES expansion in the message
+# shellcheck disable=SC2016
+[ -z "${DOTFILES}" ] && die '$DOTFILES variable not set.'
+cd "${DOTFILES}" || die "Can't read ${DOTFILES}"
+
+do_link() {
if [ -e "$2" ]; then
- echo "$2 already exists, renaming to $2.bak"
- mv "$2" "$2.bak"
+ if [ -L "$2" ] && [ "$(realpath "$2")" == "$(pwd)/$1" ]; then
+ echo "$2 is already linked to $1."
+ return
+ else
+ echo "$2 already exists, renaming to $2.bak"
+ mv "$2" "$2.bak"
+ fi
fi
ln -svf "$(pwd)/$1" "$2"
}
-# TODO: handle multiple nesting levels, support unlinking
-
-declare -A mappings
parse_mapfile() {
if [ ! -f "$1" ]; then
die "Mapfile $1 does not exist."
fi
+
local nestdir=""
local lineno=1
- homedir="$(echo -n "$HOME" | tr -d '\n\r')"
+ homedir="$(echo -n "${HOME}" | tr -d '\n\r')"
+
while read -r map; do
- if [ ! -z "$map" ] && [[ ! "$map" == "#"* ]]; then
- mapping=($(echo -n "$map" | sed -e 's/^ *- /-/' -e "s:~:$homedir:" | awk -F ': ' '{ print $1 " " $2 }'))
+ if [ -n "${map}" ] && [[ ! "${map}" == "#"* ]]; then
+
+ IFS=" " read -r -a mapping <<< "$(echo -n "${map}" | sed -e 's/^ *- /-/' -e "s:~:${homedir}:" | awk -F ': ' '{ print $1 " " $2 }')"
# Top level items
if [[ ! "${mapping[0]}" == "-"* ]]; then
@@ -36,37 +49,95 @@ parse_mapfile() {
nestdir="${mapping[0]/://}"
else
# one-off mapping
- if [ ! -e "$nestdir${mapping[0]}" ]; then
- die "error in mapfile: $nestdir${mapping[0]} does not exist (line $lineno)"
+ if [ ! -e "${nestdir}${mapping[0]}" ]; then
+ die "error in mapfile: ${nestdir}${mapping[0]} does not exist (line ${lineno})"
fi
- mappings["$nestdir${mapping[0]}"]="${mapping[1]}"
+ mappings["${nestdir}${mapping[0]}"]="${mapping[1]}"
fi
else
- if [ ! -e "$nestdir${mapping[0]/-/}" ]; then
- die "error in mapfile: $nestdir${mapping[0]/-/} does not exist (line $lineno)"
+ if [ ! -e "${nestdir}${mapping[0]/-/}" ]; then
+ die "error in mapfile: ${nestdir}${mapping[0]/-/} does not exist (line ${lineno})"
fi
- mappings["$nestdir${mapping[0]/-/}"]="${mapping[1]}"
+ mappings["${nestdir}${mapping[0]/-/}"]="${mapping[1]}"
fi
fi
((lineno++))
done < <(cat "$1")
}
-parse_mapfile "./dotmap.conf"
+link_all() {
+ for f in "${!mappings[@]}"; do
+ do_link "${f}" "${mappings[${f}]}";
+ done
+}
+unlink_all() {
+ for f in "${!mappings[@]}"; do
+ do_unlink "${mappings[${f}]}"
+ done
+}
+link_specific() {
+ if ( IFS=$'\n'; echo "${mappings[*]}" ) | grep -vqFx "${i}*"; then
+ for f in "${!mappings[@]}"; do
+ if [[ "${f}" == "${i}"* ]]; then
+ do_link "${f}" "${mappings[${f}]}"
+ fi
+ done
+ else
+ die "Error: ${i} not present in mapfile, don't know how to link."
+ fi
+}
+do_unlink() {
+ if [ ! -e "$1" ]; then
+ echo "$1 does not exist."
+ elif [ ! -L "$1" ]; then
+ echo "$1 is not a link, not removing."
+ else
+ echo -n "Removing link "
+ rm -v "$1"
+ fi
+}
+unlink_specific(){
+ if ( IFS=$'\n'; echo "${mappings[*]}" ) | grep -vqFx "${i}*"; then
+ for f in "${!mappings[@]}"; do
+ if [[ "${f}" == "${i}"* ]]; then
+ do_unlink "${mappings[${f}]}"
+ fi
+ done
+ else
+ die "Error: ${i} not present in mapfile, can't unlink."
+ fi
+}
+list_mappings() {
+ for f in "${!mappings[@]}"; do
+ echo "${f} => ${mappings[${f}]}";
+ done
+}
-PARAMS=""
+declare -A mappings
+parse_mapfile "./dot.map"
-list_only=0
+PARAMS=""
+link_mode=0
+unlink_mode=0
while (( "$#" )); do
case "$1" in
-l|--list)
- list_only=1
- shift
+ list_mappings
+ exit 0
;;
-h|--help)
echo "Usage:"
- echo "-l, --list only list maps"
+ echo "conf [options] (link|unlink) [entry1 [entry2...]]"
+ echo
+ echo "Options:"
+ echo " -l, --list only list maps"
+ echo
+ echo "link [entry1 [entry2...]] Link entries according to the map file."
+ echo " With no arguments, links all entries."
+ echo
+ echo "unlink [entry1 [entry2...]] Unlink entries according to the map file."
+ echo " With no arguments, unlinks all entries."
exit 0
;;
--) # end arg parsing
@@ -75,37 +146,65 @@ while (( "$#" )); do
;;
-*) # unsupported flags
echo "Unsupported flag $1" >&2
+ echo 'Run `conf -h` to show usage.'
exit 1
;;
*) # preserve positional arguments
- PARAMS="$PARAMS $1"
+ PARAMS="${PARAMS} $1"
shift
;;
esac
done
-eval set -- "$PARAMS"
-if [ $# -eq 0 ] && [ $list_only -eq 0 ]; then
- read -srp "Link all dotfiles?" -n 1 -s conf
- case "$conf" in
- Y|y)
- echo
- for f in "${!mappings[@]}"; do link "$f" "${mappings[$f]}"; done
- ;;
- esac
-elif [ $list_only -eq 1 ]; then
- for f in "${!mappings[@]}"; do echo "$f => ${mappings[$f]}"; done
+eval set -- "${PARAMS}"
+
+case "$1" in
+ "link")
+ link_mode=1
+ shift
+ ;;
+ "unlink")
+ unlink_mode=1
+ shift
+ ;;
+ *)
+ ;;
+esac
+
+[ "${link_mode}" -eq 0 ] && [ "${unlink_mode}" -eq 0 ] && die 'Arguments required, run `conf -h` to show usage.'
+
+if [ "${link_mode}" -eq 1 ]; then
+ if [ $# -eq 0 ]; then
+ read -srp "Link all dotfiles?" -n 1 -s conf
+ case "${conf}" in
+ Y|y)
+ echo
+ link_all
+ ;;
+ *)
+ ;;
+ esac
+ else
+ for i in "$@"; do
+ link_specific "${i}"
+ done
+ fi
+elif [ "${unlink_mode}" -eq 1 ]; then
+ if [ $# -eq 0 ]; then
+ read -srp "Unlink all dotfiles?" -n 1 -s conf
+ case "${conf}" in
+ Y|y)
+ echo
+ unlink_all
+ ;;
+ *)
+ ;;
+ esac
+ else
+ for i in "$@"; do
+ unlink_specific "${i}"
+ done
+ fi
else
- for i in $@; do
- if ( IFS=$'\n'; echo "${mappings[*]}" ) | grep -vqFx "$i"*; then
- for f in "${!mappings[@]}"; do
- if [[ "$f" == "$i"* ]]; then
- link "$f" "${mappings[$f]}"
- fi
- done
- else
- die "Error: $i not present in mapfile, don't know how to link."
- fi
- done
+ die "Neither link nor unlink mode specified."
fi
-