Stop hanging after KiCad folder permission.

Apri progetto walked every nested file (HubAudio .history ~2000) so
onFilesChange never ran and Next stayed disabled. Read only kicad_pro,
sch, and pcb in the project dir; timeout to an error; enable Next when
.kicad_pro is in.
This commit is contained in:
2026-09-21 08:18:01 +02:00
parent a0b89365c2
commit 027546b0bd
5 changed files with 223 additions and 45 deletions
+85
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import json
import re
from pathlib import Path
import pytest
@@ -321,3 +322,87 @@ def test_real_hubaudio_kicad_pro_filename_and_folder_ingest(tmp_path: Path):
parts, _nets, fmt = parse_netlist_any(parsed.root)
assert fmt == "kicad_sch"
assert "U13" not in parts
# Mirrors periscope/src/frontend/src/lib/kicad-project-files.ts (folder walk + Next).
def _skip_walk_dir_name(name: str) -> bool:
n = name.rstrip("/").lower()
if not n or n.startswith("."):
return True
return bool(re.search(r"(-backups|\.pretty|3dmodels|__macosx|node_modules)$", n))
def _is_kicad_project_file_name(name: str) -> bool:
base = name.replace("\\", "/").rsplit("/", 1)[-1].lower()
return base.endswith((".kicad_pro", ".kicad_sch", ".kicad_pcb"))
def _skip_rel(rel: str) -> bool:
parts = [p for p in rel.replace("\\", "/").lower().split("/") if p]
return any(_skip_walk_dir_name(p) for p in parts)
def _details_step_ready(project_name: str, files: list[dict[str, str]]) -> bool:
if not project_name.strip():
return False
return any(_looks_like_kicad_pro(f.get("name", ""), f.get("webkitRelativePath", "")) for f in files)
def test_folder_walk_skips_history_and_keeps_project_dir_only():
"""Live 2.60.8 recursed handle.entries() into HubAudio/.history (~2000 files) so Next never enabled."""
names = [
"HubAudio.kicad_pro",
"HubAudio.kicad_sch",
"Codec.kicad_sch",
"HubAudio.kicad_pcb",
"HubAudio.kicad_prl",
"~HubAudio.kicad_pcb.lck",
".history",
".git",
"fp-lib-table",
]
kept = [n for n in names if _is_kicad_project_file_name(n)]
skipped_dirs = [n for n in names if _skip_walk_dir_name(n)]
assert kept == [
"HubAudio.kicad_pro",
"HubAudio.kicad_sch",
"Codec.kicad_sch",
"HubAudio.kicad_pcb",
]
assert ".history" in skipped_dirs and ".git" in skipped_dirs
assert _skip_rel("HubAudio/.history/objects/aa")
assert not _skip_rel("HubAudio/HubAudio.kicad_pro")
def test_details_next_enables_when_kicad_pro_is_in():
empty: list[dict[str, str]] = []
assert not _details_step_ready("HubAudio", empty)
assert not _details_step_ready(
"",
[{"name": "HubAudio.kicad_pro", "webkitRelativePath": "HubAudio/HubAudio.kicad_pro"}],
)
assert _details_step_ready(
"HubAudio",
[{"name": "HubAudio.kicad_pro", "webkitRelativePath": "HubAudio/HubAudio.kicad_pro"}],
)
assert _details_step_ready(
"HubAudio",
[{"name": "HubAudio", "webkitRelativePath": "HubAudio/HubAudio.kicad_pro"}],
)
@pytest.mark.skipif(not (HUBAUDIO / "HubAudio.kicad_pro").is_file(), reason="HubAudio tree not on disk")
def test_real_hubaudio_recursive_tree_is_huge_project_dir_is_small():
tree = list(HUBAUDIO.rglob("*"))
project_dir = [
p
for p in HUBAUDIO.iterdir()
if p.is_file() and _is_kicad_project_file_name(p.name)
]
assert len(tree) > 100
assert (HUBAUDIO / ".history").is_dir()
assert any(p.name == "HubAudio.kicad_pro" for p in project_dir)
assert any(p.name.endswith(".kicad_sch") for p in project_dir)
assert any(p.name.endswith(".kicad_pcb") for p in project_dir)
assert all(".history" not in str(p) for p in project_dir)
assert len(project_dir) < 40