88 lines
3.8 KiB
Python
88 lines
3.8 KiB
Python
"""
|
|
python3 -m docgen scaffold <docgen.toml> [--only NAME ...]
|
|
python3 -m docgen scaffold <docgen.toml> --list # print the spots, write nothing
|
|
|
|
Write an empty note for every spot a document has — the document's top and end,
|
|
each book's top, what came in, the page index, every page, every step, every
|
|
API call, what came out — so the ids are listed rather than guessed.
|
|
|
|
Never overwrites: a spot that already has a note is left alone, so running it
|
|
again after the sources change only adds the spots that are new. A stub is a
|
|
single HTML comment and renders nothing until somebody writes below it.
|
|
|
|
Extraction and page structure only — nothing is drawn and no output is written.
|
|
"""
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
from .common import PROG, Abort
|
|
|
|
|
|
def main(argv) -> int:
|
|
p = argparse.ArgumentParser(prog=f"{PROG} scaffold")
|
|
p.add_argument("config", type=Path, nargs="?", default=Path("docgen.toml"))
|
|
p.add_argument("--only", action="append", default=[], metavar="NAME",
|
|
help="Just these books. Repeatable.")
|
|
p.add_argument("--list", action="store_true",
|
|
help="Print every spot a note can be filed under, and write nothing — "
|
|
"the list to hand a model instead of letting it guess page ids.")
|
|
args = p.parse_args(argv)
|
|
|
|
from ..book.config import ConfigError, ProjectFile, apply_reference, load, select_parts
|
|
from ..book.document import Part, plan_spots
|
|
from ..book.notes import Notes
|
|
|
|
if not args.config.exists():
|
|
raise Abort(f"no run file at {args.config}")
|
|
try:
|
|
loaded = load(args.config)
|
|
apply_reference(loaded)
|
|
if isinstance(loaded, ProjectFile):
|
|
groups = {loaded.document.notes: select_parts(loaded, args.only)}
|
|
else:
|
|
groups = {}
|
|
for e in loaded.select(args.only):
|
|
part = Part(name=e.name, kind=e.kind, source=e.source, out=e.out,
|
|
exclude=e.exclude)
|
|
groups.setdefault(e.notes, []).append(part)
|
|
except ConfigError as e:
|
|
raise Abort(str(e)) from None
|
|
|
|
total = 0
|
|
for root, parts in groups.items():
|
|
spots = {}
|
|
for part in parts:
|
|
try:
|
|
spots[part.name] = plan_spots(part)
|
|
except Exception as e: # noqa: BLE001 - one bad source must not cost the rest
|
|
print(f" skip {part.name}: {type(e).__name__}: {str(e).splitlines()[0]}")
|
|
if args.list:
|
|
# Relative to the run file's folder, which is how a note's path is
|
|
# written in a reply — not as an absolute path on this machine.
|
|
base = args.config.resolve().parent
|
|
try:
|
|
shown = root.relative_to(base)
|
|
except ValueError:
|
|
shown = root
|
|
rows = [(f"{shown}/_intro.md", "top of the document"),
|
|
(f"{shown}/_end.md", "end of the document")]
|
|
for book, entries in spots.items():
|
|
rows.append((f"{shown}/{book}/_intro.md", f"top of book {book}"))
|
|
for spot, where in entries:
|
|
has = " (has a note)" if Notes(root).book(book, spot) else ""
|
|
rows.append((f"{shown}/{book}/{spot}.md", where + has))
|
|
width = max(len(r[0]) for r in rows)
|
|
for path, where in rows:
|
|
print(f"{path:<{width}} {where}")
|
|
continue
|
|
written = Notes(root).scaffold(spots)
|
|
total += len(written)
|
|
existing = sum(len(v) for v in spots.values()) + 2 + len(spots) - len(written)
|
|
print(f" notes {root} — {len(written)} new stub(s), {existing} already there")
|
|
for path in written[:12]:
|
|
print(f" {path.relative_to(root)}")
|
|
if len(written) > 12:
|
|
print(f" … and {len(written) - 12} more")
|
|
return 0
|