mirror of
https://github.com/Comfy-Org/ComfyUI-Manager.git
synced 2026-03-08 02:27:31 +08:00
Add automated E2E test scripts for unified dependency resolver: - setup_e2e_env.sh: idempotent environment setup (clone ComfyUI, create venv, install deps, symlink Manager, write config.ini) - start_comfyui.sh: foreground-blocking launcher using tail -f | grep -q readiness detection - stop_comfyui.sh: graceful SIGTERM → SIGKILL shutdown Update test documentation reflecting E2E testing findings: - TEST-environment-setup.md: add automated script usage, document caveats (PYTHONPATH, config.ini path, Manager v4 /v2/ prefix, Blocked by policy, bash ((var++)) trap, git+https:// rejection) - TEST-unified-dep-resolver.md: add TC-17 (restart dependency detection), TC-18 (real node pack integration), Validated Behaviors section, normalize API port to 8199 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
242 lines
7.3 KiB
Bash
Executable File
242 lines
7.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# setup_e2e_env.sh — Automated E2E environment setup for ComfyUI + Manager
|
|
#
|
|
# Creates an isolated ComfyUI installation with ComfyUI-Manager for E2E testing.
|
|
# Idempotent: skips setup if marker file and key artifacts already exist.
|
|
#
|
|
# Input env vars:
|
|
# E2E_ROOT — target directory (default: auto-generated via mktemp)
|
|
# MANAGER_ROOT — manager repo root (default: auto-detected from script location)
|
|
# COMFYUI_BRANCH — ComfyUI branch to clone (default: master)
|
|
# PYTHON — Python executable (default: python3)
|
|
#
|
|
# Output (last line of stdout):
|
|
# E2E_ROOT=/path/to/environment
|
|
#
|
|
# Exit: 0=success, 1=failure
|
|
|
|
set -euo pipefail
|
|
|
|
# --- Constants ---
|
|
COMFYUI_REPO="https://github.com/comfyanonymous/ComfyUI.git"
|
|
PYTORCH_CPU_INDEX="https://download.pytorch.org/whl/cpu"
|
|
CONFIG_INI_CONTENT="[default]
|
|
use_uv = true
|
|
use_unified_resolver = true
|
|
file_logging = false"
|
|
|
|
# --- Logging helpers ---
|
|
log() { echo "[setup_e2e] $*"; }
|
|
err() { echo "[setup_e2e] ERROR: $*" >&2; }
|
|
die() { err "$@"; exit 1; }
|
|
|
|
# --- Detect manager root by walking up from script dir to find pyproject.toml ---
|
|
detect_manager_root() {
|
|
local dir
|
|
dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
while [[ "$dir" != "/" ]]; do
|
|
if [[ -f "$dir/pyproject.toml" ]]; then
|
|
echo "$dir"
|
|
return 0
|
|
fi
|
|
dir="$(dirname "$dir")"
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# --- Validate prerequisites ---
|
|
validate_prerequisites() {
|
|
local py="${PYTHON:-python3}"
|
|
local missing=()
|
|
|
|
command -v git >/dev/null 2>&1 || missing+=("git")
|
|
command -v uv >/dev/null 2>&1 || missing+=("uv")
|
|
command -v "$py" >/dev/null 2>&1 || missing+=("$py")
|
|
|
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
die "Missing prerequisites: ${missing[*]}"
|
|
fi
|
|
|
|
# Verify Python version >= 3.9
|
|
local py_version
|
|
py_version=$("$py" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")
|
|
local major minor
|
|
major="${py_version%%.*}"
|
|
minor="${py_version##*.}"
|
|
if [[ "$major" -lt 3 ]] || { [[ "$major" -eq 3 ]] && [[ "$minor" -lt 9 ]]; }; then
|
|
die "Python 3.9+ required, found $py_version"
|
|
fi
|
|
log "Prerequisites OK (python=$py_version, git=$(git --version | awk '{print $3}'), uv=$(uv --version 2>&1 | awk '{print $2}'))"
|
|
}
|
|
|
|
# --- Check idempotency: skip if already set up ---
|
|
check_already_setup() {
|
|
local root="$1"
|
|
if [[ -f "$root/.e2e_setup_complete" ]] \
|
|
&& [[ -d "$root/comfyui" ]] \
|
|
&& [[ -d "$root/venv" ]] \
|
|
&& [[ -f "$root/comfyui/user/__manager/config.ini" ]] \
|
|
&& [[ -L "$root/comfyui/custom_nodes/ComfyUI-Manager" ]]; then
|
|
log "Environment already set up at $root (marker file exists). Skipping."
|
|
echo "E2E_ROOT=$root"
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
# --- Verify the setup ---
|
|
verify_setup() {
|
|
local root="$1"
|
|
local manager_root="$2"
|
|
local venv_py="$root/venv/bin/python"
|
|
local errors=0
|
|
|
|
log "Running verification checks..."
|
|
|
|
# Check ComfyUI directory
|
|
if [[ ! -f "$root/comfyui/main.py" ]]; then
|
|
err "Verification FAIL: comfyui/main.py not found"
|
|
((errors++))
|
|
fi
|
|
|
|
# Check venv python
|
|
if [[ ! -x "$venv_py" ]]; then
|
|
err "Verification FAIL: venv python not executable"
|
|
((errors++))
|
|
fi
|
|
|
|
# Check symlink
|
|
local link_target="$root/comfyui/custom_nodes/ComfyUI-Manager"
|
|
if [[ ! -L "$link_target" ]]; then
|
|
err "Verification FAIL: symlink $link_target does not exist"
|
|
((errors++))
|
|
elif [[ "$(readlink -f "$link_target")" != "$(readlink -f "$manager_root")" ]]; then
|
|
err "Verification FAIL: symlink target mismatch"
|
|
((errors++))
|
|
fi
|
|
|
|
# Check config.ini
|
|
if [[ ! -f "$root/comfyui/user/__manager/config.ini" ]]; then
|
|
err "Verification FAIL: config.ini not found"
|
|
((errors++))
|
|
fi
|
|
|
|
# Check Python imports
|
|
# comfy is a local package inside ComfyUI (not pip-installed), and
|
|
# comfyui_manager.__init__ imports from comfy — both need PYTHONPATH
|
|
if ! PYTHONPATH="$root/comfyui" "$venv_py" -c "import comfy" 2>/dev/null; then
|
|
err "Verification FAIL: 'import comfy' failed"
|
|
((errors++))
|
|
fi
|
|
|
|
if ! PYTHONPATH="$root/comfyui" "$venv_py" -c "import comfyui_manager" 2>/dev/null; then
|
|
err "Verification FAIL: 'import comfyui_manager' failed"
|
|
((errors++))
|
|
fi
|
|
|
|
if [[ "$errors" -gt 0 ]]; then
|
|
die "Verification failed with $errors error(s)"
|
|
fi
|
|
log "Verification OK: all checks passed"
|
|
}
|
|
|
|
# ===== Main =====
|
|
|
|
# Resolve MANAGER_ROOT
|
|
if [[ -z "${MANAGER_ROOT:-}" ]]; then
|
|
MANAGER_ROOT="$(detect_manager_root)" || die "Cannot detect MANAGER_ROOT. Set it explicitly."
|
|
fi
|
|
MANAGER_ROOT="$(cd "$MANAGER_ROOT" && pwd)"
|
|
log "MANAGER_ROOT=$MANAGER_ROOT"
|
|
|
|
# Validate prerequisites
|
|
validate_prerequisites
|
|
|
|
PYTHON="${PYTHON:-python3}"
|
|
COMFYUI_BRANCH="${COMFYUI_BRANCH:-master}"
|
|
|
|
# Create or use E2E_ROOT
|
|
CREATED_BY_US=false
|
|
if [[ -z "${E2E_ROOT:-}" ]]; then
|
|
E2E_ROOT="$(mktemp -d -t e2e_comfyui_XXXXXX)"
|
|
CREATED_BY_US=true
|
|
log "Created E2E_ROOT=$E2E_ROOT"
|
|
else
|
|
mkdir -p "$E2E_ROOT"
|
|
log "Using E2E_ROOT=$E2E_ROOT"
|
|
fi
|
|
|
|
# Idempotency check
|
|
check_already_setup "$E2E_ROOT"
|
|
|
|
# Cleanup trap: remove E2E_ROOT on failure only if we created it
|
|
cleanup_on_failure() {
|
|
local exit_code=$?
|
|
if [[ "$exit_code" -ne 0 ]] && [[ "$CREATED_BY_US" == "true" ]]; then
|
|
err "Setup failed. Cleaning up $E2E_ROOT"
|
|
rm -rf "$E2E_ROOT"
|
|
fi
|
|
}
|
|
trap cleanup_on_failure EXIT
|
|
|
|
# Step 1: Clone ComfyUI
|
|
log "Step 1/8: Cloning ComfyUI (branch=$COMFYUI_BRANCH)..."
|
|
if [[ -d "$E2E_ROOT/comfyui/.git" ]]; then
|
|
log " ComfyUI already cloned, skipping"
|
|
else
|
|
git clone --depth=1 --branch "$COMFYUI_BRANCH" "$COMFYUI_REPO" "$E2E_ROOT/comfyui"
|
|
fi
|
|
|
|
# Step 2: Create virtual environment
|
|
log "Step 2/8: Creating virtual environment..."
|
|
if [[ -d "$E2E_ROOT/venv" ]]; then
|
|
log " venv already exists, skipping"
|
|
else
|
|
uv venv "$E2E_ROOT/venv"
|
|
fi
|
|
VENV_PY="$E2E_ROOT/venv/bin/python"
|
|
|
|
# Step 3: Install ComfyUI dependencies
|
|
log "Step 3/8: Installing ComfyUI dependencies (CPU-only)..."
|
|
uv pip install \
|
|
--python "$VENV_PY" \
|
|
-r "$E2E_ROOT/comfyui/requirements.txt" \
|
|
--extra-index-url "$PYTORCH_CPU_INDEX"
|
|
|
|
# Step 4: Install ComfyUI-Manager (non-editable, production-like)
|
|
log "Step 4/8: Installing ComfyUI-Manager..."
|
|
uv pip install --python "$VENV_PY" "$MANAGER_ROOT"
|
|
|
|
# Step 5: Create symlink for custom_nodes discovery
|
|
log "Step 5/8: Creating custom_nodes symlink..."
|
|
mkdir -p "$E2E_ROOT/comfyui/custom_nodes"
|
|
local_link="$E2E_ROOT/comfyui/custom_nodes/ComfyUI-Manager"
|
|
if [[ -L "$local_link" ]]; then
|
|
log " Symlink already exists, updating"
|
|
rm -f "$local_link"
|
|
fi
|
|
ln -s "$MANAGER_ROOT" "$local_link"
|
|
|
|
# Step 6: Write config.ini to correct path
|
|
log "Step 6/8: Writing config.ini..."
|
|
mkdir -p "$E2E_ROOT/comfyui/user/__manager"
|
|
echo "$CONFIG_INI_CONTENT" > "$E2E_ROOT/comfyui/user/__manager/config.ini"
|
|
|
|
# Step 7: Create HOME isolation directories
|
|
log "Step 7/8: Creating HOME isolation directories..."
|
|
mkdir -p "$E2E_ROOT/home/.config"
|
|
mkdir -p "$E2E_ROOT/home/.local/share"
|
|
mkdir -p "$E2E_ROOT/logs"
|
|
|
|
# Step 8: Verify setup
|
|
log "Step 8/8: Verifying setup..."
|
|
verify_setup "$E2E_ROOT" "$MANAGER_ROOT"
|
|
|
|
# Write marker file
|
|
date -Iseconds > "$E2E_ROOT/.e2e_setup_complete"
|
|
|
|
# Clear the EXIT trap since setup succeeded
|
|
trap - EXIT
|
|
|
|
log "Setup complete."
|
|
echo "E2E_ROOT=$E2E_ROOT"
|