"""Regenera el appicon.ico de todas las apps C++ que declaren bloque icon: en su app.md.""" import os import sys from pathlib import Path from typing import Optional import yaml sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from infra.generate_app_icon import generate_app_icon def _find_registry_root() -> Path: env_root = os.environ.get("FN_REGISTRY_ROOT") if env_root: return Path(env_root).resolve() current = Path(__file__).resolve() for parent in current.parents: if (parent / "registry.db").exists(): return parent raise FileNotFoundError("registry.db no encontrado; define FN_REGISTRY_ROOT") def _read_frontmatter(md_path: Path) -> Optional[dict]: text = md_path.read_text(encoding="utf-8") if not text.startswith("---"): return None end = text.find("\n---", 3) if end < 0: return None try: return yaml.safe_load(text[3:end]) except yaml.YAMLError: return None def _iter_cpp_app_mds(root: Path): for pattern in ("apps/*/app.md", "projects/*/apps/*/app.md"): for md in sorted(root.glob(pattern)): fm = _read_frontmatter(md) if not fm or fm.get("lang") != "cpp": continue yield md, fm def regenerate_app_icons(only: Optional[list[str]] = None) -> dict: """Recorre apps C++ con bloque icon: en su frontmatter y regenera appicon.ico. Args: only: Lista opcional de nombres de app a filtrar (campo `name`). Si None, procesa todas las apps C++ con `icon:` declarado. Returns: dict con keys: ok (list[str]), skipped (list[dict]), failed (list[dict]). """ root = _find_registry_root() ok, skipped, failed = [], [], [] for md, fm in _iter_cpp_app_mds(root): name = fm.get("name", md.parent.name) if only and name not in only: continue icon = fm.get("icon") if not icon or not isinstance(icon, dict): skipped.append({"name": name, "reason": "no icon: block"}) continue phosphor = icon.get("phosphor") accent = icon.get("accent") if not phosphor or not accent: skipped.append({"name": name, "reason": "icon: missing phosphor/accent"}) continue out_ico = md.parent / "appicon.ico" try: generate_app_icon( phosphor_icon_name=phosphor, accent_hex=accent, out_ico_path=str(out_ico), ) ok.append(name) except Exception as e: failed.append({"name": name, "error": str(e)}) return {"ok": ok, "skipped": skipped, "failed": failed} if __name__ == "__main__": only = sys.argv[1:] or None result = regenerate_app_icons(only=only) for name in result["ok"]: print(f"OK {name}") for s in result["skipped"]: print(f"SKIP {s['name']}: {s['reason']}") for f in result["failed"]: print(f"FAIL {f['name']}: {f['error']}") sys.exit(1 if result["failed"] else 0)