Files
ComfyUI_Skills_OpenClaw/scripts/shared/runtime_config.py
科林_Cyril Pilgrim 425cdd0db4 feat(ui): refactor data structure and enhance configuration migration
Motivation:
The previous data structure for workflows and schemas lacked cohesion and was difficult to maintain manually. Additionally, a more robust and flexible migration system was needed to transfer skill configurations across different environments.

Implementation:
1. Unified the data hierarchy into a directory-based structure: 'data/<server>/<workflow>/'.
2. Enhanced 'transfer_manager.py' and 'transfer_bundle.py' for environmental-aware configuration migration.
3. Updated frontend JS/CSS and Flask routes to support the new directory-centric asset management.
4. Revamped English and Chinese READMEs to prioritize safe installation and clear configuration workflows.
2026-03-12 15:05:40 +08:00

156 lines
4.9 KiB
Python

from __future__ import annotations
import shutil
from pathlib import Path
from shared.config import (
CONFIG_PATH,
DATA_DIR,
DEFAULT_SERVER_ID,
SCHEMA_FILENAME,
WORKFLOW_FILENAME,
default_config,
default_server,
get_legacy_server_schemas_dir,
get_legacy_server_workflows_dir,
get_server_data_dir,
get_server_schema_path,
get_server_workflow_path,
)
from shared.json_utils import load_json, save_json
def migrate_legacy_config() -> None:
"""Detect old flat config format and migrate to the new multi-server format.
Old format:
{ "comfyui_server_url": "...", "output_dir": "..." }
New format:
{ "servers": [ { "id": "local", ... } ], "default_server": "local" }
Also migrates the old split workflow/schema storage into per-workflow folders under data/local/.
"""
if not CONFIG_PATH.exists():
return
config = load_json(CONFIG_PATH)
if not isinstance(config, dict):
return
# Already in new format
if "servers" in config:
return
# Detect legacy flat format
old_url = config.get("comfyui_server_url")
old_output = config.get("output_dir")
server = default_server()
if old_url:
server["url"] = old_url
if old_output:
server["output_dir"] = old_output
new_config = {
"servers": [server],
"default_server": DEFAULT_SERVER_ID,
}
save_json(CONFIG_PATH, new_config)
# Migrate data directories
migrate_workflow_storage_layout()
def _migrate_server_storage_layout(server_id: str) -> None:
server_dir = get_server_data_dir(server_id)
legacy_workflows_dir = get_legacy_server_workflows_dir(server_id)
legacy_schemas_dir = get_legacy_server_schemas_dir(server_id)
legacy_ids: set[str] = set()
if legacy_workflows_dir.exists():
legacy_ids.update(path.stem for path in legacy_workflows_dir.glob("*.json"))
if legacy_schemas_dir.exists():
legacy_ids.update(path.stem for path in legacy_schemas_dir.glob("*.json"))
for workflow_id in sorted(legacy_ids):
legacy_workflow_path = legacy_workflows_dir / f"{workflow_id}.json"
legacy_schema_path = legacy_schemas_dir / f"{workflow_id}.json"
workflow_path = get_server_workflow_path(server_id, workflow_id)
schema_path = get_server_schema_path(server_id, workflow_id)
if legacy_workflow_path.exists() and not workflow_path.exists():
workflow_path.parent.mkdir(parents=True, exist_ok=True)
shutil.move(str(legacy_workflow_path), str(workflow_path))
if legacy_schema_path.exists() and not schema_path.exists():
schema_path.parent.mkdir(parents=True, exist_ok=True)
shutil.move(str(legacy_schema_path), str(schema_path))
for legacy_dir in (legacy_workflows_dir, legacy_schemas_dir):
if legacy_dir.exists():
try:
legacy_dir.rmdir()
except OSError:
pass
# Remove empty workflow directories that may remain after migrations or deletes.
if server_dir.exists():
for workflow_dir in server_dir.iterdir():
if not workflow_dir.is_dir():
continue
if workflow_dir.name in {"workflows", "schemas"}:
continue
has_workflow = (workflow_dir / WORKFLOW_FILENAME).exists()
has_schema = (workflow_dir / SCHEMA_FILENAME).exists()
if not has_workflow and not has_schema:
try:
workflow_dir.rmdir()
except OSError:
pass
def migrate_workflow_storage_layout() -> None:
"""Migrate old split workflow/schema directories into per-workflow folders."""
if not DATA_DIR.exists():
return
_migrate_server_storage_layout(DEFAULT_SERVER_ID)
for server_dir in DATA_DIR.iterdir():
if not server_dir.is_dir():
continue
if server_dir.name in {"workflows", "schemas"}:
continue
_migrate_server_storage_layout(server_dir.name)
def get_runtime_config() -> dict[str, object]:
"""Load the full multi-server config, migrating from legacy format if needed."""
migrate_legacy_config()
migrate_workflow_storage_layout()
if not CONFIG_PATH.exists():
return default_config()
loaded = load_json(CONFIG_PATH)
if not isinstance(loaded, dict) or "servers" not in loaded:
return default_config()
return loaded
def get_server_by_id(server_id: str) -> dict[str, object] | None:
"""Look up a single server entry by its id."""
config = get_runtime_config()
for server in config.get("servers", []):
if isinstance(server, dict) and server.get("id") == server_id:
return server
return None
def get_default_server_id() -> str:
"""Return the default server id from config."""
config = get_runtime_config()
return str(config.get("default_server", DEFAULT_SERVER_ID))