feat(esp32): scope ESP-IDF resolution to the project's SAVED library manifest
Adds the get_project_libraries hook: the compile route reads a saved project's declared library manifest (by project_id) and uses it as the ESP-IDF resolution scope, preferring it over the client-sent manifest. So a saved project always compiles against only its own declared libraries — never another user's, or another project's, stray install in the shared dir — authoritatively from the server, independent of frontend wiring. Client-sent manifest still used for unsaved examples; None/empty → legacy scan-all. Overlay fills the hook in register_pro; OSS default is no-op (None).
This commit is contained in:
parent
4a21c4f938
commit
b7954fa8c5
|
|
@ -8,7 +8,7 @@ from typing import Any
|
|||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.hooks import get_current_user_id, record_compile
|
||||
from app.core.hooks import get_current_user_id, get_project_libraries, record_compile
|
||||
from app.services.arduino_cli import ArduinoCLIService
|
||||
from app.services.espidf_compiler import espidf_compiler
|
||||
|
||||
|
|
@ -215,12 +215,23 @@ async def _run_compile(
|
|||
[f.model_dump() for f in request.spiffs_files]
|
||||
if request.spiffs_files else None
|
||||
)
|
||||
# Library manifest = ESP-IDF resolution SCOPE. Prefer the manifest SAVED
|
||||
# with the project (authoritative, read server-side from the project
|
||||
# record) so a reloaded project always scopes to its own libraries
|
||||
# regardless of what the client sends; fall back to the manifest the
|
||||
# client sent (unsaved examples). None/empty → legacy scan-all.
|
||||
allowed_libraries = None
|
||||
project_libs = await get_project_libraries(request.project_id)
|
||||
if project_libs:
|
||||
allowed_libraries = set(project_libs)
|
||||
elif request.libraries:
|
||||
allowed_libraries = set(request.libraries)
|
||||
result = await espidf_compiler.compile(
|
||||
files, request.board_fqbn,
|
||||
progress_callback=progress_callback,
|
||||
board_options=request.board_options,
|
||||
spiffs_files=spiffs_dicts,
|
||||
allowed_libraries=set(request.libraries) if request.libraries is not None else None,
|
||||
allowed_libraries=allowed_libraries,
|
||||
)
|
||||
return CompileResponse(
|
||||
success=result["success"],
|
||||
|
|
|
|||
|
|
@ -103,6 +103,36 @@ async def get_current_user_id(request: Request) -> Optional[str]: # FastAPI dep
|
|||
return None
|
||||
|
||||
|
||||
# ── get_project_libraries ─────────────────────────────────────────────────────
|
||||
# Returns the declared library manifest (list of library names) SAVED with a
|
||||
# project. The ESP-IDF compiler uses it as the resolution SCOPE so a project
|
||||
# only merges its own declared libraries — never another user's, or another
|
||||
# project's, stray install in the shared library dir. Sourced authoritatively
|
||||
# from the project record (not the client), so it is robust regardless of what
|
||||
# the frontend sends. Returns None for an unknown project, an empty manifest,
|
||||
# or when no overlay is loaded (→ legacy scan-all).
|
||||
|
||||
GetProjectLibrariesHook = Callable[[str], Awaitable[Optional[list[str]]]]
|
||||
|
||||
_get_project_libraries_hook: Optional[GetProjectLibrariesHook] = None
|
||||
|
||||
|
||||
def register_get_project_libraries(hook: GetProjectLibrariesHook) -> None:
|
||||
"""Install the project-manifest resolver. Called by overlays in register_pro."""
|
||||
global _get_project_libraries_hook
|
||||
_get_project_libraries_hook = hook
|
||||
|
||||
|
||||
async def get_project_libraries(project_id: Optional[str]) -> Optional[list[str]]:
|
||||
if _get_project_libraries_hook is None or not project_id:
|
||||
return None
|
||||
try:
|
||||
return await _get_project_libraries_hook(project_id)
|
||||
except Exception:
|
||||
logger.exception("get_project_libraries hook failed (treating as no manifest)")
|
||||
return None
|
||||
|
||||
|
||||
# ── lifespan startup ──────────────────────────────────────────────────────────
|
||||
# Overlays that need to run async setup during FastAPI lifespan (DB init,
|
||||
# table creation, legacy column migrations, etc.) register a coroutine here.
|
||||
|
|
|
|||
Loading…
Reference in New Issue