Skip to content

Commit 2ef4415

Browse files
committed
Refactor BCASL plugin management and execution
1 parent 3ab3630 commit 2ef4415

3 files changed

Lines changed: 601 additions & 524 deletions

File tree

bcasl/Loader.py

Lines changed: 97 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,97 @@ def _run_bcasl_sync(
300300
)
301301

302302

303+
def _get_plugins_dir() -> Path:
304+
try:
305+
return Path(__file__).resolve().parents[1] / "Plugins"
306+
except Exception:
307+
return Path("Plugins")
308+
309+
310+
def _resolve_ordered_plugin_ids(
311+
plugin_ids: list[str], meta_map: dict[str, dict[str, Any]], cfg: dict[str, Any]
312+
) -> list[str]:
313+
order: list[str] = []
314+
try:
315+
order = cfg.get("plugin_order", []) if isinstance(cfg, dict) else []
316+
order = [pid for pid in order if pid in plugin_ids]
317+
except Exception:
318+
order = []
319+
if not order:
320+
try:
321+
order = [pid for pid in compute_tag_order(meta_map) if pid in plugin_ids]
322+
except Exception:
323+
order = sorted(plugin_ids)
324+
remaining = [pid for pid in plugin_ids if pid not in order]
325+
return order + remaining
326+
327+
328+
def _plugin_enabled(plugins_cfg: dict[str, Any], pid: str) -> bool:
329+
try:
330+
pentry = plugins_cfg.get(pid, {})
331+
if isinstance(pentry, dict):
332+
return bool(pentry.get("enabled", True))
333+
if isinstance(pentry, bool):
334+
return bool(pentry)
335+
except Exception:
336+
pass
337+
return True
338+
339+
340+
def _build_plugin_item(
341+
pid: str,
342+
meta: dict[str, Any],
343+
plugins_cfg: dict[str, Any],
344+
Qt,
345+
QListWidgetItem,
346+
) -> Any:
347+
# Importer les fonctions de tagging pour afficher les phases
348+
from .tagging import get_tag_phase_name
349+
350+
label = meta.get("name") or pid
351+
ver = meta.get("version") or ""
352+
tags = meta.get("tags") or []
353+
354+
phase_name = get_tag_phase_name(tags[0]) if tags else ""
355+
text = f"{label} ({pid})" + (f" v{ver}" if ver else "")
356+
if phase_name:
357+
text += f" [Phase: {phase_name}]"
358+
359+
item = QListWidgetItem(text)
360+
361+
# Tooltip avec description, tags et requirements
362+
try:
363+
desc = meta.get("description") or ""
364+
tooltip = desc
365+
if tags:
366+
tooltip += f"\n\nTags: {', '.join(tags)}"
367+
reqs = meta.get("requirements", [])
368+
if reqs:
369+
tooltip += f"\n\nRequirements:\n" + "\n".join(f" • {req}" for req in reqs)
370+
if tooltip:
371+
item.setToolTip(tooltip)
372+
except Exception:
373+
pass
374+
375+
enabled = _plugin_enabled(plugins_cfg, pid)
376+
try:
377+
item.setData(0x0100, pid)
378+
except Exception:
379+
pass
380+
if Qt is not None:
381+
item.setFlags(
382+
item.flags()
383+
| Qt.ItemIsUserCheckable
384+
| Qt.ItemIsEnabled
385+
| Qt.ItemIsSelectable
386+
| Qt.ItemIsDragEnabled
387+
)
388+
item.setCheckState(
389+
Qt.CheckState.Checked if enabled else Qt.CheckState.Unchecked
390+
)
391+
return item
392+
393+
303394
def _load_workspace_config(workspace_root: Path) -> dict[str, Any]:
304395
"""Charge bcasl.yml si présent, sinon génère une config par défaut minimale et l'écrit.
305396
@@ -326,8 +417,7 @@ def _read_yml(p: Path) -> dict[str, Any]:
326417
# 2) Génération défaut avec fusion ARK
327418
default_cfg: dict[str, Any] = {}
328419
try:
329-
repo_root = Path(__file__).resolve().parents[1]
330-
Plugins_dir = repo_root / "Plugins"
420+
Plugins_dir = _get_plugins_dir()
331421
detected_plugins: dict[str, Any] = {}
332422
meta_map = _discover_bcasl_meta(Plugins_dir) if Plugins_dir.exists() else {}
333423
if meta_map:
@@ -588,8 +678,7 @@ def open_bc_loader_dialog(self) -> None: # UI minimale
588678
)
589679
return
590680
workspace_root = Path(self.workspace_dir).resolve()
591-
repo_root = Path(__file__).resolve().parents[1]
592-
Plugins_dir = repo_root / "Plugins"
681+
Plugins_dir = _get_plugins_dir()
593682
if not Plugins_dir.exists():
594683
QMessageBox.information(
595684
self,
@@ -643,89 +732,10 @@ def open_bc_loader_dialog(self) -> None: # UI minimale
643732
lst.setSelectionMode(QAbstractItemView.SingleSelection)
644733
lst.setDragDropMode(QAbstractItemView.InternalMove)
645734

646-
# Ordre initial: plugin_order si présent; sinon heuristique par tags; sinon alphabétique
647-
order = []
648-
try:
649-
order = cfg.get("plugin_order", []) if isinstance(cfg, dict) else []
650-
order = [pid for pid in order if pid in plugin_ids]
651-
except Exception:
652-
order = []
653-
if not order:
654-
try:
655-
order = [
656-
pid for pid in compute_tag_order(meta_map) if pid in plugin_ids
657-
]
658-
except Exception:
659-
order = sorted(plugin_ids)
660-
661-
remaining = [pid for pid in plugin_ids if pid not in order]
662-
ordered_ids = order + remaining
663-
664-
# Importer les fonctions de tagging pour afficher les phases
665-
from .tagging import get_tag_phase_name
666-
735+
ordered_ids = _resolve_ordered_plugin_ids(plugin_ids, meta_map, cfg)
667736
for pid in ordered_ids:
668737
meta = meta_map.get(pid, {})
669-
label = meta.get("name") or pid
670-
ver = meta.get("version") or ""
671-
tags = meta.get("tags") or []
672-
673-
# Déterminer la phase d'exécution
674-
phase_name = ""
675-
if tags:
676-
# Utiliser le premier tag pour déterminer la phase
677-
phase_name = get_tag_phase_name(tags[0])
678-
679-
# Construire le texte avec la phase
680-
text = f"{label} ({pid})" + (f" v{ver}" if ver else "")
681-
if phase_name:
682-
text += f" [Phase: {phase_name}]"
683-
684-
item = QListWidgetItem(text)
685-
# Tooltip avec description, tags et requirements
686-
try:
687-
desc = meta.get("description") or ""
688-
tooltip = desc
689-
if tags:
690-
tooltip += f"\n\nTags: {', '.join(tags)}"
691-
692-
# Ajouter les requirements du plugin depuis meta_map
693-
reqs = meta.get("requirements", [])
694-
if reqs:
695-
tooltip += f"\n\nRequirements:\n" + "\n".join(
696-
f" • {req}" for req in reqs
697-
)
698-
699-
if tooltip:
700-
item.setToolTip(tooltip)
701-
except Exception:
702-
pass
703-
# Etat
704-
enabled = True
705-
try:
706-
pentry = plugins_cfg.get(pid, {})
707-
if isinstance(pentry, dict):
708-
enabled = bool(pentry.get("enabled", True))
709-
elif isinstance(pentry, bool):
710-
enabled = pentry
711-
except Exception:
712-
pass
713-
try:
714-
item.setData(0x0100, pid)
715-
except Exception:
716-
pass
717-
if Qt is not None:
718-
item.setFlags(
719-
item.flags()
720-
| Qt.ItemIsUserCheckable
721-
| Qt.ItemIsEnabled
722-
| Qt.ItemIsSelectable
723-
| Qt.ItemIsDragEnabled
724-
)
725-
if Qt is not None:
726-
item.setCheckState(
727-
Qt.CheckState.Checked if enabled else Qt.CheckState.Unchecked
728-
)
738+
item = _build_plugin_item(pid, meta, plugins_cfg, Qt, QListWidgetItem)
729739
lst.addItem(item)
730740
layout.addWidget(lst)
731741

@@ -867,8 +877,7 @@ def run_pre_compile_async(self, on_done: Optional[callable] = None) -> None:
867877
pass
868878
return
869879
workspace_root = Path(self.workspace_dir).resolve()
870-
repo_root = Path(__file__).resolve().parents[1]
871-
Plugins_dir = repo_root / "Plugins"
880+
Plugins_dir = _get_plugins_dir()
872881

873882
cfg = _load_workspace_config(workspace_root)
874883
plugin_timeout = _resolve_plugin_timeout(cfg)
@@ -960,8 +969,7 @@ def run_pre_compile(self) -> Optional[object]:
960969
if not getattr(self, "workspace_dir", None):
961970
return None
962971
workspace_root = Path(self.workspace_dir).resolve()
963-
repo_root = Path(__file__).resolve().parents[1]
964-
Plugins_dir = repo_root / "Plugins"
972+
Plugins_dir = _get_plugins_dir()
965973

966974
cfg = _load_workspace_config(workspace_root)
967975
plugin_timeout = _resolve_plugin_timeout(cfg)

0 commit comments

Comments
 (0)