Some checks failed
CI / node 22.19 (push) Has been skipped
CI / node 26 (push) Has been skipped
CI / python 3.10 / keyless SDK (push) Has been skipped
CI / python runtime / release-shaped Linux x64 (push) Has been skipped
CI / windows node 24 / wine blocking (push) Has been skipped
CI / wine apt cache (push) Successful in 58s
CI / serial / linux (push) Has been skipped
Deploy documentation / build (push) Failing after 2m46s
Deploy documentation / deploy (push) Has been skipped
E2E (real DeepSeek API) / e2e (push) Failing after 1m18s
Sandbox / sandbox e2e (bwrap, ubuntu-latest) (push) Failing after 1m18s
Landlock Run / Matrix (push) Successful in 13s
Release (vendor) / Pack npm tarballs (push) Failing after 3m43s
Release (dsh) / Pack npm tarballs (push) Failing after 1m53s
Sandbox / sandbox e2e (landlock, ubuntu-24.04) (push) Failing after 1m51s
Release (vendor) / Publish to npm (push) Has been skipped
Release (dsh) / Publish to npm (push) Has been skipped
CI / node 24 / static (push) Has been cancelled
CI / node 24 / coverage (push) Has been cancelled
CI / node 24 / snapshots and artifacts (push) Has been cancelled
CI / windows node 24 / native complete (push) Has been cancelled
CI / serial / linux (self-hosted standby) (push) Has been cancelled
CI / serial / macos (push) Has been cancelled
CI / serial / windows (self-hosted standby) (push) Has been cancelled
CI / larger-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (16, windows, dsh-windows-2025-16core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (32, windows, dsh-windows-2025-32core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (4, windows, dsh-windows-2025-4core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (64, windows, dsh-windows-2025-64core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (8, windows, dsh-windows-2025-8core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (96, windows, dsh-windows-2025-96core, production-site) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, 16) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, windows, dsh-windows-2025-16core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, windows, dsh-windows-2025-32core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, 4) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, windows, dsh-windows-2025-4core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, windows, dsh-windows-2025-64core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, 8) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, windows, dsh-windows-2025-8core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, windows, dsh-windows-2025-96core, 2) (push) Has been cancelled
CI / all checks passed (push) Has been cancelled
Sandbox / sandbox e2e (seatbelt, macos-latest) (push) Has been cancelled
Sandbox / sandbox e2e (landlock, ubuntu-24.04-arm) (push) Has been cancelled
Landlock Run / ${{ matrix.platform }} (push) Has been cancelled
Landlock Run / darwin (no platform package — degradation proof) (push) Has been cancelled
294 lines
9.2 KiB
Bash
294 lines
9.2 KiB
Bash
#!/usr/bin/env bash
|
|
# Prefetch official Node, Corepack pnpm, and lockfile packages into in-repo caches.
|
|
# Run on the same OS/CPU as the later install, while nodejs.org and the npm registry
|
|
# are reachable. Node/pnpm cannot use socks5h:// proxies; pass an HTTP proxy via
|
|
# DSH_NPM_HTTP_PROXY (example: http://127.0.0.1:3067). That overlay is applied only
|
|
# around Corepack/pnpm and is restored before the script returns, so a caller SOCKS
|
|
# proxy stays in the current shell. curl keeps the inherited proxy (SOCKS included).
|
|
# Optional DSH_NODE_VERSION (no leading v) pins the Node distro; otherwise the
|
|
# running Node is used, or the newest v24.x from nodejs.org/dist/index.json.
|
|
#
|
|
# Usage (repo root): bash scripts/offline/download-deps.sh
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
process_var() {
|
|
local name="$1"
|
|
if [[ -n "${!name+x}" ]]; then
|
|
printf '%s' "${!name}"
|
|
fi
|
|
}
|
|
|
|
inherited_proxy() {
|
|
local name value
|
|
for name in HTTPS_PROXY HTTP_PROXY ALL_PROXY https_proxy http_proxy all_proxy; do
|
|
value="$(process_var "$name")"
|
|
if [[ -n "$value" ]]; then
|
|
printf '%s' "$value"
|
|
return
|
|
fi
|
|
done
|
|
}
|
|
|
|
resolve_node_http_proxy() {
|
|
local override socks name value
|
|
override="$(process_var DSH_NPM_HTTP_PROXY)"
|
|
if [[ -n "$override" ]]; then
|
|
if [[ "$override" == socks5* ]]; then
|
|
echo "DSH_NPM_HTTP_PROXY=$override. Node and pnpm cannot fetch through SOCKS. Use an HTTP proxy (for example http://127.0.0.1:3067)." >&2
|
|
exit 1
|
|
fi
|
|
printf '%s' "$override"
|
|
return
|
|
fi
|
|
socks=
|
|
for name in HTTPS_PROXY HTTP_PROXY ALL_PROXY https_proxy http_proxy all_proxy; do
|
|
value="$(process_var "$name")"
|
|
if [[ -z "$value" ]]; then
|
|
continue
|
|
fi
|
|
if [[ "$value" == socks5* ]]; then
|
|
socks="$name=$value"
|
|
continue
|
|
fi
|
|
printf '%s' "$value"
|
|
return
|
|
done
|
|
if [[ -n "$socks" ]]; then
|
|
echo "$socks. Node and pnpm cannot fetch through SOCKS. Set DSH_NPM_HTTP_PROXY to an HTTP proxy (for example http://127.0.0.1:3067)." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
run_with_node_http_proxy() {
|
|
local http status
|
|
http="$(resolve_node_http_proxy)"
|
|
if [[ -z "$http" ]]; then
|
|
"$@"
|
|
return
|
|
fi
|
|
local HTTPS_PROXY_BAK="${HTTPS_PROXY-}" HTTP_PROXY_BAK="${HTTP_PROXY-}" ALL_PROXY_BAK="${ALL_PROXY-}"
|
|
local https_proxy_bak="${https_proxy-}" http_proxy_bak="${http_proxy-}" all_proxy_bak="${all_proxy-}"
|
|
local had_HTTPS_PROXY=0 had_HTTP_PROXY=0 had_ALL_PROXY=0
|
|
local had_https_proxy=0 had_http_proxy=0 had_all_proxy=0
|
|
if [[ -n "${HTTPS_PROXY+x}" ]]; then had_HTTPS_PROXY=1; fi
|
|
if [[ -n "${HTTP_PROXY+x}" ]]; then had_HTTP_PROXY=1; fi
|
|
if [[ -n "${ALL_PROXY+x}" ]]; then had_ALL_PROXY=1; fi
|
|
if [[ -n "${https_proxy+x}" ]]; then had_https_proxy=1; fi
|
|
if [[ -n "${http_proxy+x}" ]]; then had_http_proxy=1; fi
|
|
if [[ -n "${all_proxy+x}" ]]; then had_all_proxy=1; fi
|
|
export HTTPS_PROXY="$http" HTTP_PROXY="$http" ALL_PROXY="$http"
|
|
export https_proxy="$http" http_proxy="$http" all_proxy="$http"
|
|
set +e
|
|
"$@"
|
|
status=$?
|
|
set -e
|
|
if (( had_HTTPS_PROXY )); then export HTTPS_PROXY="$HTTPS_PROXY_BAK"; else unset HTTPS_PROXY; fi
|
|
if (( had_HTTP_PROXY )); then export HTTP_PROXY="$HTTP_PROXY_BAK"; else unset HTTP_PROXY; fi
|
|
if (( had_ALL_PROXY )); then export ALL_PROXY="$ALL_PROXY_BAK"; else unset ALL_PROXY; fi
|
|
if (( had_https_proxy )); then export https_proxy="$https_proxy_bak"; else unset https_proxy; fi
|
|
if (( had_http_proxy )); then export http_proxy="$http_proxy_bak"; else unset http_proxy; fi
|
|
if (( had_all_proxy )); then export all_proxy="$all_proxy_bak"; else unset all_proxy; fi
|
|
return "$status"
|
|
}
|
|
|
|
curl_proxy_args=()
|
|
curl_proxy="$(inherited_proxy)"
|
|
if [[ -z "$curl_proxy" ]]; then
|
|
curl_proxy="$(process_var DSH_NPM_HTTP_PROXY)"
|
|
fi
|
|
if [[ -n "$curl_proxy" ]]; then
|
|
curl_proxy_args=(--proxy "$curl_proxy")
|
|
fi
|
|
|
|
save_url() {
|
|
local url="$1"
|
|
local dest="$2"
|
|
mkdir -p "$(dirname "$dest")"
|
|
curl -fsSL --retry 3 "${curl_proxy_args[@]}" -o "$dest" "$url"
|
|
}
|
|
|
|
node_platform() {
|
|
local sys arch
|
|
sys="$(uname -s)"
|
|
arch="$(uname -m)"
|
|
case "$sys:$arch" in
|
|
Linux:x86_64) echo linux-x64 ;;
|
|
Linux:aarch64) echo linux-arm64 ;;
|
|
Darwin:x86_64) echo darwin-x64 ;;
|
|
Darwin:arm64) echo darwin-arm64 ;;
|
|
MINGW*|MSYS*|CYGWIN*)
|
|
echo "Use scripts/offline/download-deps.ps1 on Windows." >&2
|
|
exit 1
|
|
;;
|
|
*)
|
|
echo "Unsupported OS/CPU: $sys $arch" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
archive_name() {
|
|
local version="$1"
|
|
local platform="$2"
|
|
case "$platform" in
|
|
linux-*) echo "node-v${version}-${platform}.tar.xz" ;;
|
|
darwin-*) echo "node-v${version}-${platform}.tar.gz" ;;
|
|
*) echo "node-v${version}-${platform}.zip" ;;
|
|
esac
|
|
}
|
|
|
|
file_tag() {
|
|
case "$1" in
|
|
linux-x64) echo linux-x64 ;;
|
|
linux-arm64) echo linux-arm64 ;;
|
|
darwin-x64) echo osx-x64-tar ;;
|
|
darwin-arm64) echo osx-arm64-tar ;;
|
|
win-x64) echo win-x64-zip ;;
|
|
win-arm64) echo win-arm64-zip ;;
|
|
esac
|
|
}
|
|
|
|
engines_ok() {
|
|
local version="$1"
|
|
local major minor
|
|
major="${version%%.*}"
|
|
minor="${version#*.}"
|
|
minor="${minor%%.*}"
|
|
if (( major == 22 && minor >= 19 )); then return 0; fi
|
|
if (( major >= 24 )); then return 0; fi
|
|
return 1
|
|
}
|
|
|
|
resolve_node_version() {
|
|
local platform="$1"
|
|
local dist_base="$2"
|
|
if [[ -n "${DSH_NODE_VERSION:-}" ]]; then
|
|
echo "${DSH_NODE_VERSION#v}"
|
|
return
|
|
fi
|
|
if command -v node >/dev/null 2>&1; then
|
|
local running
|
|
running="$(node --version)"
|
|
running="${running#v}"
|
|
if ! engines_ok "$running"; then
|
|
echo "Running Node v$running is outside engines.node (^22.19.0 || >=24.0.0). Set DSH_NODE_VERSION." >&2
|
|
exit 1
|
|
fi
|
|
echo "$running"
|
|
return
|
|
fi
|
|
local index_path tag version
|
|
index_path="$(mktemp)"
|
|
save_url "$dist_base/index.json" "$index_path"
|
|
tag="$(file_tag "$platform")"
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
version="$(python3 -c 'import json,sys
|
|
releases=json.load(open(sys.argv[1]))
|
|
tag=sys.argv[2]
|
|
for r in releases:
|
|
if r["version"].startswith("v24.") and tag in r["files"]:
|
|
print(r["version"][1:])
|
|
break
|
|
' "$index_path" "$tag")"
|
|
else
|
|
echo "python3 or node is required to pick a Node v24.x from index.json, or set DSH_NODE_VERSION." >&2
|
|
rm -f "$index_path"
|
|
exit 1
|
|
fi
|
|
rm -f "$index_path"
|
|
if [[ -z "$version" ]]; then
|
|
echo "No Node v24.x archive published for $platform at $dist_base." >&2
|
|
exit 1
|
|
fi
|
|
echo "$version"
|
|
}
|
|
|
|
assert_checksum() {
|
|
local sums_path="$1"
|
|
local archive_path="$2"
|
|
local archive="$3"
|
|
local expected actual
|
|
expected="$(awk -v name="$archive" '$2 == name { print $1; exit }' "$sums_path")"
|
|
if [[ -z "$expected" ]]; then
|
|
echo "SHASUMS256.txt has no entry for $archive" >&2
|
|
exit 1
|
|
fi
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
actual="$(sha256sum "$archive_path" | awk '{ print $1 }')"
|
|
else
|
|
actual="$(shasum -a 256 "$archive_path" | awk '{ print $1 }')"
|
|
fi
|
|
if [[ "$actual" != "$expected" ]]; then
|
|
echo "SHA256 mismatch for $archive" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
extract_node() {
|
|
local archive_path="$1"
|
|
local runtime_dir="$2"
|
|
mkdir -p "$runtime_dir"
|
|
case "$archive_path" in
|
|
*.tar.xz) tar -xJf "$archive_path" -C "$runtime_dir" ;;
|
|
*.tar.gz) tar -xzf "$archive_path" -C "$runtime_dir" ;;
|
|
*.zip) unzip -q "$archive_path" -d "$runtime_dir" ;;
|
|
*)
|
|
echo "Unknown Node archive: $archive_path" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
PACKAGE_MANAGER="$(sed -n 's/.*"packageManager": "\(pnpm@[0-9.]*\)".*/\1/p' package.json | head -n 1)"
|
|
case "$PACKAGE_MANAGER" in
|
|
pnpm@*) ;;
|
|
*)
|
|
echo "package.json packageManager must be pnpm@<version>, got ${PACKAGE_MANAGER:-<empty>}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
DIST_BASE="${DSH_NODE_DIST_BASE:-https://nodejs.org/dist}"
|
|
DIST_BASE="${DIST_BASE%/}"
|
|
PLATFORM="$(node_platform)"
|
|
NODE_VERSION="$(resolve_node_version "$PLATFORM" "$DIST_BASE")"
|
|
ARCHIVE_NAME="$(archive_name "$NODE_VERSION" "$PLATFORM")"
|
|
NODE_CACHE="$ROOT/.offline-cache/node"
|
|
ARCHIVE_PATH="$NODE_CACHE/$ARCHIVE_NAME"
|
|
SUMS_PATH="$NODE_CACHE/SHASUMS256-v${NODE_VERSION}.txt"
|
|
RUNTIME_DIR="$NODE_CACHE/runtime"
|
|
NODE_PREFIX="$RUNTIME_DIR/node-v${NODE_VERSION}-${PLATFORM}"
|
|
|
|
echo "Prefetch Node v$NODE_VERSION ($PLATFORM)"
|
|
save_url "$DIST_BASE/v$NODE_VERSION/SHASUMS256.txt" "$SUMS_PATH"
|
|
save_url "$DIST_BASE/v$NODE_VERSION/$ARCHIVE_NAME" "$ARCHIVE_PATH"
|
|
assert_checksum "$SUMS_PATH" "$ARCHIVE_PATH" "$ARCHIVE_NAME"
|
|
if [[ ! -x "$NODE_PREFIX/bin/node" ]]; then
|
|
rm -rf "$RUNTIME_DIR"
|
|
extract_node "$ARCHIVE_PATH" "$RUNTIME_DIR"
|
|
fi
|
|
if [[ ! -x "$NODE_PREFIX/bin/node" ]]; then
|
|
echo "Unpacked Node is missing: $NODE_PREFIX/bin/node" >&2
|
|
exit 1
|
|
fi
|
|
printf '%s\n' "{\"version\":\"$NODE_VERSION\",\"archive\":\"$ARCHIVE_NAME\",\"platform\":\"$PLATFORM\"}" > "$NODE_CACHE/runtime.json"
|
|
|
|
STORE_DIR="$ROOT/.offline-store"
|
|
COREPACK_HOME="$ROOT/.offline-cache/corepack"
|
|
mkdir -p "$STORE_DIR" "$COREPACK_HOME"
|
|
export COREPACK_HOME
|
|
export PATH="$NODE_PREFIX/bin:$PATH"
|
|
|
|
echo "Node $("$NODE_PREFIX/bin/node" --version); prefetch $PACKAGE_MANAGER into $STORE_DIR"
|
|
run_with_node_http_proxy corepack prepare "$PACKAGE_MANAGER" --activate
|
|
run_with_node_http_proxy corepack pnpm fetch --frozen-lockfile --store-dir "$STORE_DIR"
|
|
|
|
cat <<EOF
|
|
Prefetch complete (Node v$NODE_VERSION archive + pnpm store).
|
|
Copy this checkout (including .offline-store and .offline-cache) to the offline machine.
|
|
Then run: bash scripts/offline/install-deps.sh
|
|
EOF
|