#!/usr/bin/env bash
# pgh installer — P.10 Phase 0.5i
#
# Usage:
# curl -sSfL https://7rnx.net/pgh/install.sh | sh
# curl -sSfL https://7rnx.net/pgh/install.sh | sh -s -- --from /path/to/tarball
# sh install.sh --from ./pgh-bootstrap-linux-x64.tar.gz
#
# What this does:
# 1. Detect OS + arch
# 2. Download (or use a local) pgh-bootstrap-<os>-<arch>.tar.gz
# 3. Extract into ~/.local/share/pgh/bootstrap/
# 4. Symlink ~/.local/bin/pgh and ~/.local/bin/pgh-sidecar
# 5. Prompt user to run `pgh init` for the network bootstrap step
#
# Nothing here requires root. If ~/.local/bin is not on PATH, we print
# the one-line snippet to add to .bashrc/.zshrc.
set -eu
PGH_VERSION_DEFAULT="0.1.0"
DEFAULT_DOWNLOAD_BASE="${PGH_DOWNLOAD_BASE:-https://7rnx.net/pgh}"
LOCAL_PREFIX="${HOME}/.local"
SHARE_DIR="${LOCAL_PREFIX}/share/pgh"
BOOTSTRAP_DIR="${SHARE_DIR}/bootstrap"
BIN_DIR="${LOCAL_PREFIX}/bin"
# ── Parse args ────────────────────────────────────────────────
SOURCE=""
VERSION="${PGH_VERSION:-$PGH_VERSION_DEFAULT}"
SKIP_PATH_WARN=0
while [ $# -gt 0 ]; do
case "$1" in
--from) SOURCE="$2"; shift 2 ;;
--version) VERSION="$2"; shift 2 ;;
--no-path-warn) SKIP_PATH_WARN=1; shift ;;
-h|--help)
sed -n '2,16p' "$0"
exit 0
;;
*) echo "unknown flag: $1" >&2; exit 1 ;;
esac
done
# ── Detect platform ───────────────────────────────────────────
os_raw="$(uname -s)"
arch_raw="$(uname -m)"
case "$os_raw" in
Linux) OS="linux" ;;
Darwin) OS="darwin" ;;
*) echo "unsupported OS: $os_raw" >&2; exit 1 ;;
esac
case "$arch_raw" in
x86_64|amd64) ARCH="x64" ;;
aarch64|arm64) ARCH="arm64" ;;
*) echo "unsupported arch: $arch_raw" >&2; exit 1 ;;
esac
ARCH_LABEL="${OS}-${ARCH}"
TARBALL_NAME="pgh-bootstrap-${ARCH_LABEL}.tar.gz"
echo "pgh installer: ${OS}-${ARCH}, version ${VERSION}"
# ── Fetch or locate tarball ───────────────────────────────────
fetch_tarball () {
local url="$1" out="$2"
if command -v curl >/dev/null 2>&1; then
curl -sSfL "$url" -o "$out"
elif command -v wget >/dev/null 2>&1; then
wget -qO "$out" "$url"
else
echo "neither curl nor wget available — install one and rerun" >&2
exit 1
fi
}
if [ -z "$SOURCE" ]; then
SOURCE_URL="${DEFAULT_DOWNLOAD_BASE}/${VERSION}/${TARBALL_NAME}"
TMPFILE="$(mktemp -u -t "${TARBALL_NAME}.XXXXXX")"
echo " downloading ${SOURCE_URL}"
fetch_tarball "$SOURCE_URL" "$TMPFILE"
SOURCE="$TMPFILE"
fi
if [ ! -f "$SOURCE" ]; then
echo "source tarball not found: $SOURCE" >&2
exit 1
fi
# ── Extract ───────────────────────────────────────────────────
mkdir -p "$BOOTSTRAP_DIR" "$BIN_DIR"
echo " extracting to ${BOOTSTRAP_DIR}"
tar -xzf "$SOURCE" -C "$BOOTSTRAP_DIR"
# The tarball layout is expected to be:
# pgh-bootstrap/
# bin/pgh
# bin/pgh-sidecar
# lib/...
# node_modules/...
# package.json
# If the top-level is named (common), move its contents up.
if [ ! -f "$BOOTSTRAP_DIR/package.json" ] && [ -d "$BOOTSTRAP_DIR/pgh-bootstrap" ]; then
( cd "$BOOTSTRAP_DIR/pgh-bootstrap" && find . -maxdepth 1 -mindepth 1 -exec mv {} "$BOOTSTRAP_DIR/" \; )
rmdir "$BOOTSTRAP_DIR/pgh-bootstrap" || true
fi
# ── Symlink launchers into ~/.local/bin ──────────────────────
link_bin () {
local name="$1"
local src="$BOOTSTRAP_DIR/bin/$name"
local dst="$BIN_DIR/$name"
if [ ! -f "$src" ]; then
echo " skipping (missing): $src" >&2
return
fi
ln -sf "$src" "$dst"
chmod +x "$src"
echo " linked ${dst} -> ${src}"
}
link_bin pgh
link_bin pgh-sidecar
# ── PATH check ────────────────────────────────────────────────
if [ "$SKIP_PATH_WARN" -ne 1 ]; then
case ":$PATH:" in
*":${BIN_DIR}:"*) : ;; # already on PATH
*)
echo
echo "WARNING: ${BIN_DIR} is not on your PATH."
echo "Add this line to your shell rc (~/.bashrc, ~/.zshrc, or ~/.profile):"
echo
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
echo
;;
esac
fi
# ── Final instructions ────────────────────────────────────────
echo
echo "pgh installed. Next step:"
echo
echo " pgh init"
echo
echo "which sets up your identity + tree store and joins the bootstrap"
echo "topic to pull the live pgh runtime. Pass --offline to skip network."
echo
exit 0