Spaces:
Running
Running
| # JupyterLab entrypoint. | |
| # Runs WITHOUT a token/password β the aiohttp proxy in front of it handles | |
| # the password gate. Listens only on localhost:8888 so it is not directly | |
| # reachable. HF exposes the container (via the proxy) on port 7860. | |
| # ββ Persistent-storage bootstrap βββββββββββββββββββββββββββββββββββββ | |
| # On HF Spaces, /data is the ONLY directory guaranteed to survive a | |
| # sleep/restart/rebuild β and only if "Persistent Storage" is actually | |
| # enabled in Settings β Persistent storage. Everything else under / is | |
| # rebuilt fresh from the image every time the container starts. | |
| # | |
| # To make sure real work survives, we redirect the ephemeral spots that | |
| # matter β pip's cache + `pip install --user`, npm/bun's cache, Hugging | |
| # Face's model/dataset cache, and JupyterLab's own settings/workspaces β | |
| # onto /data. This runs on every boot; it's a no-op once already wired, | |
| # and intentionally non-fatal (no `set -e`) so a hiccup here never | |
| # prevents JupyterLab from starting. | |
| mkdir -p /data/notebooks /data/projects \ | |
| /data/.npm-global /data/node_modules \ | |
| /data/.cache /data/.local /data/.npm-cache /data/.bun-cache \ | |
| /data/.huggingface \ | |
| /data/.jupyter-data/user-settings /data/.jupyter-data/workspaces \ | |
| 2>/dev/null | |
| link_to_data() { | |
| # $1 = ephemeral path (e.g. /root/.cache), $2 = persistent path under /data | |
| local target="$1" persist="$2" | |
| if [ -L "$target" ]; then | |
| return 0 # already wired up from a previous boot of this container | |
| fi | |
| if [ -e "$target" ]; then | |
| # First boot only: keep whatever the image shipped with, then swap | |
| # in the symlink so all future writes land on /data. | |
| cp -an "$target"/. "$persist"/ 2>/dev/null | |
| rm -rf "$target" 2>/dev/null | |
| fi | |
| ln -s "$persist" "$target" 2>/dev/null | |
| } | |
| link_to_data /root/.cache "/data/.cache" # pip download/build cache, etc. | |
| link_to_data /root/.local "/data/.local" # `pip install --user` packages | |
| link_to_data /root/.npm "/data/.npm-cache" | |
| link_to_data /root/.bun "/data/.bun-cache" | |
| # Set env vars here instead of supervisord environment= directive. | |
| # supervisord's environment= REPLACES the entire env (dropping HF secrets). | |
| export HOME="/root" | |
| export JUPYTER_CONFIG_DIR="/home/user/.jupyter" | |
| export SHELL="/bin/bash" | |
| # Plain `pip install <pkg>` (no --user flag needed, even as root) now | |
| # lands under /root/.local, which is symlinked to /data/.local above. | |
| export PIP_USER=1 | |
| # transformers / diffusers / datasets / huggingface_hub all cache | |
| # downloaded models here β avoids re-downloading after every restart. | |
| export HF_HOME="/data/.huggingface" | |
| # JupyterLab's *data* β kernelspecs, settings, saved workspaces, history β | |
| # goes to /data so customizations survive. (The static config file used | |
| # below, jupyter_lab_config.py, ships in the image and doesn't need to.) | |
| export JUPYTER_DATA_DIR="/data/.jupyter-data" | |
| export JUPYTERLAB_SETTINGS_DIR="/data/.jupyter-data/user-settings" | |
| export JUPYTERLAB_WORKSPACES_DIR="/data/.jupyter-data/workspaces" | |
| # root_dir is set to "/" in jupyter_lab_config.py so the file browser can | |
| # navigate the whole filesystem. cd to /data so new terminals open in the | |
| # persistent folder by default (avoids the cwd-mismatch confusion, and | |
| # avoids people accidentally saving work somewhere that gets wiped on the | |
| # next restart). | |
| cd /data || exit 1 | |
| # Silence the "new version available" popup in JupyterLab | |
| jupyter labextension disable "@jupyterlab/apputils-extension:announcements" | |
| exec jupyter-lab \ | |
| --config=/home/user/.jupyter/jupyter_lab_config.py \ | |
| --allow-root |