from __future__ import annotations from pathlib import Path from django.core.management.base import BaseCommand, CommandError from control_plane.authoring.models import ( DocumentAuthority, DocumentType, Series, Work, WorkType, ) from control_plane.authoring.sources import discover_source_paths, inspect_source, register_source class Command(BaseCommand): help = "Register immutable, authority-labelled story source documents and passages." def add_arguments(self, parser) -> None: parser.add_argument("action", choices=["register"]) parser.add_argument("--root", type=Path, required=True) parser.add_argument("--series-slug", required=True) parser.add_argument("--series-title", required=True) parser.add_argument("--work-slug", required=True) parser.add_argument("--work-title", required=True) parser.add_argument("--work-type", choices=WorkType.values, default=WorkType.BOOK) parser.add_argument("--authority", choices=DocumentAuthority.values, required=True) parser.add_argument( "--document-type", choices=DocumentType.values, default=DocumentType.OTHER ) parser.add_argument("--include-glob", action="append", default=[]) parser.add_argument("--dry-run", action="store_true") def handle(self, *args, **options) -> None: root: Path = options["root"] if not root.exists(): raise CommandError(f"source root does not exist: {root}") paths = discover_source_paths(root, options["include_glob"]) if not paths: raise CommandError(f"no supported UTF-8 source files found under {root}") if options["dry_run"]: for path in paths: result = inspect_source(path, root) self.stdout.write( f"DRY-RUN {result.logical_key} sha256={result.source_sha256} " f"passages={result.passage_count} authority={options['authority']}" ) self.stdout.write( self.style.SUCCESS(f"Discovered {len(paths)} source files; no changes made.") ) return series, _ = Series.objects.get_or_create( slug=options["series_slug"], defaults={"title": options["series_title"]} ) work, _ = Work.objects.get_or_create( series=series, slug=options["work_slug"], defaults={ "title": options["work_title"], "work_type": options["work_type"], }, ) counts = {"created": 0, "versioned": 0, "unchanged": 0} for path in paths: try: result = register_source( work=work, path=path, root=root, authority=options["authority"], document_type=options["document_type"], ) except UnicodeDecodeError as exc: raise CommandError(f"source is not valid UTF-8: {path}") from exc except ValueError as exc: raise CommandError(str(exc)) from exc counts[result.status] += 1 self.stdout.write( f"{result.status.upper()} {result.logical_key} v{result.version} " f"passages={result.passage_count}" ) self.stdout.write( self.style.SUCCESS( f"Registered {len(paths)} files: {counts['created']} created, " f"{counts['versioned']} versioned, {counts['unchanged']} unchanged." ) )