整理 tjwater-cli 代码和文档
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Annotated
|
||||
|
||||
import click
|
||||
import typer
|
||||
from click.exceptions import NoArgsIsHelpError
|
||||
|
||||
from . import commands_analysis, commands_data, commands_project # noqa: F401
|
||||
from .apps import app
|
||||
from .core import CLIError, DEFAULT_SERVER, DEFAULT_TIMEOUT, emit_failure
|
||||
from .helping import (
|
||||
apply_typer_help_metadata,
|
||||
build_error_guidance,
|
||||
classify_click_error,
|
||||
emit_help_payload,
|
||||
merge_error_data,
|
||||
merge_next_commands,
|
||||
register_group_help_commands,
|
||||
resolve_help_payload,
|
||||
)
|
||||
|
||||
|
||||
@app.callback()
|
||||
def root_callback(
|
||||
ctx: typer.Context,
|
||||
server: Annotated[str | None, typer.Option("--server", help=f"服务端地址,默认 {DEFAULT_SERVER}")] = None,
|
||||
auth_context: Annotated[Path | None, typer.Option("--auth-context", help="认证上下文 JSON 文件")] = None,
|
||||
scheme: Annotated[str | None, typer.Option("--scheme", help="全局方案标识")] = None,
|
||||
timeout: Annotated[int, typer.Option("--timeout", help="请求超时秒数")] = DEFAULT_TIMEOUT,
|
||||
request_id: Annotated[str | None, typer.Option("--request-id", help="显式请求 ID")] = None,
|
||||
) -> None:
|
||||
ctx.obj = {
|
||||
"server": server,
|
||||
"auth_context": auth_context,
|
||||
"scheme": scheme,
|
||||
"timeout": timeout,
|
||||
"request_id": request_id,
|
||||
}
|
||||
|
||||
|
||||
register_group_help_commands()
|
||||
|
||||
|
||||
@app.command("help", context_settings={"allow_extra_args": True, "ignore_unknown_options": True})
|
||||
def help_command(
|
||||
ctx: typer.Context,
|
||||
json_output: Annotated[bool, typer.Option("--json", help="输出 JSON")] = False,
|
||||
) -> None:
|
||||
command_path = list(ctx.args)
|
||||
payload, is_index = resolve_help_payload(tuple(command_path))
|
||||
if payload is None:
|
||||
emit_failure(
|
||||
summary="未找到命令",
|
||||
code="COMMAND_NOT_FOUND",
|
||||
message=f"unknown command path: {' '.join(command_path)}",
|
||||
exit_code=2,
|
||||
retryable=False,
|
||||
server=None,
|
||||
request_id=None,
|
||||
data={
|
||||
"usage": "tjwater help <command-path>",
|
||||
"examples": ["tjwater help simulation run", "tjwater simulation help"],
|
||||
},
|
||||
next_commands=["tjwater help", "tjwater help simulation"],
|
||||
)
|
||||
raise typer.Exit(code=2)
|
||||
emit_help_payload(payload, json_output=json_output, is_index=is_index)
|
||||
|
||||
|
||||
# Must run at import time because tests call runner.invoke(app, ...) directly.
|
||||
apply_typer_help_metadata()
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
try:
|
||||
app(args=argv if argv is not None else sys.argv[1:], prog_name="tjwater", standalone_mode=False)
|
||||
return 0
|
||||
except CLIError as exc:
|
||||
click_ctx = click.get_current_context(silent=True)
|
||||
error_data, next_commands = build_error_guidance(click_ctx)
|
||||
return emit_failure(
|
||||
summary=exc.summary,
|
||||
code=exc.code,
|
||||
message=exc.message,
|
||||
exit_code=exc.exit_code,
|
||||
retryable=exc.retryable,
|
||||
server=None,
|
||||
request_id=None,
|
||||
next_commands=merge_next_commands(exc.next_commands, next_commands),
|
||||
data=merge_error_data(exc.data, error_data),
|
||||
)
|
||||
except NoArgsIsHelpError:
|
||||
return 0
|
||||
except click.ClickException as exc:
|
||||
click_ctx = click.get_current_context(silent=True) or exc.ctx
|
||||
error_data, next_commands = build_error_guidance(click_ctx)
|
||||
summary, code = classify_click_error(exc)
|
||||
return emit_failure(
|
||||
summary=summary,
|
||||
code=code,
|
||||
message=exc.format_message(),
|
||||
exit_code=2,
|
||||
retryable=False,
|
||||
server=None,
|
||||
request_id=None,
|
||||
next_commands=next_commands,
|
||||
data=error_data,
|
||||
)
|
||||
|
||||
|
||||
def console_entry() -> None:
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user