bin: Add stash as portable stow alternative - dotfiles - arsenal of config files, ready to be cloned in new (virtual) machines.
HTML git clone git://git.drkhsh.at/dotfiles.git
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
---
DIR commit a59202d60fa6d3d4b631238bb3d5e22bb6950bfb
DIR parent e62931a8be2175336381a5c8d874d46c7b5556f8
HTML Author: drkhsh <me@drkhsh.at>
Date: Wed, 1 Feb 2023 23:08:21 +0100
bin: Add stash as portable stow alternative
https://github.com/shawnohare/stash/
Diffstat:
A bin/stash | 131 +++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+), 0 deletions(-)
---
DIR diff --git a/bin/stash b/bin/stash
@@ -0,0 +1,131 @@
+#!/usr/bin/env sh
+# Copyright (c) 2018 Shawn O'Hare
+# https://github.com/shawnohare/stash
+
+set -e
+
+usage() {
+ cat <<EOF
+Usage:
+ stash [-Dfv] [-t target] dir ...
+ stash -h
+ stash -V
+
+OPTIONS:
+ -t target
+ Specify target directory to link into. Defaults to $STASH_TARGET or parent.
+ -f Force the creation or removal of links from source to target.
+ -D Delete target links. If -f is set, also remove target files.
+ -v VERBOSE messages. Silent by default.
+ -V Print version number.
+ -h Display this this usage message.
+EOF
+}
+
+# Link a src dir $1 to target $2
+stash() {
+ cd "$1"
+
+ # Copy source directory structure to target.
+ # First, attempt to removing broken symlinked dirs.
+ find . -type d | while read -r dir; do
+ dir="$2/${dir}"
+ [ -L "${dir}" ] && [ ! -e "${dir}" ] && rm "${dir}"
+ mkdir -p "${dir}"
+ done
+
+ # link each source file to the target dir
+ # We could find against full path but then we have to remove the prefix.
+ find . -type f | while read -r path; do
+
+ path="${path#??}"
+ src="$1/${path}"
+ tar="$2/${path}"
+
+ # - Only stash when the target file (or link) does not exist.
+ if [ "${FORCE}" ] || [ ! -f "${tar}" ]; then
+ [ "${VERBOSE}" ] && printf "stash: Linking ${src} -> ${tar}\n"
+ ln -f -s "${src}" "${tar}"
+ fi
+ done
+}
+
+# unlink a src dir $1 to target $2
+unstash() {
+ cd "$1"
+
+ # (un)stash each source file.
+ # We could find against full path but then we have to remove the prefix.
+ find . -type f | while read -r path; do
+ # src="$1/${path}"
+ tar="$2/${path#??}"
+
+ if [ "${FORCE}" ] || [ -L "${tar}" ]; then
+ [ "${VERBOSE}" ] && printf "stash: Unlinking ${tar}\n"
+ rm -f "${tar}"
+ fi
+ done
+
+ # Remove empty dirs in the source.
+ find . -depth -type d | while read -r dir; do
+ dir="$2/${dir#??}"
+ if [ -n "$(find "${dir}" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
+ printf "stash: Removing empty target ${dir}/\n"
+ rmdir "${dir}"
+ fi
+ done
+}
+
+main() {
+ while getopts "DfhvVt:" opt; do
+ case "${opt}" in
+ D)
+ cmd="unstash"
+ ;;
+ f)
+ FORCE=1
+ ;;
+ v)
+ VERBOSE=1
+ ;;
+ V)
+ printf "stash: version 1.1.3\n"
+ exit
+ ;;
+ t)
+ target="${OPTARG}"
+ ;;
+ h)
+ usage
+ exit
+ ;;
+ \?)
+ usage
+ exit 1
+ ;;
+ esac
+ done
+
+ shift $((OPTIND - 1))
+
+ if [ -z "$1" ]; then
+ printf "stash: No source dirs specified.\nTry 'stash -h' for help.\n"
+ exit 1
+ fi
+
+ cmd="${cmd:-stash}"
+ target="${target:-${STASH_TARGET:-$(dirname $(pwd))}}"
+
+ # Check if target is relative relative path (remove shortest prefix /)
+ if [ "${target#/}" = "${target}" ]; then
+ target="$(pwd)/${target}"
+ fi
+
+ for dir in "$@"; do
+ [ "${dir#/}" = "${dir}" ] && dir="$(pwd)/${dir}"
+ ${cmd} "${dir}" "${target}"
+ done
+
+}
+
+main "$@"