#!/usr/bin/env sh # Venelx worker installer for macOS and Linux (Debian/Ubuntu, x86_64). # # curl -fsSL https://get.venelx.com | sh # # Why this exists: installers downloaded through a browser get a "quarantine" # flag that makes macOS Gatekeeper warn about unsigned apps. Downloading with # curl does not set it. The installer is fetched from the public GitHub release # and its SHA-256 is checked against the digest GitHub publishes for the file. # # Options (pass after `sh -s --`): --version X.Y.Z install a specific version set -eu REPO="VenelX/worker" VERSION="" while [ $# -gt 0 ]; do case "$1" in --version) VERSION="${2:?--version needs a value}"; shift ;; -h|--help) sed -n 2,12p "$0"; exit 0 ;; *) echo "Unknown option: $1" >&2; exit 1 ;; esac shift done say() { printf '%s\n' "$*"; } die() { printf 'error: %s\n' "$*" >&2; exit 1; } need() { command -v "$1" >/dev/null 2>&1 || die "'$1' is required"; } need curl OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in Darwin) KIND=pkg ;; Linux) KIND=deb case "$ARCH" in x86_64|amd64) ;; *) die "Linux installer is x86_64 only (this machine: $ARCH)" ;; esac command -v dpkg >/dev/null 2>&1 || die "Only Debian/Ubuntu (.deb) is supported by this script" ;; *) die "Unsupported OS: $OS (Windows: run irm https://get.venelx.com/win | iex in PowerShell)" ;; esac TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT INT TERM if [ -z "$VERSION" ]; then say "Looking up the latest worker release..." VERSION="$(curl -fsSL "https://github.com/$REPO/releases/latest/download/latest.json" \ | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)" [ -n "$VERSION" ] || die "Could not determine the latest version" fi case "$VERSION" in *[!0-9.]*|"") die "Invalid version: $VERSION" ;; esac if [ "$KIND" = pkg ]; then FILE="VenelxWorker-$VERSION.pkg"; else FILE="VenelxWorker-$VERSION-amd64.deb"; fi URL="https://github.com/$REPO/releases/download/worker-v$VERSION/$FILE" RELEASE_JSON="$(curl -fsSL "https://api.github.com/repos/$REPO/releases/tags/worker-v$VERSION" 2>/dev/null || true)" # Pull this asset's checksum and size out of the release JSON. asset_field() { # $1 = field regex fragment, value pattern in $2 printf '%s' "$RELEASE_JSON" | tr -d '\n' | sed 's/":[[:space:]]*/":/g' \ | awk -v n="\"name\":\"$FILE\"" -v re="$1" '{ i = index($0, n); if (i) { r = substr($0, i); if (match(r, re)) { d = substr(r, RSTART, RLENGTH); sub(/^[^:]*:/, "", d); gsub(/"|sha256:/, "", d); print d } } }' } EXPECTED="$(asset_field '"digest":"sha256:[0-9a-f]+"')" TOTAL="$(asset_field '"size":[0-9]+')" # One short status line (never wraps, unlike curl's own bar in a narrow terminal). say "Downloading $FILE ..." if [ -t 2 ]; then curl -fsSL -o "$TMP/$FILE" "$URL" 2>"$TMP/curl.err" & CURL_PID=$! while kill -0 "$CURL_PID" 2>/dev/null; do SIZE=0 [ -f "$TMP/$FILE" ] && SIZE="$(wc -c < "$TMP/$FILE" | tr -d ' ')" MB=$((SIZE / 1048576)) if [ -n "$TOTAL" ] && [ "$TOTAL" -gt 0 ] 2>/dev/null; then printf '\r %s%% (%s/%s MB) ' "$((SIZE * 100 / TOTAL))" "$MB" "$((TOTAL / 1048576))" >&2 else printf '\r %s MB ' "$MB" >&2 fi sleep 1 done printf '\r%40s\r' '' >&2 wait "$CURL_PID" || die "Download failed: $URL ($(cat "$TMP/curl.err" 2>/dev/null))" else curl -fsSL -o "$TMP/$FILE" "$URL" || die "Download failed: $URL" fi say "Downloaded." # Verify against the digest GitHub records for the release asset. if [ -n "$EXPECTED" ]; then if command -v shasum >/dev/null 2>&1; then ACTUAL="$(shasum -a 256 "$TMP/$FILE" | cut -d' ' -f1)" else need sha256sum; ACTUAL="$(sha256sum "$TMP/$FILE" | cut -d' ' -f1)"; fi [ "$ACTUAL" = "$EXPECTED" ] || die "Checksum mismatch - refusing to install (expected $EXPECTED, got $ACTUAL)" say "Checksum OK." else say "Note: GitHub published no checksum for this file, so it could not be verified." fi say "Installing (administrator password required)..." # This script usually runs as `curl ... | sh`, so stdin is the download pipe, not the keyboard. # Give sudo the real terminal so it can ask for the password. run_priv() { if [ -r /dev/tty ] && [ -w /dev/tty ]; then sudo "$@" /dev/null 2>&1; then INSTALL_CMD="apt-get install -y $TMP/$FILE"; else INSTALL_CMD="dpkg -i $TMP/$FILE"; fi fi # shellcheck disable=SC2086 if ! run_priv $INSTALL_CMD; then # Keep the verified download so the install can be retried without downloading again. KEEP="${HOME:-/tmp}/$FILE" cp "$TMP/$FILE" "$KEEP" 2>/dev/null && SAVED="$KEEP" || SAVED="$TMP/$FILE" say "" >&2 say "The install step did not complete (wrong or missing administrator password?)." >&2 say "The verified installer was saved to: $SAVED" >&2 RETRY="$(printf '%s' "$INSTALL_CMD" | sed "s#$TMP/$FILE#$SAVED#")" say "Retry with: sudo $RETRY" >&2 trap - EXIT INT TERM [ "$SAVED" = "$TMP/$FILE" ] || rm -rf "$TMP" exit 1 fi say "" say "Venelx worker $VERSION installed." say "Next: open the Venelx Worker app and pair it from Dashboard -> Account -> Workers."