mirror of
https://github.com/blw1138/cross-py-builder.git
synced 2026-09-07 21:41:09 -05:00
Add controller with web UI and retire CLI
- Add ctrl/ package: Flask app (waitress), SQLite job store, background scheduler that probes configured workers, dispatches via /upload and /checkout_git, fetches artifacts, and serves a single-page UI - Supporting API: /api/jobs (create/list/detail/cancel), /api/workers, /api/capabilities, artifact download, and SSE log stream - Workers keep the existing HTTP API; add /progress/<job_id> endpoint and per-step build tracking for live status - Retire agent_manager.py and the cross-py-builder CLI; controller UI is the primary frontend - Record design in DESIGN.md; add waitress dependency Note: /progress is exposed on the worker but the synchronous /upload and /checkout endpoints block until a build completes, so per-step worker progress is not yet relayed live in the UI. Live streaming needs an async-start worker endpoint as a follow-up.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
def _get_bool(name, default=False):
|
||||
val = os.environ.get(name)
|
||||
if val is None:
|
||||
return default
|
||||
return val.strip().lower() in ("1", "true", "yes", "on")
|
||||
|
||||
|
||||
def _get_json_list(name, default=None):
|
||||
raw = os.environ.get(name)
|
||||
if not raw:
|
||||
return list(default or [])
|
||||
try:
|
||||
value = json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
raise ValueError(f"{name} must be a JSON array string")
|
||||
if not isinstance(value, list):
|
||||
raise ValueError(f"{name} must be a JSON array")
|
||||
return value
|
||||
|
||||
|
||||
def _get_int(name, default):
|
||||
raw = os.environ.get(name)
|
||||
if raw is None:
|
||||
return default
|
||||
return int(raw)
|
||||
|
||||
|
||||
DATA_DIR = os.environ.get("CROSS_PY_DATA", os.path.join(os.path.dirname(os.path.dirname(__file__)), "data"))
|
||||
DB_PATH = os.environ.get("CROSS_PY_DB", os.path.join(DATA_DIR, "jobs.db"))
|
||||
BUILDS_DIR = os.environ.get("CROSS_PY_BUILDS", os.path.join(DATA_DIR, "builds"))
|
||||
PORT = _get_int("CROSS_PY_PORT", 8080)
|
||||
|
||||
# Static worker list: JSON array of "host:port" strings.
|
||||
WORKERS = _get_json_list("CROSS_PY_WORKERS")
|
||||
|
||||
# One job at a time by default; raise to allow parallel dispatches to distinct workers.
|
||||
MAX_CONCURRENT = _get_int("CROSS_PY_MAX_CONCURRENT", 1)
|
||||
|
||||
# Per-request timeouts (seconds) for talking to workers.
|
||||
WORKER_STATUS_TIMEOUT = _get_int("CROSS_PY_WORKER_STATUS_TIMEOUT", 5)
|
||||
WORKER_BUILD_TIMEOUT = _get_int("CROSS_PY_WORKER_BUILD_TIMEOUT", 3600)
|
||||
|
||||
# Interval (seconds) for the scheduler loop.
|
||||
SCHEDULER_INTERVAL = 1.0
|
||||
|
||||
# Debug mode uses Flask's dev server; otherwise serve through waitress.
|
||||
DEBUG = _get_bool("CROSS_PY_DEBUG", False)
|
||||
|
||||
|
||||
def ensure_dirs():
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
os.makedirs(BUILDS_DIR, exist_ok=True)
|
||||
Reference in New Issue
Block a user