2026-03-04 21:07:04 +01:00
|
|
|
#!/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."
|
|
|
|
|
|
|
|
|
|
# -------------------------------------------------------
|
2026-05-08 11:21:21 +02:00
|
|
|
# 4. Bootstrap Node-RED projects from examples/
|
|
|
|
|
#
|
|
|
|
|
# Each examples/<name>/ becomes a project under /data/projects/<name>/.
|
|
|
|
|
# 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).
|
2026-03-04 21:07:04 +01:00
|
|
|
# -------------------------------------------------------
|
2026-05-08 11:21:21 +02:00
|
|
|
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.
|
2026-03-04 21:07:04 +01:00
|
|
|
DEMO_FLOW="$EVOLV_DIR/docker/demo-flow.json"
|
|
|
|
|
FLOW_FILE="/data/flows.json"
|
2026-05-08 11:21:21 +02:00
|
|
|
if [ -f "$DEMO_FLOW" ] && [ ! -f "$FLOW_FILE" ]; then
|
|
|
|
|
cp "$DEMO_FLOW" "$FLOW_FILE"
|
2026-03-04 21:07:04 +01:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# -------------------------------------------------------
|
|
|
|
|
# 5. Start Node-RED with custom settings
|
|
|
|
|
# -------------------------------------------------------
|
|
|
|
|
echo "[entrypoint] Starting Node-RED..."
|
|
|
|
|
exec node-red --settings "$EVOLV_DIR/docker/settings.js"
|