URI:
       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 "$@"