feat(scripts): add offline bundle creation and installation scripts

This commit is contained in:
Ivan 2026-05-18 05:09:30 -05:00
parent 6fb0efbd89
commit 040a204d27
No known key found for this signature in database
GPG key ID: B84314E2D9332AE0
2 changed files with 235 additions and 0 deletions

View file

@ -0,0 +1,157 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Create an offline bundle for air-gapped (zero-network) builds.
This script downloads and caches everything needed to build MeshChatX without
any network access. Run it on an online machine, then transfer the resulting
vendor/offline/ directory to your air-gapped build host.
Usage:
bash scripts/create-offline-bundle.sh [options]
Options:
--warm-packaging Pre-download electron-builder packaging tools
(appimagetool, app-builder, etc.) by running a
dummy Linux build. Increases bundle size.
--out-dir PATH Output directory (default: vendor/offline)
-h, --help Show this help
Prerequisites on the online machine:
- pnpm (matching packageManager in package.json)
- uv
- Node.js >= 24
- Python >= 3.11
The bundle includes:
- node_modules/ (fully resolved, with all postinstall artifacts)
- uv cache (all Python wheels)
- electron-builder cache (app-builder and related tools)
- Verification that all vendored assets are present
On the air-gapped machine:
bash scripts/install-offline.sh
MESHCHATX_OFFLINE_BUILD=1 make build
EOF
}
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT_DIR}"
WARM_PACKAGING="0"
OUT_DIR="${ROOT_DIR}/vendor/offline"
while [[ $# -gt 0 ]]; do
case "$1" in
--warm-packaging)
WARM_PACKAGING="1"
shift
;;
--out-dir)
OUT_DIR="${2:?missing value for --out-dir}"
shift 2
;;
--)
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage
exit 1
;;
esac
done
require_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "Missing required command: $1" >&2
exit 1
fi
}
require_cmd node
require_cmd pnpm
require_cmd uv
require_cmd python3
VERSION=$(node -p "require('./package.json').version")
PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
BUNDLE_NAME="meshchatx-offline-bundle-${VERSION}-${PLATFORM}-${ARCH}"
BUNDLE_DIR="${OUT_DIR}/${BUNDLE_NAME}"
rm -rf "${BUNDLE_DIR}"
mkdir -p "${BUNDLE_DIR}"
echo "==> [1/7] Verifying lockfiles..."
if [[ ! -f "pnpm-lock.yaml" ]]; then
echo "Missing pnpm-lock.yaml. Run 'pnpm install' first." >&2
exit 1
fi
if [[ ! -f "uv.lock" ]]; then
echo "Missing uv.lock. Run 'uv lock' first." >&2
exit 1
fi
echo "==> [2/7] Ensuring vendored assets..."
node scripts/fetch-micron-wasm.mjs
python3 scripts/build/fetch_reticulum_manual.py
python3 scripts/build/fetch_repository_wheels.py
echo "==> [3/7] Installing Node.js dependencies..."
pnpm install --frozen-lockfile
echo "==> [4/7] Running postinstall hooks..."
mkdir -p "${BUNDLE_DIR}/electron-builder-cache"
ELECTRON_BUILDER_CACHE="${BUNDLE_DIR}/electron-builder-cache" pnpm run electron-postinstall
echo "==> [5/7] Bundling node_modules..."
if tar --help 2>/dev/null | grep -q -- '--hard-dereference'; then
tar czf "${BUNDLE_DIR}/node_modules.tar.gz" --hard-dereference node_modules/
else
NM_BUNDLE="${BUNDLE_DIR}/node_modules-bundle"
cp -rL node_modules "${NM_BUNDLE}"
(cd "${BUNDLE_DIR}" && tar czf node_modules.tar.gz node_modules-bundle/)
rm -rf "${NM_BUNDLE}"
fi
echo "==> [6/7] Installing Python dependencies and populating uv cache..."
mkdir -p "${BUNDLE_DIR}/uv-cache"
UV_CACHE_DIR="${BUNDLE_DIR}/uv-cache" uv sync --group dev
echo "==> [7/7] Finalizing..."
if [[ "${WARM_PACKAGING}" == "1" ]]; then
echo " Pre-downloading electron-builder packaging tools..."
ELECTRON_BUILDER_CACHE="${BUNDLE_DIR}/electron-builder-cache" \
npx electron-builder --linux dir --publish=never >/dev/null 2>&1 || true
fi
cat > "${BUNDLE_DIR}/.bundle-manifest.json" <<EOF
{
"name": "meshchatx-offline-bundle",
"version": "${VERSION}",
"platform": "${PLATFORM}",
"arch": "${ARCH}",
"created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"warm_packaging": ${WARM_PACKAGING}
}
EOF
echo ""
echo "Offline bundle created: ${BUNDLE_DIR}"
echo ""
ls -lh "${BUNDLE_DIR}"
echo ""
echo "To transfer to an air-gapped machine:"
echo " tar czf meshchatx-offline-${PLATFORM}-${ARCH}.tar.gz -C ${OUT_DIR} ${BUNDLE_NAME}"
echo ""
echo "On the air-gapped machine:"
echo " tar xzf meshchatx-offline-${PLATFORM}-${ARCH}.tar.gz"
echo " bash scripts/install-offline.sh"
echo " MESHCHATX_OFFLINE_BUILD=1 make build"

View file

@ -0,0 +1,78 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Install MeshChatX dependencies from an offline bundle for air-gapped builds.
Run this on the air-gapped machine after extracting the offline bundle into
vendor/offline/ (or the project root).
Usage:
bash scripts/install-offline.sh
This script:
1. Finds the offline bundle directory
2. Extracts node_modules/ from the bundle (if not already present)
3. Exports cache paths for uv and electron-builder
4. Runs 'make install' in offline mode
After install, build with:
MESHCHATX_OFFLINE_BUILD=1 make build
EOF
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${ROOT_DIR}"
BUNDLE=""
if [[ -d "${ROOT_DIR}/vendor/offline" ]]; then
BUNDLE=$(find "${ROOT_DIR}/vendor/offline" -maxdepth 1 -type d -name 'meshchatx-offline-bundle-*' 2>/dev/null | head -n 1)
fi
if [[ -z "${BUNDLE}" ]]; then
echo "No offline bundle found in ${ROOT_DIR}/vendor/offline/" >&2
echo "Create one on an online machine with:" >&2
echo " bash scripts/create-offline-bundle.sh" >&2
exit 1
fi
BUNDLE_NAME=$(basename "${BUNDLE}")
echo "Found offline bundle: ${BUNDLE_NAME}"
if [[ -d "node_modules" ]]; then
echo "node_modules already exists. Skipping extraction."
else
NM_TAR="${BUNDLE}/node_modules.tar.gz"
if [[ ! -f "${NM_TAR}" ]]; then
echo "Missing node_modules.tar.gz in bundle" >&2
exit 1
fi
echo "Extracting node_modules from bundle..."
tar xzf "${NM_TAR}"
echo "node_modules extracted."
fi
export MESHCHATX_OFFLINE_BUILD=1
export UV_CACHE_DIR="${BUNDLE}/uv-cache"
export ELECTRON_BUILDER_CACHE="${BUNDLE}/electron-builder-cache"
echo ""
echo "Running offline install..."
make install
echo ""
echo "========================================"
echo "Offline install complete."
echo ""
echo "Build with:"
echo " MESHCHATX_OFFLINE_BUILD=1 make build"
echo ""
echo "Or package with:"
echo " MESHCHATX_OFFLINE_BUILD=1 pnpm run dist:linux"
echo "========================================"