From 31e73fa899e566bd692ec76c2d450f4ec36aa3c8 Mon Sep 17 00:00:00 2001 From: Jason Swank Date: Fri, 2 Jun 2023 11:38:03 -0400 Subject: [PATCH] use bash impl of stow --- install | 13 --- install.sh | 7 ++ stow.sh | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 13 deletions(-) delete mode 100755 install create mode 100755 install.sh create mode 100755 stow.sh diff --git a/install b/install deleted file mode 100755 index 68ccc5e..0000000 --- a/install +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# -# Install my dotfiles. -# - -which stow >/dev/null 2>&1 -if [ $? -ne 0 ]; then - echo "stow is not installed" >&2 - exit 1 -fi - -rm $HOME/.zshrc $HOME/.profile -ls -d */ | tr -d / | xargs stow -t $HOME -R diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..4e572c5 --- /dev/null +++ b/install.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# +# Install my dotfiles. +# + +rm $HOME/.zshrc $HOME/.profile +ls -d */ | tr -d / | xargs ./stow.sh -t $HOME -R diff --git a/stow.sh b/stow.sh new file mode 100755 index 0000000..8bddbd7 --- /dev/null +++ b/stow.sh @@ -0,0 +1,226 @@ +#!/usr/bin/env bash + +# From: github.com/mikepqr/stowsh +# Author: Mike Lee Williams +# License: GPL3 + +_runcommands() { + if [[ $DRYRUN == 1 ]] || [[ $VERBOSE -gt 1 ]]; then + echo "$@" + fi + if [[ $DRYRUN != 1 ]]; then + eval "$@" + fi +} + +echoerr() { + printf "%s\n" "$*" >&2 +} + +deperr() { + echoerr "stowsh requires $1" +} + +isgnu() { + if $1 --version >/dev/null 2>&1; then + return 1 + else + return 0 + fi +} + +stowsh_setpaths() { + if command -v grealpath >/dev/null 2>&1; then + rpcmd="grealpath" + elif command -v realpath >/dev/null 2>&1; then + rpcmd="realpath" + else + deperr "GNU coreutils" + return 1 + fi + if isgnu $rpcmd; then + deperr "GNU coreutils" + return 1 + fi + if command -v gfind >/dev/null 2>&1; then + findcmd="gfind" + elif command -v find >/dev/null 2>&1; then + findcmd="find" + else + deperr "GNU findutils" + return 1 + fi + if isgnu $findcmd; then + deperr "GNU findutils" + return 1 + fi + if [[ "${USEGIT}" -eq 1 ]]; then + flist="list_git_files" + else + flist="list_files" + fi +} + +list_files() { + if [[ "$1" == "-d" ]]; then + $findcmd . -mindepth 1 -type d -printf "%P\0" + else + $findcmd . -type f -printf "%P\0" -or -type l -printf "%P\0" + fi +} + +list_git_files() { + gitfiles=($(git ls-files)) + if [[ "${#gitfiles[@]}" == 0 ]]; then return; fi + + if [[ "$1" == "-d" ]]; then + printf "%s\n" "${gitfiles[@]}" | + xargs -n1 dirname | + sort | uniq | + sed '/^\.$/d' | + tr '\n' '\0' + else + printf "%s\0" "${gitfiles[@]}" + fi +} + +stowsh_install() { + stowsh_setpaths || return 1 + local pkg=$1 + local target + target=$("$rpcmd" "${2-$PWD}") + local commands=() + + cd "$pkg" || return 1 + + mkdir -p "$target" + while IFS= read -r -d '' d; do + commands+=("mkdir -p '$target/$d'") + done < <($flist -d) + + while IFS= read -r -d '' f; do + local targetf="$target/$f" + local thisdir + thisdir=$(dirname "$targetf") + local relative + relative=$($rpcmd "$f" --relative-to="$thisdir" --canonicalize-missing) + if [[ ! -f "$targetf" ]]; then + commands+=("ln -s '$relative' '$targetf'") + else + echoerr "$targetf already exists." + if [[ ! $SKIP -eq 1 ]]; then + echoerr "Aborting. Rerun with the -s flag to skip errors." + return 1 + fi + fi + done < <($flist) + + for cmd in "${commands[@]}"; do + _runcommands "$cmd" + done +} + +stowsh_uninstall() { + stowsh_setpaths || return 1 + local pkg=$1 + local target + target=$("$rpcmd" "${2-$PWD}") + local commands=() + + cd "$pkg" || return 1 + + while IFS= read -r -d '' f; do + local targetf="$target/$f" + if [[ $($rpcmd "$targetf") == $($rpcmd "$f") ]]; then + commands+=("rm '$targetf'") + elif [[ -f "$targetf" ]]; then + echoerr "$targetf does not point to to $($rpcmd "$f")." + if [[ ! $SKIP -eq 1 ]]; then + echoerr "Aborting. Rerun with the -s flag to skip errors." + return 1 + fi + elif [[ ! -f "$targetf" ]]; then + echoerr "$targetf does not exist. Nothing to do." + if [[ ! $SKIP -eq 1 ]]; then + echoerr "Aborting. Rerun with the -s flag to skip errors." + return 1 + fi + fi + done < <($flist) + + while IFS= read -r -d '' d; do + commands+=("[[ -d '$target/$d' ]] && $findcmd '$target/$d' -type d -empty -delete") + done < <($flist -d) + + for cmd in "${commands[@]}"; do + _runcommands "$cmd" + done +} + +stowsh_help() { + echo "Usage: $0 [-D] [-n] [-s] [-g] [-v[v]] [-t TARGET] PACKAGES..." +} + +if [ "$0" = "$BASH_SOURCE" ]; then + UNINSTALL=0 + DRYRUN=0 + SKIP=0 + USEGIT=0 + TARGET="$PWD" + PACKAGES=() + while [[ "$@" ]]; do + if [[ $1 =~ ^- ]]; then + OPTIND=1 + while getopts ":vhDsngt:" opt; do + case $opt in + h) + stowsh_help + exit 0 + ;; + D) + UNINSTALL=1 + ;; + n) + DRYRUN=1 + ;; + s) + SKIP=1 + ;; + v) + VERBOSE=$((VERBOSE + 1)) + ;; + g) + USEGIT=1 + ;; + t) + TARGET="$OPTARG" + ;; + *) + echo "'$OPTARG' is an invalid option/flag" + exit 1 + ;; + esac + done + shift $((OPTIND - 1)) + else + PACKAGES+=("$1") + shift + fi + done + + if [[ ${#PACKAGES[@]} -eq 0 ]]; then + stowsh_help + exit 1 + fi + + for i in ${!PACKAGES[*]}; do + pkg=${PACKAGES[$i]} + if [[ $UNINSTALL -eq 1 ]]; then + if [[ $VERBOSE -gt 0 ]]; then echoerr "Uninstalling $pkg from $TARGET"; fi + stowsh_uninstall "$pkg" "$TARGET" + else + if [[ $VERBOSE -gt 0 ]]; then echoerr "Installing $pkg to $TARGET"; fi + stowsh_install "$pkg" "$TARGET" + fi + done +fi