mirror of
https://github.com/rookiestar28/ComfyUI-OpenClaw.git
synced 2026-08-14 00:48:07 +00:00
162 lines
4.4 KiB
Python
162 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
R120: Dependency parity preflight check.
|
|
|
|
Validates the build environment before deployment or test execution.
|
|
Checks:
|
|
1. Python version (>=3.10)
|
|
2. Node.js version (>=18.0.0, per package.json + TEST_SOP)
|
|
3. Essential Python dependencies (cryptography, defusedxml)
|
|
|
|
Usage:
|
|
python scripts/preflight_check.py [--strict]
|
|
"""
|
|
|
|
import argparse
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
# Minimum requirements
|
|
MIN_PYTHON_VERSION = (3, 10)
|
|
MIN_NODE_VERSION = (18, 0, 0)
|
|
|
|
REQUIRED_PYTHON_PACKAGES = [
|
|
("cryptography", "41.0"),
|
|
("defusedxml", "0.7.1"),
|
|
]
|
|
|
|
# Colors for output
|
|
GREEN = "\033[92m"
|
|
RED = "\033[91m"
|
|
YELLOW = "\033[93m"
|
|
RESET = "\033[0m"
|
|
|
|
|
|
def log_ok(msg: str):
|
|
print(f"{GREEN}[OK]{RESET} {msg}")
|
|
|
|
|
|
def log_fail(msg: str):
|
|
print(f"{RED}[FAIL]{RESET} {msg}")
|
|
|
|
|
|
def log_warn(msg: str):
|
|
print(f"{YELLOW}[WARN]{RESET} {msg}")
|
|
|
|
|
|
def check_python_version() -> bool:
|
|
"""Validate Python interpreter version."""
|
|
current = sys.version_info[:3]
|
|
if current < MIN_PYTHON_VERSION:
|
|
log_fail(
|
|
f"Python version {sys.version} is too old. Required: >={'.'.join(map(str, MIN_PYTHON_VERSION))}"
|
|
)
|
|
return False
|
|
log_ok(f"Python version: {'.'.join(map(str, current))}")
|
|
return True
|
|
|
|
|
|
def check_node_version() -> bool:
|
|
"""Validate Node.js version."""
|
|
try:
|
|
output = (
|
|
subprocess.check_output(["node", "--version"], stderr=subprocess.STDOUT)
|
|
.decode("utf-8")
|
|
.strip()
|
|
)
|
|
# Output is usually vX.Y.Z
|
|
match = re.search(r"v(\d+)\.(\d+)\.(\d+)", output)
|
|
if not match:
|
|
log_warn(f"Could not parse Node version from '{output}'.")
|
|
return False
|
|
|
|
major, minor, patch = map(int, match.groups())
|
|
if (major, minor, patch) < MIN_NODE_VERSION:
|
|
log_fail(
|
|
f"Node version {output} is too old. Required: >={'.'.join(map(str, MIN_NODE_VERSION))}"
|
|
)
|
|
return False
|
|
|
|
log_ok(f"Node version: {output}")
|
|
return True
|
|
except FileNotFoundError:
|
|
log_fail("Node.js not found in PATH.")
|
|
return False
|
|
except Exception as e:
|
|
log_warn(f"Failed to check Node version: {e}")
|
|
return False
|
|
|
|
|
|
def check_python_packages() -> bool:
|
|
"""Validate installed Python packages."""
|
|
all_ok = True
|
|
try:
|
|
from importlib.metadata import PackageNotFoundError, version
|
|
|
|
for pkg, min_ver in REQUIRED_PYTHON_PACKAGES:
|
|
try:
|
|
installed_ver = version(pkg)
|
|
# Simple version compare (not fully semver compliant but enough for preflight)
|
|
# Using pkg_resources or packaging.version is better but might add deps.
|
|
# We'll just split by dot.
|
|
|
|
# normalize versions
|
|
def parse_ver(v_str):
|
|
return tuple(map(int, v_str.split(".")[:3]))
|
|
|
|
if parse_ver(installed_ver) < parse_ver(min_ver):
|
|
log_fail(f"Package '{pkg}' version {installed_ver} < {min_ver}")
|
|
all_ok = False
|
|
else:
|
|
log_ok(f"Package '{pkg}': {installed_ver} (>= {min_ver})")
|
|
except PackageNotFoundError:
|
|
log_fail(f"Package '{pkg}' not installed.")
|
|
all_ok = False
|
|
except ValueError:
|
|
# Fallback for complex version strings
|
|
log_warn(
|
|
f"Package '{pkg}' version {installed_ver} checked (complex format). Assuming OK."
|
|
)
|
|
|
|
except ImportError:
|
|
log_warn(
|
|
"importlib.metadata not available (Python < 3.8?). Skipping package checks."
|
|
)
|
|
|
|
return all_ok
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Run dependency preflight checks.")
|
|
parser.add_argument(
|
|
"--strict", action="store_true", help="Fail with exit code 1 on any error"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
print("Running R120 Dependency Preflight...")
|
|
print("-" * 40)
|
|
|
|
checks = [
|
|
check_python_version(),
|
|
check_node_version(),
|
|
check_python_packages(),
|
|
]
|
|
|
|
print("-" * 40)
|
|
success = all(checks)
|
|
|
|
if success:
|
|
print(f"{GREEN}Preflight PASSED.{RESET}")
|
|
sys.exit(0)
|
|
else:
|
|
print(f"{RED}Preflight FAILED.{RESET}")
|
|
if args.strict:
|
|
sys.exit(1)
|
|
# Non-strict mode (e.g. dev) might exit 0 or just warn
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|