summaryrefslogtreecommitdiff
path: root/link/lib.sh
diff options
context:
space:
mode:
Diffstat (limited to 'link/lib.sh')
-rw-r--r--link/lib.sh122
1 files changed, 122 insertions, 0 deletions
diff --git a/link/lib.sh b/link/lib.sh
new file mode 100644
index 0000000..1899f00
--- /dev/null
+++ b/link/lib.sh
@@ -0,0 +1,122 @@
+# shellcheck shell=bash
+# shellcheck disable=SC2034 # the paths below are for whichever script sources this
+#
+# Shared by link.sh and the link/*.sh parts: the dry-run flag, colours, link and
+# link_all, and the paths they all use. Source it with the script's own
+# arguments:
+#
+# source "$(dirname "$0")/lib.sh" "$@"
+#
+# Dry run unless the first argument is `yes`.
+#
+# Other repos' link.sh source this file instead of keeping copies, finding it
+# through $DOT_LINK_LIB, which link.sh exports for them. Keep these names and
+# the `yes` convention stable, or change them there as well.
+
+is_dry_run="y"
+if [[ "${1:-}" == "yes" ]]
+then
+ is_dry_run=""
+fi
+
+color() {
+ color_code="$1"
+ shift
+ # Black 0;30 Dark Gray 1;30
+ # Red 0;31 Light Red 1;31
+ # Green 0;32 Light Green 1;32
+ # Brown/Orange 0;33 Yellow 1;33
+ # Blue 0;34 Light Blue 1;34
+ # Purple 0;35 Light Purple 1;35
+ # Cyan 0;36 Light Cyan 1;36
+ # Light Gray 0;37 White 1;37
+ yes_color="\033[${color_code}m"
+ no_color='\033[0m'
+ echo -e "${yes_color}$*${no_color}"
+}
+
+green() {
+ color '0;32' "$@"
+}
+
+yellow() {
+ color '1;33' "$@"
+}
+
+red() {
+ color '0;31' "$@"
+}
+
+# Link up dotfiles
+link() {
+ local target="$1"
+ local link="$2"
+ if [[ -z "$1" ]]
+ then
+ >&2 echo "Error: need valid target"
+ return 1
+ fi
+ if [[ -z "$2" ]]
+ then
+ >&2 echo "Error: need valid link"
+ return 1
+ fi
+ target="$(realpath "${target}")"
+
+ if [[ -n "${is_dry_run}" ]]
+ then
+ local actual
+ actual="$(readlink "$link" || true)"
+ if [[ -n "${actual}" ]] ; then
+ actual="$(realpath "$actual" || true)"
+ fi
+
+ if [[ -L "$link" && "$target" == "$actual" ]]
+ then
+ green "$link already exists and is correct"
+ return
+ elif [[ -e "$link" ]]
+ then
+ if diff "$link" "$target" > /dev/null
+ then
+ yellow "$link already exists and will be deleted first but contents are the same. $target != $actual"
+ else
+ red "$link WILL CHANGE"
+ fi
+ else
+ yellow "$link will be created"
+ fi
+ else
+ mkdir -p "$(dirname "$2")"
+ rm -rf "$2"
+ ln -sf "$1" "$2"
+ fi
+}
+
+link_all() {
+ from="$1"
+ to="$2"
+ # Process substitution rather than a pipe, so `link` runs in this shell and
+ # not a subshell; NUL-delimited so names with spaces survive (SC2044/SC2086).
+ while IFS= read -r -d '' f
+ do
+ link "$f" "$to/$(basename "$f")"
+ done < <(find "$from" -mindepth 1 -maxdepth 1 -print0)
+}
+
+# Run another script with this interface, dry or not as this one is.
+run_link() {
+ if [[ -n "${is_dry_run}" ]]
+ then
+ "$1"
+ else
+ "$1" yes
+ fi
+}
+
+dotfiles_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+config_dir="$dotfiles_dir/config"
+xdg_config_dir="${XDG_CONFIG_HOME:-$HOME/.config}"
+
+# iCloud Drive, on a Mac signed into it; absent everywhere else.
+icloud_dir="$HOME/Library/Mobile Documents/com~apple~CloudDocs"