instalee/instalee

213 lines
6.3 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
## DEFINITIONS
name="$(basename "$0")"
self="$(realpath "$0")"
globalconfigdir=/etc/xdg
case "$XDG_CONFIG_DIRS" in
(""|*$globalconfigdir*);;
(*) globalconfigdir=$(echo $XDG_CONFIG_DIRS | cut -d: -f1);;
esac
export dir_home="$(dirname $(find "$INSTALEE_HOME" \
"${XDG_CONFIG_HOME:-$HOME/.config}/$name" "$HOME/.$name" "$globalconfigdir/instalee" "$(realpath "$(dirname "$0")")" "$PWD" \
-maxdepth 1 -name "handlers.available*" 2>/dev/null | head -1))"
handlersfile="$dir_home/handlers.available"
dir_packages="$dir_home/packages"
highlight() { echo $2 "$1" >&2; }
destress() { echo $2 "$1" >&2; }
# Cat a file, filtering out dos line endings and commented lines
catfile() {
cat "$@" | tr -d '\r' | sed '/^#/d'
}
# Get the content of a file or the output of its execution
getcontent() {
for arg; do
if test -z "$noexec" && test -x "$arg"
then "$arg"
else catfile "$arg"
fi
done
}
# Get available package entries for given package
getentries() {
catfile "$handlersfile" | while read handler
do find "$dir_packages/$1/" -depth -type f -name "$handler*" 2>/dev/null | tac
done
}
# Install a package by name
installpkg() {
test "$1" = "--quiet" && local quiet=true && shift
local dir_package="$dir_packages/$1/"
# TODO prefer unsuffixed entries, i.e. sort by length
local package_available_entries=""
test -d "$dir_package" && package_available_entries="$(getentries "$1")"
if test -z "$package_available_entries"; then
local pkghandlers="$(find "$dir_package" -type f -printf "%f\n" 2>/dev/null)"
for handler in $pkghandlers
do installpkg --quiet "$handler" &&
echo "$handler" >>"$handlersfile" &&
package_available_entries=$(getentries "$1") &&
break
done
if test -z "$package_available_entries"; then
test "$quiet" ||
echo "No handler available for package '$1'" >&2
return 2
fi
fi
local pkg_entry
for pkg_entry in $package_available_entries
do highlight "Installing $(echo ${pkg_entry#$dir_packages/} | sed 's|\(.*\)/|\1 via |')"
set -e
local name="$(basename $pkg_entry)"
local base="${name%_*}"
echo "Dependencies" >&2
for dependency in $(cat "${dir_package}depends" "${dir_package}depends_${base}" 2>/dev/null)
do { runinstalee "$dependency" || installdefault "$dependency"; } | sed 's/^/ /'
done
local ext="${name#$base}"
local handler="$dir_home/handlers/$base"
(cd "$(mktemp -d --tmpdir=$execdir "$name.XXXX")"
if test -d "$handler"
then
# This declaration needs to be ahead, otherwise it overrides failing exit codes
local args
local install
args="$(getcontent "$pkg_entry")"
args="${args:-$1}"
installhandler="$(find "$handler" -name "install$ext")"
if test -n "$installhandler"
then pkg_entry="$installhandler $args"
else $(find "$handler" -name "${ext#_}") $args
pkg_entry="$(find "$handler" -name "install") $1"
fi
else
destress " running unhandled" -n
fi
destress " $pkg_entry"
$pkg_entry
find ${dir_package} -name "post" -o -name "post_${base}" -exec {} \; | sed 's/^/ /'
)
set +e
break
done
}
## EXECUTION
version=$(printf "$name r%s.%s%s" "$(git rev-list --count HEAD 2>/dev/null)" "$(git rev-parse --short HEAD 2>/dev/null)" "$(git diff-index HEAD 2>/dev/null | wc -l | sed 's|^[1-9]|-mod\0|')")
while true
do case "$1" in
(-V|--version|"")
printf "$version\nTry '$0 --help' or 'man $name' for usage info\n" >&2
# TODO license https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
exit 0
;;
(-h|--help)
man $name 2>/dev/null || man "$dir_home/$name.1"
exit $?
;;
(-v|--verbose) set -x; export INSTALEE_VERBOSE=10; shift;;
(-d|--default) default=true; shift;;
(-x|--noexec) noexec=true; shift;;
(-a|--add*)
action=$1
shift
case "$action" in
(*group) ${EDITOR:-vi} "$dir_home/groups/$1"; exit $?;;
(*handler)
file="$dir_home/handlers/$1/install"
if ! test -f "$file"; then
mkdir -p "$(dirname "$file")"
printf "#!/bin/sh -e\n$1 install "'"$@"' >"$file"
fi
${EDITOR:-vi} "$file"
exit $?;;
esac
if test $# -gt 0
then packagename=$1; shift
else printf "Name of the package? "; read packagename
fi
dir="$dir_packages/$packagename"
mkdir -p "$dir"
if test $# -gt 0
then handler=$1
test $# -gt 1 && echo "$2">"$dir/$handler" || ${EDITOR:-vi} "$dir/$handler"
exit $?
else
while printf "Handler? (Ctrl-C or Ctrl-D to exit, / to list all) " && read handler
do
case "$handler" in
(/*) find "$dir_packages" "$dir_home/handlers" -type f -printf "%f\n" |
grep -vE '(_|\.)' |
sort | uniq | paste -s -d ' ';;
(*) ${EDITOR:-vi} "$dir/$handler";;
esac
done
exit 0
fi
;;
(*) break;;
esac
done
installdefault() {
local defaulthandler="$(head -1 "$handlersfile")"
highlight "Attempting install of '$1' via default handler '$defaulthandler'"
$(test "$noexec" && echo "sh") "$dir_home/handlers/$defaulthandler/install" "$1" &&
$(test "$noexec" && echo "sh") "$self" --add "$1" "$defaulthandler" "" &&
echo "Added package entry for '$1' via '$defaulthandler'" >&2
}
runinstalee() {
local groupfiles=$(find "$dir_home/groups/$1" -type f 2>/dev/null)
if test -n "$groupfiles"
then
for package in $(getcontent $groupfiles)
do runinstalee "$package" || installdefault "$package"
done
else installpkg "$1" || { test "$default" && installdefault "$1"; }
fi
}
if ! test -f "$handlersfile"
then
copy="$(case "$(uname)" in
(MINGW64*) echo "$dir_home/handlers.available.windows";;
(*) ls "$dir_home/$({ cat /etc/os-release | grep -E '^ID(_LIKE)?=' | cut -d= -f2 | grep . || lsb_release -s -i | tr 'A-Z' 'a-z'; } |
sed 's/^/handlers.available./' | paste -d' ' -s)" 2>/dev/null | head -1;;
esac)" &&
test -n "$copy" &&
echo "Bootstrapping available handlers from $copy" &&
cp "$copy" "$handlersfile" || {
# TODO copy to hostname suffix to prevent lock in on stick
echo "Missing available handlers in $handlersfile!" >&2
exit 1
}
fi
chmod +rx "$dir_home/handlers" -R 2>/dev/null
execdir=/tmp/instalee.$(date +%s)
mkdir -p $execdir
cd $execdir
destress "Running $version in $execdir"
export INSTALEE_VERBOSE="${INSTALEE_VERBOSE:-2}"
exitcode=0
while test $# -gt 0; do
runinstalee "$1"
exitcode=$(expr $exitcode \| $?)
shift
done
case $- in (*x*) $(which tree && echo " $execdir -L" || echo "find $execdir -maxdepth") 3;; esac
exit $exitcode