Add local 1C runtime adapter execution for CF files
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
|
||||
@@ -134,7 +138,19 @@ async def runtime_import(request: RuntimeImportRequest) -> RuntimeImportResponse
|
||||
],
|
||||
dump_plan=dump_plan,
|
||||
)
|
||||
raise HTTPException(status_code=501, detail="Designer execution runner is not implemented yet")
|
||||
if source_kind in {"CF_FILE", "CFE_FILE"}:
|
||||
if not request.path:
|
||||
raise HTTPException(status_code=400, detail="path is required for CF/CFE import")
|
||||
dump_root, execution_logs = _convert_local_cf_or_cfe_to_metadata_dump(request, platform_status)
|
||||
return RuntimeImportResponse(
|
||||
status="normalized",
|
||||
mode=mode.value,
|
||||
platform_found=True,
|
||||
normalized_project=normalize_one_c_project(dump_root, project_id=request.project_id),
|
||||
diagnostics=[*platform_status.diagnostics, *execution_logs],
|
||||
dump_plan=dump_plan,
|
||||
)
|
||||
raise HTTPException(status_code=501, detail=f"Designer execution runner is not implemented yet for {source_kind}")
|
||||
|
||||
|
||||
def _mode() -> RuntimeMode:
|
||||
@@ -217,6 +233,105 @@ def _designer_dump_plan(request: RuntimeImportRequest) -> list[str]:
|
||||
return plan
|
||||
|
||||
|
||||
def _convert_local_cf_or_cfe_to_metadata_dump(
|
||||
request: RuntimeImportRequest,
|
||||
platform_status: RuntimePlatformResponse,
|
||||
) -> tuple[Path, list[str]]:
|
||||
source_kind = request.source_kind.upper()
|
||||
payload_path = Path(request.path or "")
|
||||
if not payload_path.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Path not found: {request.path}")
|
||||
if not platform_status.designer_path:
|
||||
raise HTTPException(status_code=503, detail="1C Designer CLI path is not configured")
|
||||
export_root = Path(tempfile.mkdtemp(prefix=f"sfera-runtime-{request.project_id or 'project'}-"))
|
||||
builder_infobase = export_root / "builder-infobase"
|
||||
logs: list[str] = []
|
||||
|
||||
_run_designer_command(
|
||||
platform_status.designer_path,
|
||||
["CREATEINFOBASE", f"File={builder_infobase};"],
|
||||
export_root / "create-builder-infobase.log",
|
||||
"1C CREATEINFOBASE for local CF/CFE conversion",
|
||||
)
|
||||
builder_args = ["/F", str(builder_infobase)]
|
||||
artifacts_root = export_root / "artifacts"
|
||||
artifacts_root.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(payload_path, artifacts_root / payload_path.name)
|
||||
|
||||
if source_kind == "CF_FILE":
|
||||
_run_designer_command(
|
||||
platform_status.designer_path,
|
||||
[*builder_args, "/LoadCfg", str(payload_path)],
|
||||
export_root / "designer-loadcfg-local-cf.log",
|
||||
"1C LoadCfg local CF",
|
||||
)
|
||||
metadata_root = export_root / "configuration"
|
||||
metadata_root.mkdir(parents=True, exist_ok=True)
|
||||
_run_designer_command(
|
||||
platform_status.designer_path,
|
||||
[*builder_args, "/DumpConfigToFiles", str(metadata_root), "-Format", "Hierarchical"],
|
||||
export_root / "designer-dumpconfigtofiles-local-cf.log",
|
||||
"1C DumpConfigToFiles from local CF",
|
||||
)
|
||||
shutil.copyfile(payload_path, metadata_root / payload_path.name)
|
||||
logs.append("Local .cf converted to metadata export for server-side parsing.")
|
||||
return export_root, logs
|
||||
|
||||
if source_kind == "CFE_FILE":
|
||||
extension_name = str(request.metadata.get("one_c_extension") or payload_path.stem).strip()
|
||||
if not extension_name:
|
||||
raise HTTPException(status_code=400, detail="Extension name is required for local CFE conversion.")
|
||||
_run_designer_command(
|
||||
platform_status.designer_path,
|
||||
[*builder_args, "/LoadCfg", str(payload_path), "-Extension", extension_name, "/UpdateDBCfg"],
|
||||
export_root / "designer-loadcfg-local-cfe.log",
|
||||
"1C LoadCfg local CFE",
|
||||
)
|
||||
metadata_root = export_root / "extension"
|
||||
metadata_root.mkdir(parents=True, exist_ok=True)
|
||||
_run_designer_command(
|
||||
platform_status.designer_path,
|
||||
[*builder_args, "/DumpConfigToFiles", str(metadata_root), "-Format", "Hierarchical", "-Extension", extension_name],
|
||||
export_root / "designer-dumpconfigtofiles-local-cfe.log",
|
||||
"1C DumpConfigToFiles from local CFE",
|
||||
)
|
||||
shutil.copyfile(payload_path, metadata_root / payload_path.name)
|
||||
logs.append("Local .cfe converted to metadata export for server-side parsing.")
|
||||
return export_root, logs
|
||||
|
||||
raise HTTPException(status_code=400, detail=f"Unsupported local 1C source: {source_kind}")
|
||||
|
||||
|
||||
def _designer_process_command(designer_path: str, arguments: list[str]) -> list[str]:
|
||||
path = Path(designer_path)
|
||||
if path.suffix.casefold() == ".py":
|
||||
return [sys.executable, designer_path, *arguments]
|
||||
return [designer_path, *arguments]
|
||||
|
||||
|
||||
def _run_designer_command(designer_path: str, arguments: list[str], log_path: Path, action_title: str, timeout_seconds: int = 180) -> None:
|
||||
command = _designer_process_command(designer_path, arguments)
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=timeout_seconds,
|
||||
check=False,
|
||||
)
|
||||
output = completed.stdout or ""
|
||||
log_path.write_text(output, encoding="utf-8")
|
||||
if completed.returncode != 0:
|
||||
tail = output[-4000:] if output else ""
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"{action_title} failed with code {completed.returncode}. {tail}".strip(),
|
||||
)
|
||||
|
||||
|
||||
def _redact_connection_string(value: str) -> str:
|
||||
sensitive_keys = {"pwd", "password", "пароль"}
|
||||
chunks: list[str] = []
|
||||
|
||||
Reference in New Issue
Block a user