ictlogin/install.sh

165 lines
4.3 KiB
Bash
Executable File

#!/bin/sh
# Install the portable ICT login zipapp for the current user.
set -eu
usage() {
cat <<'EOF'
Usage: install.sh [options]
Options:
-s, --source PATH|URL install this .pyz file
-p, --prefix DIR install directory (default: $HOME/.local/bin)
--sha256 HEX expected SHA-256 of the .pyz
-h, --help show this help
Environment overrides:
ICTLOGIN_PYZ local .pyz path or URL
ICTLOGIN_PYZ_URL download URL when no local artifact is present
ICTLOGIN_PYZ_SHA256 expected SHA-256
ICTLOGIN_PREFIX install directory
ICTLOGIN_PYTHON Python 3 executable
EOF
}
SOURCE="${ICTLOGIN_PYZ:-}"
URL="${ICTLOGIN_PYZ_URL:-}"
EXPECTED_SHA256="${ICTLOGIN_PYZ_SHA256:-}"
PREFIX="${ICTLOGIN_PREFIX:-${HOME}/.local/bin}"
while [ "$#" -gt 0 ]; do
case "$1" in
-s|--source)
[ "$#" -ge 2 ] || { echo "--source requires a value" >&2; exit 2; }
SOURCE=$2
shift 2
;;
-p|--prefix)
[ "$#" -ge 2 ] || { echo "--prefix requires a value" >&2; exit 2; }
PREFIX=$2
shift 2
;;
--sha256)
[ "$#" -ge 2 ] || { echo "--sha256 requires a value" >&2; exit 2; }
EXPECTED_SHA256=$2
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "unknown option: $1" >&2
usage >&2
exit 2
;;
esac
done
PYTHON="${ICTLOGIN_PYTHON:-}"
if [ -z "$PYTHON" ]; then
PYTHON=$(command -v python3 2>/dev/null || true)
fi
if [ -z "$PYTHON" ]; then
PYTHON=$(command -v python 2>/dev/null || true)
fi
if [ -z "$PYTHON" ]; then
echo "Python 3 is required" >&2
exit 1
fi
if ! "$PYTHON" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 8) else 1)' 2>/dev/null; then
echo "Python 3.8 or newer is required: $PYTHON" >&2
exit 1
fi
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
if [ -z "$SOURCE" ] && [ -z "$URL" ]; then
if [ -f "$SCRIPT_DIR/dist/ictlogin.pyz" ]; then
SOURCE=$SCRIPT_DIR/dist/ictlogin.pyz
elif [ -f "$SCRIPT_DIR/ictlogin.pyz" ]; then
SOURCE=$SCRIPT_DIR/ictlogin.pyz
else
URL="https://gitx.roy1994.top/mancitrus/ictlogin/raw/branch/main/dist/ictlogin.pyz"
fi
fi
SOURCE_PATH=""
case "$SOURCE" in
http://*|https://*) URL=$SOURCE; SOURCE="" ;;
"") ;;
*)
SOURCE_PATH=$SOURCE
[ -f "$SOURCE_PATH" ] || { echo "file not found: $SOURCE_PATH" >&2; exit 1; }
;;
esac
TMP_FILE=$(mktemp "${TMPDIR:-/tmp}/ictlogin.pyz.XXXXXX")
cleanup() {
rm -f "$TMP_FILE"
}
trap cleanup EXIT HUP INT TERM
if [ -n "$URL" ]; then
if command -v curl >/dev/null 2>&1; then
curl --fail --location --silent --show-error -o "$TMP_FILE" "$URL"
elif command -v wget >/dev/null 2>&1; then
wget --quiet --output-document="$TMP_FILE" "$URL"
else
echo "curl or wget is required to download $URL" >&2
exit 1
fi
else
cp "$SOURCE_PATH" "$TMP_FILE"
fi
if [ -z "$EXPECTED_SHA256" ] && [ -n "$SOURCE_PATH" ] && [ -f "${SOURCE_PATH}.sha256" ]; then
EXPECTED_SHA256=$(awk 'NF { print $1; exit }' "${SOURCE_PATH}.sha256")
fi
sha256_file() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | awk '{print $1}'
else
"$PYTHON" - "$1" <<'PY'
import hashlib
import sys
digest = hashlib.sha256()
with open(sys.argv[1], "rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
print(digest.hexdigest())
PY
fi
}
if [ -n "$EXPECTED_SHA256" ]; then
ACTUAL_SHA256=$(sha256_file "$TMP_FILE")
if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then
echo "SHA-256 verification failed" >&2
echo "expected: $EXPECTED_SHA256" >&2
echo "actual: $ACTUAL_SHA256" >&2
exit 1
fi
fi
"$PYTHON" "$TMP_FILE" --version >/dev/null
mkdir -p "$PREFIX"
TARGET="$PREFIX/ictlogin"
if command -v install >/dev/null 2>&1; then
install -m 0755 "$TMP_FILE" "$TARGET"
else
cp "$TMP_FILE" "$TARGET"
chmod 0755 "$TARGET"
fi
echo "installed $TARGET"
case ":${PATH:-}:" in
*":$PREFIX:"*) ;;
*) echo "add to PATH: export PATH=\"$PREFIX:\$PATH\"" ;;
esac
"$TARGET" --version