bbuilder-host / noderuntime.py
joddabod's picture
deploy bbuilder host
e2b893f verified
Raw History Blame Contribute Delete
3.75 kB
"""Provision Node.js and the shared nerimity.js install inside the Space container.
Gradio Space images ship Python, not Node. Rather than depend on whatever `apt` would give
us, we download the official Node LTS tarball on cold start (~25 MB compressed, ~20 s) into
/home/user/.node and install @nerimity/nerimity.js once into a shared node_modules that all
bots resolve through NODE_PATH.
(The plan called this bootstrap_node.sh; it's Python so failures surface in the same log
stream as everything else instead of vanishing into a subshell.)
"""
from __future__ import annotations
import os
import shutil
import subprocess
import tarfile
import urllib.request
from pathlib import Path
NODE_VERSION = os.environ.get("BB_NODE_VERSION", "v22.14.0")
NODE_HOME = Path(os.environ.get("BB_NODE_HOME", "/home/user/.node"))
DATA_DIR = Path(os.environ.get("BB_DATA_DIR", "/home/user/data"))
SHARED_MODULES = DATA_DIR / "node_modules"
NERIMITY_PKG = "@nerimity/nerimity.js"
def _log(msg: str) -> None:
print(f"[node] {msg}", flush=True)
def ensure_node() -> str:
"""Return a usable `node` binary path, downloading the runtime if needed."""
existing = shutil.which("node")
if existing:
_log(f"using system node: {existing}")
return existing
node_bin = NODE_HOME / "bin" / "node"
if node_bin.exists():
_log(f"using cached node: {node_bin}")
os.environ["PATH"] = f"{NODE_HOME / 'bin'}:{os.environ.get('PATH', '')}"
return str(node_bin)
name = f"node-{NODE_VERSION}-linux-x64"
url = f"https://nodejs.org/dist/{NODE_VERSION}/{name}.tar.xz"
tmp = Path("/tmp") / f"{name}.tar.xz"
_log(f"downloading {url}")
urllib.request.urlretrieve(url, tmp) # noqa: S310 - fixed, trusted URL
_log("extracting")
NODE_HOME.parent.mkdir(parents=True, exist_ok=True)
with tarfile.open(tmp) as tf:
tf.extractall("/tmp") # noqa: S202 - official tarball
extracted = Path("/tmp") / name
if NODE_HOME.exists():
shutil.rmtree(NODE_HOME, ignore_errors=True)
shutil.move(str(extracted), str(NODE_HOME))
tmp.unlink(missing_ok=True)
os.environ["PATH"] = f"{NODE_HOME / 'bin'}:{os.environ.get('PATH', '')}"
_log(f"node ready: {node_bin}")
return str(node_bin)
def ensure_nerimity(node_bin: str) -> bool:
"""Install the Nerimity SDK once into a shared node_modules. Returns True if usable."""
marker = SHARED_MODULES / "@nerimity" / "nerimity.js" / "package.json"
if marker.exists():
_log("nerimity.js already installed")
return True
DATA_DIR.mkdir(parents=True, exist_ok=True)
pkg = DATA_DIR / "package.json"
if not pkg.exists():
pkg.write_text('{"name":"bbuilder-host-deps","private":true}\n')
npm = Path(node_bin).parent / "npm"
npm_cmd = [str(npm)] if npm.exists() else ["npm"]
_log(f"installing {NERIMITY_PKG}")
try:
res = subprocess.run(
npm_cmd + ["install", "--no-audit", "--no-fund", NERIMITY_PKG],
cwd=str(DATA_DIR),
capture_output=True,
text=True,
timeout=300,
env={**os.environ, "PATH": f"{Path(node_bin).parent}:{os.environ.get('PATH','')}"},
)
except Exception as exc: # noqa: BLE001
_log(f"install failed: {exc}")
return False
if res.returncode != 0:
_log(f"npm install failed:\n{res.stderr[-1500:]}")
return False
_log("nerimity.js installed")
return marker.exists()
def version(node_bin: str) -> str:
try:
return subprocess.run([node_bin, "--version"], capture_output=True, text=True,
timeout=15).stdout.strip()
except Exception: # noqa: BLE001
return "unknown"