generated from coulomb/repo-seed
Refresh planning layer for backend fabric
This commit is contained in:
@@ -19,6 +19,8 @@ from markitect_tool.cache import (
|
||||
from markitect_tool.backend import (
|
||||
BackendRegistryError,
|
||||
load_backend_registry,
|
||||
load_snapshot_state_file,
|
||||
plan_snapshot_refresh,
|
||||
snapshot_identity_for_file,
|
||||
)
|
||||
from markitect_tool.content_class import (
|
||||
@@ -581,6 +583,71 @@ def backend_snapshot_id(
|
||||
_emit_snapshot_identity(data, output_format)
|
||||
|
||||
|
||||
@backend.command("refresh-plan")
|
||||
@click.argument("paths", nargs=-1, required=True, type=click.Path(exists=True, path_type=Path))
|
||||
@click.option(
|
||||
"--root",
|
||||
type=click.Path(exists=True, file_okay=False, path_type=Path),
|
||||
default=Path("."),
|
||||
show_default=True,
|
||||
help="Root used for relative source paths.",
|
||||
)
|
||||
@click.option(
|
||||
"--state",
|
||||
"state_file",
|
||||
type=click.Path(exists=True, dir_okay=False, path_type=Path),
|
||||
help="YAML/JSON snapshot state file from a previous backend run.",
|
||||
)
|
||||
@click.option("--no-recursive", is_flag=True, help="Do not recurse into directories.")
|
||||
@click.option(
|
||||
"--verify-hashes",
|
||||
is_flag=True,
|
||||
help="Hash metadata-changed files to avoid unnecessary parse/index work.",
|
||||
)
|
||||
@click.option(
|
||||
"--parse-option",
|
||||
"parse_options",
|
||||
multiple=True,
|
||||
metavar="KEY=VALUE",
|
||||
help="Parse option included in the identity comparison.",
|
||||
)
|
||||
@click.option("--contract-hash", help="Optional contract hash included in identity comparison.")
|
||||
@click.option(
|
||||
"--format",
|
||||
"output_format",
|
||||
type=click.Choice(["json", "yaml", "text"], case_sensitive=False),
|
||||
default="text",
|
||||
show_default=True,
|
||||
)
|
||||
def backend_refresh_plan(
|
||||
paths: tuple[Path, ...],
|
||||
root: Path,
|
||||
state_file: Path | None,
|
||||
no_recursive: bool,
|
||||
verify_hashes: bool,
|
||||
parse_options: tuple[str, ...],
|
||||
contract_hash: str | None,
|
||||
output_format: str,
|
||||
) -> None:
|
||||
"""Plan cheap-first snapshot and index refresh work."""
|
||||
|
||||
try:
|
||||
previous = load_snapshot_state_file(state_file) if state_file else []
|
||||
plan = plan_snapshot_refresh(
|
||||
list(paths),
|
||||
previous=previous,
|
||||
root=root,
|
||||
recursive=not no_recursive,
|
||||
parse_options=_parse_key_value_options(parse_options),
|
||||
contract_hash=contract_hash,
|
||||
verify_hashes=verify_hashes,
|
||||
)
|
||||
except (ValueError, TypeError) as exc:
|
||||
raise click.ClickException(str(exc)) from exc
|
||||
_emit_refresh_plan(plan.to_dict(), output_format)
|
||||
raise click.exceptions.Exit(1 if plan.dirty else 0)
|
||||
|
||||
|
||||
@main.group("class")
|
||||
def class_group() -> None:
|
||||
"""Resolve deterministic content classes."""
|
||||
@@ -1238,6 +1305,31 @@ def _emit_snapshot_identity(data: dict, output_format: str) -> None:
|
||||
click.echo(f"parser: {data['parser']} {data['parser_version']}")
|
||||
|
||||
|
||||
def _emit_refresh_plan(data: dict, output_format: str) -> None:
|
||||
if output_format == "json":
|
||||
click.echo(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
elif output_format == "yaml":
|
||||
click.echo(yaml.safe_dump(data, sort_keys=False))
|
||||
else:
|
||||
click.echo("dirty" if data["dirty"] else "clean")
|
||||
counts = data["counts"]
|
||||
for key in [
|
||||
"unchanged",
|
||||
"needs_hash",
|
||||
"needs_parse",
|
||||
"needs_index",
|
||||
"needs_metadata_update",
|
||||
"deleted",
|
||||
"invalidated",
|
||||
]:
|
||||
click.echo(f"{key}: {counts[key]}")
|
||||
for entry in data["entries"]:
|
||||
actions = ",".join(entry.get("actions", [])) or "none"
|
||||
click.echo(f"- {entry['path']}: {actions} ({entry['reason']})")
|
||||
if entry.get("invalidated_by"):
|
||||
click.echo(f" invalidated_by: {', '.join(entry['invalidated_by'])}")
|
||||
|
||||
|
||||
def _emit_content_class_result(data: dict, output_format: str) -> None:
|
||||
if output_format == "json":
|
||||
click.echo(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
|
||||
Reference in New Issue
Block a user