nested_pages: Katalogtiefe 1 durchgesetzt, layout:-dir validiert, move raeumt geleerte Verzeichnisse - die drei #57-Seiten hochgezogen (schliesst #57)
Files changed: - CHANGES.md - VERSION - kb/CONTRACT.md - kb/entities/projects/kfchou/wiki-skills.md - kb/entities/projects/llm-wiki-skills.md - kb/entities/projects/vanillaflava/wiki-skills-vanillaflava.md - kb/entities/projects/wiki-skills-vanillaflava.md - kb/entities/projects/wiki-skills.md - kb/entities/projects/yugasun/llm-wiki-skills.md - kb/log.md - tools/CONTRACT.md - tools/chemenu/commands/index_build.py - tools/chemenu/commands/page_ops.py - tools/chemenu/kb_scan.py - tools/chemenu/lint_core.py - tools/chemenu/tests/test_index_build.py - tools/chemenu/tests/test_kb_scan.py - tools/chemenu/tests/test_lint.py - tools/chemenu/tests/test_page_ops.py - tools/chemenu/tests/test_type_resolver.py - tools/chemenu/type_resolver.py
This commit is contained in:
1 parent
9e414319b8
commit
251e597c63
18 files changed
+331
-10
No files matched your search
@@ -28,7 +28,7 @@ from chemenu import config
|
||||
from chemenu.commands._util import rel_path, success
|
||||
from chemenu.kb_collections import iter_kb_collections
|
||||
from chemenu.page import Page
|
||||
from chemenu.kb_scan import GENERATED_INDEX, load_kb_pages
|
||||
from chemenu.kb_scan import GENERATED_INDEX, find_nested_pages, load_kb_pages
|
||||
from chemenu.type_resolver import resolver
|
||||
|
||||
app = typer.Typer(help="Manage the generated wiki catalog (kb/index.md + per-collection INDEX.md).")
|
||||
@@ -302,6 +302,17 @@ def index_rebuild(
|
||||
False, "--dry-run", help="Print what would be written instead of writing it"
|
||||
),
|
||||
):
|
||||
# Reported, not refused (#57 decision): a nested page still gets a catalog
|
||||
# written for it, just a wrong one (folded into its area, no distinct
|
||||
# location of its own) - `wikitool lint`'s `nested_pages` is the hard
|
||||
# finding this warning previews.
|
||||
for title, page, depth in find_nested_pages(config.KB_DIR, load_kb_pages(config.KB_DIR)):
|
||||
typer.echo(
|
||||
f"WARNING: [[{title}]] is {depth} directories below its collection "
|
||||
f"({rel_path(page.path.parent)}) - the catalog folds it into the area silently. "
|
||||
"See `wikitool lint`'s Nested Pages finding."
|
||||
)
|
||||
|
||||
plan = plan_index(config.KB_DIR)
|
||||
stale = stale_shards(config.KB_DIR, plan)
|
||||
|
||||
|
||||
@@ -381,6 +381,24 @@ def rm_command(
|
||||
)
|
||||
|
||||
|
||||
def _rmdir_if_emptied(directory: Path) -> bool:
|
||||
"""Remove `directory` if the move that just vacated it left it empty.
|
||||
|
||||
Symmetric with the `target_dir.mkdir(parents=True, exist_ok=True)` a move
|
||||
does on the way in: without this, a hand-nested directory (#57) survives
|
||||
its own fix, and a directory-shape test would still find it after every
|
||||
page under it moved out. Never touches `kb/` itself, and only ever a
|
||||
directory this move just emptied - never a pre-existing empty one it
|
||||
happens to pass through.
|
||||
"""
|
||||
if directory.resolve() == config.KB_DIR.resolve():
|
||||
return False
|
||||
if not directory.is_dir() or any(directory.iterdir()):
|
||||
return False
|
||||
directory.rmdir()
|
||||
return True
|
||||
|
||||
|
||||
def move_command(
|
||||
page_title: Optional[str] = typer.Option(
|
||||
None, "--page", help="Exact title of the page to move to its computed location"
|
||||
@@ -431,7 +449,9 @@ def move_command(
|
||||
|
||||
moved: list[str] = []
|
||||
failed: list[str] = list(collisions)
|
||||
removed_dirs = 0
|
||||
for title, page, target_dir, new_path in planned:
|
||||
old_dir = page.path.parent
|
||||
try:
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
page.path.rename(new_path)
|
||||
@@ -440,13 +460,17 @@ def move_command(
|
||||
continue
|
||||
moved.append(title)
|
||||
typer.echo(f" moved '{title}' -> {rel_path(new_path)}")
|
||||
if _rmdir_if_emptied(old_dir):
|
||||
removed_dirs += 1
|
||||
typer.echo(f" removed empty {rel_path(old_dir)}")
|
||||
|
||||
if failed:
|
||||
fail(
|
||||
f"Moved {len(moved)}/{len(candidates)} page(s) before a failure: {', '.join(failed)}. "
|
||||
"Safe to retry - `move --reconcile` only re-moves what is still misplaced."
|
||||
)
|
||||
success(f"Moved {len(moved)} page(s). Run `wikitool index rebuild` next.")
|
||||
removed_note = f", removed {removed_dirs} emptied dir(s)" if removed_dirs else ""
|
||||
success(f"Moved {len(moved)} page(s){removed_note}. Run `wikitool index rebuild` next.")
|
||||
return
|
||||
|
||||
target = pages.get(page_title)
|
||||
@@ -473,6 +497,10 @@ def move_command(
|
||||
typer.echo(f"[dry-run] would move {rel_path(target.path)} -> {rel_path(new_path)}")
|
||||
return
|
||||
|
||||
old_dir = target.path.parent
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
target.path.rename(new_path)
|
||||
success(f"Moved '{page_title}' -> {rel_path(new_path)}. Run `wikitool index rebuild` next.")
|
||||
removed_note = ""
|
||||
if _rmdir_if_emptied(old_dir):
|
||||
removed_note = f" Removed emptied {rel_path(old_dir)}."
|
||||
success(f"Moved '{page_title}' -> {rel_path(new_path)}.{removed_note} Run `wikitool index rebuild` next.")
|
||||
Reference in new issue
Block a user