189 lines
5.2 KiB
Bash
Executable File
189 lines
5.2 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_URL checksum URL for a downloaded .pyz
|
|
ICTLOGIN_PYZ_SHA256 expected SHA-256
|
|
ICTLOGIN_RELEASE_TAG public Gitea release tag (default: v0.2.0)
|
|
ICTLOGIN_PREFIX install directory
|
|
ICTLOGIN_PYTHON Python 3 executable
|
|
EOF
|
|
}
|
|
|
|
SOURCE="${ICTLOGIN_PYZ:-}"
|
|
URL="${ICTLOGIN_PYZ_URL:-}"
|
|
CHECKSUM_URL="${ICTLOGIN_PYZ_SHA256_URL:-}"
|
|
EXPECTED_SHA256="${ICTLOGIN_PYZ_SHA256:-}"
|
|
PREFIX="${ICTLOGIN_PREFIX:-${HOME}/.local/bin}"
|
|
RELEASE_TAG="${ICTLOGIN_RELEASE_TAG:-v0.2.0}"
|
|
RELEASE_BASE_URL="https://gitx.roy1994.top/mancitrus/ictlogin/releases/download/${RELEASE_TAG}"
|
|
|
|
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="${RELEASE_BASE_URL}/ictlogin.pyz"
|
|
CHECKSUM_URL="${CHECKSUM_URL:-${RELEASE_BASE_URL}/ictlogin.pyz.sha256}"
|
|
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")
|
|
TMP_CHECKSUM=""
|
|
cleanup() {
|
|
rm -f "$TMP_FILE"
|
|
[ -z "$TMP_CHECKSUM" ] || rm -f "$TMP_CHECKSUM"
|
|
}
|
|
trap cleanup EXIT HUP INT TERM
|
|
|
|
download() {
|
|
TARGET_FILE=$1
|
|
SOURCE_URL=$2
|
|
if command -v curl >/dev/null 2>&1; then
|
|
curl --fail --location --silent --show-error -o "$TARGET_FILE" "$SOURCE_URL"
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
wget --quiet --output-document="$TARGET_FILE" "$SOURCE_URL"
|
|
else
|
|
echo "curl or wget is required to download $SOURCE_URL" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
if [ -n "$URL" ]; then
|
|
download "$TMP_FILE" "$URL"
|
|
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
|
|
|
|
if [ -z "$EXPECTED_SHA256" ] && [ -n "$CHECKSUM_URL" ]; then
|
|
TMP_CHECKSUM=$(mktemp "${TMPDIR:-/tmp}/ictlogin.pyz.sha256.XXXXXX")
|
|
download "$TMP_CHECKSUM" "$CHECKSUM_URL"
|
|
EXPECTED_SHA256=$(awk 'NF { print $1; exit }' "$TMP_CHECKSUM")
|
|
if [ -z "$EXPECTED_SHA256" ]; then
|
|
echo "could not read SHA-256 from $CHECKSUM_URL" >&2
|
|
exit 1
|
|
fi
|
|
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
|