Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 68 additions & 11 deletions apps/logicsrc-web/public/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#
# What it does:
# 1. Detects OS (Linux/macOS — Windows: use WSL) and requires Node 18+.
# 2. Fetches the repo tarball from GitHub into $LOGICSRC_HOME/src.
# 3. `npm install` + `npm run build:cli` (builds only the CLI's workspaces).
# 2. Fetches the repo tarball from GitHub into a staging dir.
# 3. `npm install` + `npm run build:cli` (builds only the CLI's workspaces)
# there, then swaps it into $LOGICSRC_HOME/src only once it built. A failed
# run leaves any existing install untouched.
# 4. Drops a `logicsrc` wrapper on $HOME/.local/bin.
#
# Env overrides:
Expand Down Expand Up @@ -60,8 +62,15 @@ check_node() {
# bare text, so this needs no jq. Empty on failure — never fatal, since a missing
# sha only costs `logicsrc update` its precision.
resolve_sha() {
curl -fsSL -H "Accept: application/vnd.github.sha" \
"https://api.github.com/repos/$GH_REPO/commits/$LOGICSRC_REF" 2>/dev/null || true
_sha="$(curl -fsSL -H "Accept: application/vnd.github.sha" \
"https://api.github.com/repos/$GH_REPO/commits/$LOGICSRC_REF" 2>/dev/null || true)"
# Anything that is not a commit id is dropped rather than recorded: an error
# page or a proxy's HTML would otherwise be written into install.json as the
# commit, and `logicsrc update` compares against that string.
case "$_sha" in
*[!0-9a-f]* | "") echo "" ;;
*) [ "${#_sha}" = 40 ] && echo "$_sha" || echo "" ;;
esac
}

# Records what we installed so `logicsrc update` can compare against the remote.
Expand All @@ -79,22 +88,70 @@ write_manifest() {
EOF
}

# Everything is built in a staging directory and only swapped in once it works,
# so a failed or interrupted run cannot leave a half-installed tree behind.
#
# It used to `rm -rf "$SRC_DIR"` before building. If the build then failed --
# or the run was interrupted, or the machine went to sleep -- you were left with
# no dist/, a wrapper still pointing at it, and a manifest from the previous
# install claiming success. Every later `logicsrc` invocation died with
# MODULE_NOT_FOUND and nothing said why.
#
# Staging lives inside $LOGICSRC_HOME rather than /tmp so the swap is a rename
# on the same filesystem, not a cross-device copy of node_modules.
STAGE="$LOGICSRC_HOME/.staging.$$"
PREV="$LOGICSRC_HOME/.previous.$$"
BUILD_LOG="${TMPDIR:-/tmp}/logicsrc-install.$$.log"

cleanup_stage() { rm -rf "$STAGE" "$PREV"; }

# Build output is captured rather than discarded: "build failed" with no reason
# is not a diagnosis. The log survives so it can be read or pasted.
step_fail() {
printf '%s ✗%s %s\n' "$R" "$X" "$1" >&2
if [ -s "$BUILD_LOG" ]; then
printf '\n%s--- last 25 lines ---%s\n' "$Y" "$X" >&2
tail -n 25 "$BUILD_LOG" >&2
printf '%s--- full log: %s ---%s\n' "$Y" "$BUILD_LOG" "$X" >&2
fi
printf '\nyour existing install was left untouched.\n' >&2
cleanup_stage
exit 1
}

do_install() {
detect_os; check_node
need curl; need tar
trap cleanup_stage INT TERM HUP

info "fetching logicsrc@$LOGICSRC_REF from GitHub…"
mkdir -p "$SRC_DIR"
mkdir -p "$LOGICSRC_HOME"
sha="$(resolve_sha)"
short_sha="$(printf '%.7s' "$sha")"
tmp="$(mktemp -d)"
curl -fsSL "$TARBALL_URL" | tar -xz -C "$tmp" --strip-components=1
rm -rf "$SRC_DIR"; mkdir -p "$(dirname "$SRC_DIR")"; mv "$tmp" "$SRC_DIR"
ok "downloaded to $SRC_DIR${short_sha:+ ($short_sha)}"
rm -rf "$STAGE"; mkdir -p "$STAGE"
curl -fsSL "$TARBALL_URL" | tar -xz -C "$STAGE" --strip-components=1 \
|| step_fail "download failed — could not fetch $TARBALL_URL"
ok "downloaded${short_sha:+ ($short_sha)}"

info "installing dependencies (this can take a minute)…"
( cd "$SRC_DIR" && npm install --no-audit --no-fund --ignore-scripts >/dev/null 2>&1 ) || fail "npm install failed — run it by hand in $SRC_DIR"
( cd "$STAGE" && npm install --no-audit --no-fund --ignore-scripts ) >"$BUILD_LOG" 2>&1 \
|| step_fail "npm install failed"
info "building the CLI…"
( cd "$SRC_DIR" && npm run build:cli >/dev/null 2>&1 ) || fail "build failed — run 'npm run build:cli' in $SRC_DIR"
( cd "$STAGE" && npm run build:cli ) >>"$BUILD_LOG" 2>&1 \
|| step_fail "build failed"

# The wrapper execs this exact file, so its absence is the failure the user
# would otherwise only discover on their next command.
[ -f "$STAGE/packages/cli/dist/index.js" ] \
|| step_fail "build produced no packages/cli/dist/index.js"

# Swap. This is the first point at which a working install is touched.
rm -rf "$PREV"
[ -d "$SRC_DIR" ] && mv "$SRC_DIR" "$PREV"
mv "$STAGE" "$SRC_DIR" || { [ -d "$PREV" ] && mv "$PREV" "$SRC_DIR"; step_fail "could not move the build into $SRC_DIR"; }
rm -rf "$PREV"
rm -f "$BUILD_LOG"
trap - INT TERM HUP

mkdir -p "$LOGICSRC_BIN"
cat > "$WRAPPER" <<EOF
Expand Down
Loading