Merge remote-tracking branch 'origin/sub_laptop_6' into sub_laptop_5

This commit is contained in:
2026-10-31 17:25:31 +09:00
3 changed files with 54 additions and 13 deletions
+31 -12
View File
@@ -340,24 +340,43 @@ def copies(project_root: str | Path) -> list[tuple[Path, dict[str, Any]]]:
return out
def used_folders(user: dict[str, Any]) -> set[str]:
def used_folders(user: dict[str, Any], project_root: str | Path | None = None) -> set[str]:
"""설계내역서 덮개 줄 · 거리이정표 운반 연결(251-5)이 잇는 서고 사본 폴더 +
일위대가 복사본(703-2 `@copy`)의 원본 사본."""
copies = [
str(lines["@copy"].get("from") or "")
for lines in (user.get("daega_cover") or {}).values()
일위대가 복사본(703-2 `@copy`)의 원본 사본 — 복사본의 복사본(`K:`)은 맨 처음 원본까지 ·
사전조합 원본(`C:참조`) = 그 참조를 담은 사본 폴더(`project_root` 줄 때)."""
covers = user.get("daega_cover") or {}
def origin(src: str) -> str:
seen: set[str] = set()
while src.startswith("K:") and src not in seen:
seen.add(src)
src = str(((covers.get(src) or {}).get("@copy") or {}).get("from") or "")
return src
srcs = {
origin(str(lines["@copy"].get("from") or ""))
for lines in covers.values()
if isinstance(lines, dict) and isinstance(lines.get("@copy"), dict)
]
return {
str(ref["lib"])
for row in ref_rows(user)
if isinstance(ref := row.get("ref"), dict) and ref.get("tab") == "dg" and ref.get("lib")
} | {src[2:] for src in copies if src.startswith("L:")}
}
pre = {src[2:] for src in srcs if src.startswith("C:")}
return (
{
str(ref["lib"])
for row in ref_rows(user)
if isinstance(ref := row.get("ref"), dict) and ref.get("tab") == "dg" and ref.get("lib")
}
| {src[2:] for src in srcs if src.startswith("L:")}
| {
folder.name
for folder, manifest in (copies(project_root) if pre and project_root else [])
if refs.ref_id((manifest.get("원본") or {}).get("참조") or {}) in pre
}
)
def prune(project_root: str | Path, user: dict[str, Any]) -> list[str]:
"""[저장] 뒤 — 줄이 안 잇는 사본 폴더를 지움(다시 고르면 새로 들여옴) · 지운 이름."""
keep = used_folders(user)
keep = used_folders(user, project_root)
base = library_dir(project_root)
gone = []
for child in sorted(base.iterdir()) if base.is_dir() else []:
+1 -1
View File
@@ -210,7 +210,7 @@ async def _demand(root: Path, draft: dict[str, Any] | None = None) -> list[str]:
"""단가 수요 키 — 연결된 사본 + 설계내역서 손 줄 로직(166-2) +
거리이정표 운반 연결(251-5) · draft = 화면 캐시(296 · 서고 사본 = 그 줄이 잇는 것만)."""
user = await asyncio.to_thread(calc_user, root, draft) # 운반 값 사본 먼저(263-2)
keep = None if draft is None else library.used_folders(user)
keep = None if draft is None else library.used_folders(user, root)
keys = await asyncio.to_thread(linked_resource_keys, root, keep)
hand = await asyncio.to_thread(sangeun.hand_resource_keys, user)
hand = [*hand, *added_keys(user.get("daega_cover"))] # 705-2 붙인 줄 이음
@@ -96,6 +96,28 @@ def test_서고_사본_원본_지킴():
assert library.used_folders(user) == {"combo@system@-@SS1"}
def test_사전조합_원본_복사본_사본_지킴(tmp_path):
"""통합 점검 — 사전조합(`C:참조`) 복사본 · 복사본의 복사본 = 원본 사본 폴더 지킴(업데이트 수요 · 저장 정리)."""
base = library.library_dir(tmp_path)
for name, ref in (
("precombo@personal@1-3@SC-000001", {"층": "personal", "주인": "1/3", "키": "SC-000001"}),
("precombo@personal@1-3@SC-000002", {"층": "personal", "주인": "1/3", "키": "SC-000002"}),
):
(base / name).mkdir(parents=True)
manifest = {"종류": "precombo", "원본": {"참조": ref}}
(base / name / "manifest.json").write_text(json.dumps(manifest), encoding="utf-8")
src = "C:참조|personal|1/3|SC-000001"
user = {
"daega_cover": {
"K:aa": {"@copy": {"from": src, "name": "복사"}},
"K:bb": {"@copy": {"from": "K:aa", "name": "복사의 복사"}},
}
}
assert library.used_folders(user) == set() # 폴더 모름 = 옛 꼴
assert library.used_folders(user, tmp_path) == {"precombo@personal@1-3@SC-000001"}
assert library.prune(tmp_path, user) == ["precombo@personal@1-3@SC-000002"]
# ── 내 자료집(개인 층 사전조합 · 임시 storage) ─────────────────────────────