#!/bin/sh set -e EVOLV_DIR="/data/evolv" USER_DIR="/data" echo "=== EVOLV Node-RED Development Container ===" echo "Starting at $(date)" # ------------------------------------------------------- # 1. Verify node_modules exist (first start or volume wipe) # ------------------------------------------------------- if [ ! -d "$EVOLV_DIR/node_modules" ]; then echo "[entrypoint] node_modules missing — running npm install..." cd "$EVOLV_DIR" npm install --ignore-scripts echo "[entrypoint] npm install complete." fi # ------------------------------------------------------- # 2. Repair generalFunctions symlink if broken by bind mount # ------------------------------------------------------- GF_LINK="$EVOLV_DIR/node_modules/generalFunctions" GF_TARGET="$EVOLV_DIR/nodes/generalFunctions" if [ -L "$GF_LINK" ] && [ ! -e "$GF_LINK" ]; then echo "[entrypoint] Repairing broken generalFunctions symlink..." rm -f "$GF_LINK" ln -s "$GF_TARGET" "$GF_LINK" echo "[entrypoint] Symlink repaired." elif [ ! -e "$GF_LINK" ]; then echo "[entrypoint] Creating generalFunctions symlink..." ln -s "$GF_TARGET" "$GF_LINK" echo "[entrypoint] Symlink created." fi # ------------------------------------------------------- # 3. Install EVOLV into Node-RED user dir # This ensures node-red.nodes mapping is discovered # ------------------------------------------------------- if [ ! -f "$USER_DIR/package.json" ]; then echo "[entrypoint] Initializing Node-RED user dir..." cat > "$USER_DIR/package.json" << 'PKGJSON' { "name": "evolv-nodered-userdir", "description": "Node-RED user directory for EVOLV dev", "version": "1.0.0", "private": true, "dependencies": {} } PKGJSON fi # Link EVOLV package into the Node-RED user dir cd "$USER_DIR" npm install --no-save "$EVOLV_DIR" 2>/dev/null || { echo "[entrypoint] npm install of EVOLV package failed, attempting symlink fallback..." mkdir -p "$USER_DIR/node_modules" rm -rf "$USER_DIR/node_modules/EVOLV" ln -s "$EVOLV_DIR" "$USER_DIR/node_modules/EVOLV" } echo "[entrypoint] EVOLV nodes installed into Node-RED user dir." # ------------------------------------------------------- # 4. Bootstrap Node-RED projects from examples/ # # Each examples// becomes a project under /data/projects//. # The Projects feature (settings.js) needs each project to be a Git # repo, so we git-init each on first copy. After that the projects # live in the persistent nodered_data volume. # # Default project: pumpingstation-complete-example (settable via # DEFAULT_PROJECT env var). # ------------------------------------------------------- PROJECTS_DIR="/data/projects" DEFAULT_PROJECT="${DEFAULT_PROJECT:-pumpingstation-complete-example}" mkdir -p "$PROJECTS_DIR" if [ -d "$EVOLV_DIR/examples" ]; then for src in "$EVOLV_DIR/examples"/*/; do [ -d "$src" ] || continue name=$(basename "$src") dst="$PROJECTS_DIR/$name" if [ -d "$dst" ]; then echo "[entrypoint] Project '$name' already exists in /data/projects, skipping bootstrap." continue fi echo "[entrypoint] Bootstrapping project '$name'..." cp -r "$src" "$dst" # Synthesize a Node-RED project package.json so the project is # recognised even when the source folder doesn't have one. if [ ! -f "$dst/package.json" ]; then cat > "$dst/package.json" << PKGJSON { "name": "$name", "description": "EVOLV example: $name", "version": "0.1.0", "private": true, "node-red": { "settings": { "flowFile": "flow.json", "credentialsFile": "flow_cred.json" } } } PKGJSON fi # Git init + initial commit (Node-RED projects require Git). if [ ! -d "$dst/.git" ]; then ( cd "$dst" && \ git init -q -b main && \ git config user.email "evolv-dev@local" && \ git config user.name "EVOLV Dev" && \ git add . && \ git commit -q -m "Bootstrap project $name from examples/" || true ) fi echo "[entrypoint] Project '$name' ready at $dst" done fi # ------------------------------------------------------- # 4b. Set the active project (Node-RED's projects state lives in # /data/.config.projects.json). Only set on first run; subsequent # boots respect the operator's last selection in the editor. # ------------------------------------------------------- PROJ_STATE="/data/.config.projects.json" if [ ! -f "$PROJ_STATE" ] && [ -d "$PROJECTS_DIR/$DEFAULT_PROJECT" ]; then echo "[entrypoint] Setting active project = $DEFAULT_PROJECT" cat > "$PROJ_STATE" << JSON { "activeProject": "$DEFAULT_PROJECT", "projects": { "$DEFAULT_PROJECT": {} } } JSON fi # Legacy demo-flow.json fallback — kept for the no-projects case if a # user flips projects.enabled = false in settings.js. DEMO_FLOW="$EVOLV_DIR/docker/demo-flow.json" FLOW_FILE="/data/flows.json" if [ -f "$DEMO_FLOW" ] && [ ! -f "$FLOW_FILE" ]; then cp "$DEMO_FLOW" "$FLOW_FILE" fi # ------------------------------------------------------- # 5. Start Node-RED with custom settings # ------------------------------------------------------- echo "[entrypoint] Starting Node-RED..." exec node-red --settings "$EVOLV_DIR/docker/settings.js"