67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
"""Utilities for rendering execution plan information in CLI output."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
|
||
def fallback_plan_summary(execution_plan: Any) -> str:
|
||
"""Build a short plan summary from summary and summary_by_reason.
|
||
|
||
This is used when execution_plan.human_summary is missing or empty.
|
||
"""
|
||
summary = getattr(execution_plan, "summary", {}) or {}
|
||
summary_by_reason = getattr(execution_plan, "summary_by_reason", {}) or {}
|
||
operations = getattr(execution_plan, "operations", []) or []
|
||
|
||
total = summary.get("total", len(operations))
|
||
parts = [
|
||
f"计划操作统计:共 {total} 条(move {summary.get('move', 0)},rename {summary.get('rename', 0)},"
|
||
f"quarantine {summary.get('quarantine', 0)},no-op {summary.get('no-op', 0)})"
|
||
]
|
||
if summary_by_reason:
|
||
parts.append(
|
||
"原因分布:" + ";".join(f"{reason}: {count}" for reason, count in list(summary_by_reason.items())[:8])
|
||
)
|
||
return "\n".join(parts)
|
||
|
||
|
||
def preferred_plan_summary(execution_plan: Any) -> str:
|
||
"""Return human_summary if available, otherwise fallback summary."""
|
||
human_summary = getattr(execution_plan, "human_summary", "")
|
||
if isinstance(human_summary, str) and human_summary.strip():
|
||
return human_summary
|
||
return fallback_plan_summary(execution_plan)
|
||
|
||
|
||
def render_review_preview(
|
||
rows: list[dict[str, str]],
|
||
preview_limit: int = 10,
|
||
show_all: bool = False,
|
||
) -> tuple[list[str], int]:
|
||
"""Render high-risk review rows for console preview.
|
||
|
||
Returns a tuple of (lines, remaining_count).
|
||
"""
|
||
if preview_limit < 1:
|
||
raise ValueError("preview_limit must be >= 1")
|
||
|
||
selected = rows if show_all else rows[:preview_limit]
|
||
remaining = 0 if show_all else max(0, len(rows) - len(selected))
|
||
|
||
lines: list[str] = []
|
||
for row in selected:
|
||
idx = row.get("index", "?")
|
||
operation_type = row.get("operation_type", "")
|
||
flags = row.get("risk_flags", "") or "none"
|
||
source_path = row.get("source_path", "")
|
||
destination_path = row.get("destination_path", "")
|
||
reason = row.get("reason", "")
|
||
|
||
lines.append(f" - [{idx}] {operation_type} | flags={flags}")
|
||
lines.append(f" source: {source_path}")
|
||
lines.append(f" destination: {destination_path or '(none)'}")
|
||
lines.append(f" reason: {reason}")
|
||
|
||
return lines, remaining
|