135 lines
3.9 KiB
Python
135 lines
3.9 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import json
|
||
|
|
import sys
|
||
|
|
from collections.abc import Callable
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
from .api import serve
|
||
|
|
from .service import (
|
||
|
|
CanonServiceError,
|
||
|
|
artifact_graph,
|
||
|
|
inspect_canon,
|
||
|
|
list_artifacts,
|
||
|
|
list_models,
|
||
|
|
list_standards,
|
||
|
|
profile_inspect,
|
||
|
|
validate_canon,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
Command = Callable[[argparse.Namespace], dict[str, Any]]
|
||
|
|
|
||
|
|
|
||
|
|
def build_parser() -> argparse.ArgumentParser:
|
||
|
|
parser = argparse.ArgumentParser(prog="info-tech-canon")
|
||
|
|
parser.add_argument(
|
||
|
|
"--root",
|
||
|
|
default="",
|
||
|
|
help="Infospace root. Defaults to ./infospace from the repository root.",
|
||
|
|
)
|
||
|
|
sub = parser.add_subparsers(dest="command", required=True)
|
||
|
|
|
||
|
|
inspect = sub.add_parser("inspect", help="Inspect the canon infospace")
|
||
|
|
inspect.set_defaults(handler=_inspect)
|
||
|
|
|
||
|
|
artifacts = sub.add_parser("artifacts", help="List canon artifacts")
|
||
|
|
artifacts.add_argument("--kind", default="")
|
||
|
|
artifacts.set_defaults(handler=_artifacts)
|
||
|
|
|
||
|
|
models = sub.add_parser("models", help="List canon model artifacts")
|
||
|
|
models.set_defaults(handler=_models)
|
||
|
|
|
||
|
|
standards = sub.add_parser("standards", help="List canon standard artifacts")
|
||
|
|
standards.set_defaults(handler=_standards)
|
||
|
|
|
||
|
|
validate = sub.add_parser("validate", help="Validate the canon infospace")
|
||
|
|
validate.set_defaults(handler=_validate)
|
||
|
|
|
||
|
|
graph = sub.add_parser("graph", help="Export the canon artifact graph")
|
||
|
|
graph.add_argument("--format", choices=["json", "mermaid"], default="json")
|
||
|
|
graph.set_defaults(handler=_graph)
|
||
|
|
|
||
|
|
profile = sub.add_parser("profile", help="Inspect canon profiles")
|
||
|
|
profile_sub = profile.add_subparsers(dest="profile_command", required=True)
|
||
|
|
profile_inspect_cmd = profile_sub.add_parser("inspect", help="Inspect a profile")
|
||
|
|
profile_inspect_cmd.add_argument("profile")
|
||
|
|
profile_inspect_cmd.set_defaults(handler=_profile_inspect)
|
||
|
|
|
||
|
|
api = sub.add_parser("api", help="Run the read-only local API")
|
||
|
|
api.add_argument("--host", default="127.0.0.1")
|
||
|
|
api.add_argument("--port", type=int, default=8765)
|
||
|
|
api.set_defaults(handler=_api)
|
||
|
|
|
||
|
|
return parser
|
||
|
|
|
||
|
|
|
||
|
|
def main(argv: list[str] | None = None) -> int:
|
||
|
|
parser = build_parser()
|
||
|
|
args = parser.parse_args(argv)
|
||
|
|
handler: Command = args.handler
|
||
|
|
try:
|
||
|
|
result = handler(args)
|
||
|
|
except CanonServiceError as exc:
|
||
|
|
_print_json(exc.to_dict())
|
||
|
|
return 2
|
||
|
|
except Exception as exc:
|
||
|
|
_print_json(
|
||
|
|
{
|
||
|
|
"ok": False,
|
||
|
|
"error": {
|
||
|
|
"code": "unhandled_error",
|
||
|
|
"message": str(exc),
|
||
|
|
"details": {},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
)
|
||
|
|
return 1
|
||
|
|
if result:
|
||
|
|
_print_json(result)
|
||
|
|
return 0 if result.get("ok", False) else 1
|
||
|
|
|
||
|
|
|
||
|
|
def _root(args: argparse.Namespace) -> Path | None:
|
||
|
|
return Path(args.root) if args.root else None
|
||
|
|
|
||
|
|
|
||
|
|
def _inspect(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
return inspect_canon(_root(args))
|
||
|
|
|
||
|
|
|
||
|
|
def _artifacts(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
return list_artifacts(_root(args), kind=args.kind or None)
|
||
|
|
|
||
|
|
|
||
|
|
def _models(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
return list_models(_root(args))
|
||
|
|
|
||
|
|
|
||
|
|
def _standards(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
return list_standards(_root(args))
|
||
|
|
|
||
|
|
|
||
|
|
def _validate(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
return validate_canon(_root(args))
|
||
|
|
|
||
|
|
|
||
|
|
def _graph(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
return artifact_graph(_root(args), output_format=args.format)
|
||
|
|
|
||
|
|
|
||
|
|
def _profile_inspect(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
return profile_inspect(args.profile, _root(args))
|
||
|
|
|
||
|
|
|
||
|
|
def _api(args: argparse.Namespace) -> dict[str, Any]:
|
||
|
|
serve(host=args.host, port=args.port, root=_root(args))
|
||
|
|
return {}
|
||
|
|
|
||
|
|
|
||
|
|
def _print_json(data: dict[str, Any]) -> None:
|
||
|
|
json.dump(data, sys.stdout, indent=2, sort_keys=True)
|
||
|
|
sys.stdout.write("\n")
|