#!/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; } # 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 cat "$arg" fi done } # Get available package entries for given package getentries() { cat "$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/" # prefer unsuffixed entries, i.e. sort by length test -d "$dir_package" && local 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 | wc -l | sed 's|^[1-9]|-mod\0|')") # TODO getopt 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 -not -name "depends*" -printf "%f\n" | sort | uniq | paste -s -d ' ';; (*) ${EDITOR:-vi} "$dir/$handler";; esac done exit 0 fi ;; esac 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 $({ 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" || { 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 " -L" || echo "find -maxdepth") 3 "$execdir";; esac exit $exitcode