227 lines
5.4 KiB
Bash
Executable File
227 lines
5.4 KiB
Bash
Executable File
#!/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
|