From 60634a77eb5d04dc075bd349510e483e30490638 Mon Sep 17 00:00:00 2001 From: malmert Date: Sun, 1 Mar 2026 10:47:48 +0100 Subject: [PATCH] test script be --- backend/src/api/packet_scripting_api.py | 55 +++++++++++++++++++------ 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/backend/src/api/packet_scripting_api.py b/backend/src/api/packet_scripting_api.py index 4c4b084..728171d 100644 --- a/backend/src/api/packet_scripting_api.py +++ b/backend/src/api/packet_scripting_api.py @@ -19,7 +19,8 @@ import shutil import subprocess import time import logging -from typing import Optional, List, Dict, Any +from typing import Optional, List, Dict, Any, Tuple, DefaultDict +from collections import defaultdict from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Query from fastapi.responses import FileResponse, JSONResponse @@ -377,7 +378,7 @@ class ScriptWithStatus(ScriptInfo): - mappings: list of UnitMapping for that script - requirements_exists: whether a requirements file exists on disk """ - mappings: List[UnitMapping] = [] + mappings: List[UnitMapping] = Field(default_factory=list) requirements_exists: bool = False @@ -405,6 +406,35 @@ class OperationResult(BaseModel): python: Optional[str] = None +# ---------- Helper: group parsed units by script name ---------- +def _group_units_by_script(units: List[str]) -> Dict[str, List[Tuple[str, UnitParsed, bool]]]: + """ + Parse each unit and group by parsed.name (script name). Returns a dict: + { script_name: [ (svc, parsed, active), ... ], ... } + If parsed.name is None, attempt to extract script name from service string using pattern. + """ + groups: DefaultDict[str, List[Tuple[str, UnitParsed, bool]]] = defaultdict(list) + for svc in units: + parsed = parse_unit_execstart(svc) + try: + active = is_unit_active(svc) + except Exception: + active = False + + script_name = parsed.name + if not script_name: + # attempt to extract from service name like 'fw-script--q' + m = re.match(rf'^{re.escape(UNIT_PREFIX)}-(?P[A-Za-z0-9_.-]+)-q\d+$', svc) + if m: + script_name = m.group("name") + if not script_name: + # fallback: group under special key so they won't be lost; use svc as key + script_name = svc + + groups[script_name].append((svc, parsed, active)) + return groups + + # ---------- Endpoints ---------- # NOTE: combined status info into GET /scripts below (replaces separate /status & /{name}/status endpoints) @@ -420,27 +450,23 @@ def list_scripts_with_status() -> List[ScriptWithStatus]: """ out: List[ScriptWithStatus] = [] - # build a list of units once for efficiency + # build a list of units once for efficiency and group them by parsed script name all_units = list_fw_units() logger.debug("list_scripts_with_status: discovered %d fw units", len(all_units)) + grouped = _group_units_by_script(all_units) + # iterate script files on disk for fn in os.listdir(SCRIPT_DIR): if not fn.endswith(".py"): continue name = fn.rsplit(".", 1)[0] spath = os.path.join(SCRIPT_DIR, fn) - # find units matching this script - prefix = f"{UNIT_PREFIX}-{name}-q" mappings: List[UnitMapping] = [] - for svc in all_units: - if svc.startswith(prefix): - parsed = parse_unit_execstart(svc) - try: - active = is_unit_active(svc) - except Exception: - active = False - mappings.append(UnitMapping(service=svc, parsed=parsed, active=active)) + # take groups[name] if present + entries = grouped.get(name, []) + for svc, parsed, active in entries: + mappings.append(UnitMapping(service=svc, parsed=parsed, active=active)) req_exists = os.path.exists(requirements_path_for(name)) out.append(ScriptWithStatus(name=name, path=spath, mappings=mappings, requirements_exists=req_exists)) @@ -520,6 +546,9 @@ async def upload_script( logger.exception("Cleanup after pip failure partially failed for %s", name) # Return pip failure as 500 with message raise HTTPException(status_code=500, detail=f"pip install failed: {err_msg}") + else: + # If no requirements provided on upload, we simply keep uploaded script. (Per earlier conversation you can require requirements always if you want.) + logger.debug("No requirements uploaded with script %s", name) except HTTPException: raise except Exception as e: