App-Ariza.git | resources/templates/ | launcher-posix.sh.j2
#!/bin/sh
# {{ app_display }} {{ app_version }} — self-contained bundle launcher.
#
# Generated by ariza for {{ platform }}. Everything this script needs is
# inside the directory above it; nothing outside the bundle is read, and
# nothing is installed. Move the bundle anywhere, including a path with
# spaces, and this still works.
set -eu
ARIZA_DISPLAY='{{ app_display }}'
# Resolve this script to its physical path, following symlinks.
#
# Not `readlink -f`: that is a GNU extension, absent from macOS before
# Monterey and from the BSDs, and a launcher that only resolves symlinks
# on Linux is a launcher that breaks the moment someone puts one in
# ~/bin. Plain `readlink` is POSIX-ish and everywhere.
ariza_resolve() {
ariza_target=$1
while [ -L "$ariza_target" ]; do
ariza_dir=$(cd -P -- "$(dirname -- "$ariza_target")" && pwd)
ariza_link=$(readlink -- "$ariza_target")
case $ariza_link in
/*) ariza_target=$ariza_link ;;
*) ariza_target=$ariza_dir/$ariza_link ;;
esac
done
ariza_dir=$(cd -P -- "$(dirname -- "$ariza_target")" && pwd)
printf '%s\n' "$ariza_dir/$(basename -- "$ariza_target")"
}
# $0 is a bare name when some shells find us on PATH; ask the shell where.
ariza_self=$0
case $ariza_self in
*/*) ;;
*) ariza_self=$(command -v -- "$ariza_self" 2>/dev/null || printf '%s\n' "$0") ;;
esac
ariza_self=$(ariza_resolve "$ariza_self")
BUNDLE_ROOT=$(cd -P -- "$(dirname -- "$ariza_self")/.." && pwd)
ARIZA_RAKU="$BUNDLE_ROOT/rakudo/bin/raku"
if [ ! -x "$ARIZA_RAKU" ]; then
printf '%s: this bundle is incomplete — no interpreter at %s\n' \
"$ARIZA_DISPLAY" "$ARIZA_RAKU" >&2
printf ' Unpack the whole archive and run this script from inside it.\n' >&2
exit 1
fi
# The bundle is the only module repository. A RAKULIB or PERL6LIB left in
# the user's environment would otherwise put their own Raku modules —
# compiled against a different Rakudo — ahead of ours.
#
# It is the bundled runtime's own vendor repository, which is what makes
# the shipped bytecode usable here: Rakudo records a precompiled module's
# dependencies relative to the repository only when it has a name for it,
# and a path of our own choosing would not have one.
RAKULIB="inst#$BUNDLE_ROOT/{{ site }}"
export RAKULIB
unset PERL6LIB || :
# Notcurses::Native looks for its prebuilt libraries here, and sets
# TERMINFO_DIRS from the same location. Never NOTCURSES_NATIVE_LIB_DIR,
# which skips that and leaves the terminal without terminfo.
NOTCURSES_NATIVE_DATA_DIR="$BUNDLE_ROOT/native"
export NOTCURSES_NATIVE_DATA_DIR
{%- if sqlcipher and os == 'linux' %}
# ELF resolves DT_NEEDED and dlopen("libsqlcipher.so") by name, so the
# bundle's library directory has to be on the search path; DBIish also
# pre-loads the library by absolute path when told where it is.
LD_LIBRARY_PATH="$BUNDLE_ROOT/{{ sqlcipher_dir }}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export LD_LIBRARY_PATH
DBIISH_SQLCIPHER_LIB="$BUNDLE_ROOT/{{ sqlcipher_lib }}"
export DBIISH_SQLCIPHER_LIB
{%- endif %}
# A first launch compiles nothing (the bundle ships warm bytecode) but
# does have to page a few hundred megabytes off disk, so say so once.
ARIZA_STATE_DIR="${XDG_STATE_HOME:-${HOME:-/tmp}/.local/state}/{{ app_exec }}"
if [ ! -e "$ARIZA_STATE_DIR/.first-run" ]; then
printf '%s: first launch can take a few seconds. Later ones are instant.\n' \
"$ARIZA_DISPLAY" >&2
if mkdir -p "$ARIZA_STATE_DIR" 2>/dev/null; then
: >"$ARIZA_STATE_DIR/.first-run" 2>/dev/null || :
fi
fi
# A warning, never a refusal: TERM is frequently wrong in environments
# where the app still runs fine, and a launcher that second-guesses the
# user's terminal is worse than one that mentions it.
case "${TERM:-}" in
''|dumb|unknown)
printf '%s: TERM is "%s" — this is a full-screen terminal application\n' \
"$ARIZA_DISPLAY" "${TERM:-unset}" >&2
printf ' and may not display correctly. Try TERM=xterm-256color.\n' >&2
;;
esac
{% if updates_enabled %}# The update coordinator returns 75 only after its private installer has
# committed a new managed `current` and written an authenticated handoff.
# A natural application exit 75 has no matching record and is returned unchanged.
unset ARIZA_UPDATE_HANDOFF ARIZA_UPDATE_NONCE || :
ARIZA_UPDATE_RECORD=
ARIZA_UPDATE_EXPECTED=
ariza_update_cleanup() {
[ -z "$ARIZA_UPDATE_RECORD" ] || rm -f -- "$ARIZA_UPDATE_RECORD" 2>/dev/null || :
[ -z "$ARIZA_UPDATE_EXPECTED" ] || rm -f -- "$ARIZA_UPDATE_EXPECTED" 2>/dev/null || :
}
trap ariza_update_cleanup EXIT
# Only an installer-managed physical version gets a challenge. Portable
# bundles still run the coordinator (which dispatches the app) but never
# create update state beside themselves.
if [ "${ARIZA_UPDATE_RELAUNCHED:-}" != 1 ]; then
ARIZA_INSTALL_ROOT=$(dirname -- "$(dirname -- "$BUNDLE_ROOT")")
ARIZA_CURRENT="$ARIZA_INSTALL_ROOT/current"
ARIZA_CURRENT_ROOT=
if [ -L "$ARIZA_CURRENT" ]; then
ARIZA_CURRENT_ROOT=$(ariza_resolve "$ARIZA_CURRENT" 2>/dev/null || :)
fi
if [ "$ARIZA_CURRENT_ROOT" = "$BUNDLE_ROOT" ]; then
ARIZA_NONCE=$(od -An -N32 -tx1 /dev/urandom 2>/dev/null \
| tr -d ' \n' 2>/dev/null || :)
case $ARIZA_NONCE in
*[!0-9a-f]*|'') ARIZA_NONCE= ;;
esac
if [ "$(printf '%s' "$ARIZA_NONCE" | wc -c)" -eq 64 ]; then
ARIZA_STATE="$ARIZA_INSTALL_ROOT/.ariza/update-v1"
ARIZA_OLD_UMASK=$(umask)
umask 077
if [ ! -L "$ARIZA_INSTALL_ROOT/.ariza" ] \
&& [ ! -L "$ARIZA_STATE" ] \
&& mkdir -p -- "$ARIZA_STATE" 2>/dev/null; then
ARIZA_UPDATE_RECORD="$ARIZA_STATE/handoff.$$.$ARIZA_NONCE"
ARIZA_UPDATE_EXPECTED="$ARIZA_UPDATE_RECORD.expected"
if [ ! -e "$ARIZA_UPDATE_RECORD" ] && [ ! -L "$ARIZA_UPDATE_RECORD" ]; then
ARIZA_UPDATE_HANDOFF=$ARIZA_UPDATE_RECORD
ARIZA_UPDATE_NONCE=$ARIZA_NONCE
export ARIZA_UPDATE_HANDOFF ARIZA_UPDATE_NONCE
fi
fi
umask "$ARIZA_OLD_UMASK"
fi
fi
fi
set +e
"$ARIZA_RAKU" "$BUNDLE_ROOT/{{ target }}" "$@"
ARIZA_STATUS=$?
set -e
if [ "$ARIZA_STATUS" -eq 75 ] \
&& [ -n "$ARIZA_UPDATE_RECORD" ] \
&& [ -f "$ARIZA_UPDATE_RECORD" ] \
&& [ ! -L "$ARIZA_UPDATE_RECORD" ] \
&& [ "$(wc -c <"$ARIZA_UPDATE_RECORD" 2>/dev/null || printf 99999)" -le 4096 ]; then
ARIZA_CANDIDATE=$(sed -n '3s/^candidate=//p' "$ARIZA_UPDATE_RECORD")
case $ARIZA_CANDIDATE in
*[!0-9.]*|.*|*..*|*.) ARIZA_CANDIDATE= ;;
esac
if [ -n "$ARIZA_CANDIDATE" ] \
&& [ "$(printf '%s' "$ARIZA_CANDIDATE" | awk -F. '{ print NF }')" -eq 3 ]; then
printf 'protocol=1\nnonce=%s\ncandidate=%s\n' \
"$ARIZA_NONCE" "$ARIZA_CANDIDATE" >"$ARIZA_UPDATE_EXPECTED"
if cmp -s -- "$ARIZA_UPDATE_EXPECTED" "$ARIZA_UPDATE_RECORD"; then
ARIZA_CANDIDATE_ROOT="$ARIZA_INSTALL_ROOT/versions/$ARIZA_CANDIDATE"
ARIZA_CURRENT_ROOT=$(ariza_resolve "$ARIZA_INSTALL_ROOT/current" 2>/dev/null || :)
ARIZA_NEXT_ROOT=$(ariza_resolve "$ARIZA_CANDIDATE_ROOT" 2>/dev/null || :)
if [ -n "$ARIZA_NEXT_ROOT" ] \
&& [ "$ARIZA_CURRENT_ROOT" = "$ARIZA_NEXT_ROOT" ] \
&& [ -x "$ARIZA_NEXT_ROOT/bin/{{ app_exec }}" ]; then
ariza_update_cleanup
ARIZA_UPDATE_RECORD=
ARIZA_UPDATE_EXPECTED=
unset ARIZA_UPDATE_HANDOFF ARIZA_UPDATE_NONCE || :
ARIZA_UPDATE_RELAUNCHED=1
export ARIZA_UPDATE_RELAUNCHED
trap - EXIT
exec "$ARIZA_NEXT_ROOT/bin/{{ app_exec }}" "$@"
fi
fi
fi
fi
exit "$ARIZA_STATUS"
{% endif %}exec "$ARIZA_RAKU" "$BUNDLE_ROOT/{{ target }}" "$@"