Files
AI_Printer/tools/esptool-factory/factory_common/idf_artifacts.py

95 lines
2.6 KiB
Python

from __future__ import annotations
import json
import shutil
from pathlib import Path
from typing import Iterable
def _load_json(path: Path) -> dict:
try:
raw = path.read_text(encoding="utf-8")
except OSError:
return {}
try:
data = json.loads(raw)
except json.JSONDecodeError:
return {}
return data if isinstance(data, dict) else {}
def _from_build(build_dir: Path, relative_path: object) -> Path | None:
if not isinstance(relative_path, str) or not relative_path.strip():
return None
candidate = build_dir / relative_path
if candidate.exists() and candidate.is_file():
return candidate
return None
def _collect_from_flasher_args(build_dir: Path) -> dict[str, Path]:
result: dict[str, Path] = {}
data = _load_json(build_dir / "flasher_args.json")
flash_files = data.get("flash_files")
if isinstance(flash_files, dict):
for rel in flash_files.values():
path = _from_build(build_dir, rel)
if path is not None:
result[path.name] = path
for key in ("bootloader", "app", "partition-table"):
section = data.get(key)
if not isinstance(section, dict):
continue
path = _from_build(build_dir, section.get("file"))
if path is not None:
result[path.name] = path
return result
def _find_in_build_tree(build_dir: Path, name: str) -> Path | None:
direct = build_dir / name
if direct.exists() and direct.is_file():
return direct
for path in build_dir.glob(f"**/{name}"):
if path.is_file():
return path
return None
def sync_bins_from_idf_build(
bin_dir: Path,
required_bins: Iterable[str],
build_dir: Path,
*,
overwrite: bool = False,
) -> list[tuple[Path, Path]]:
if not build_dir.exists() or not build_dir.is_dir():
return []
build_map = _collect_from_flasher_args(build_dir)
copied: list[tuple[Path, Path]] = []
seen: set[str] = set()
for raw_name in required_bins:
name = str(raw_name).strip()
if not name or name in seen:
continue
seen.add(name)
target = bin_dir / name
if target.exists() and not overwrite:
continue
source = build_map.get(name)
if source is None:
source = _find_in_build_tree(build_dir, name)
if source is None:
continue
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, target)
copied.append((source, target))
return copied