refactor: split the retention arg checks per backend

_validate carried the whole matrix in one function (cc C/13, over the
branch quality gate). Splitting it by what is actually being checked —
shared, sqlite-only, postgres-only — puts every piece at A/B.

Ordering is the part that had to survive: the chain's order is the error
messages' priority, so a run with several bad flags still reports the
same one it did before. The --vacuum/--apply pairing therefore stays in
the shared step ahead of the backend branch, where it was; it is a "do
not rewrite the whole file when you only meant to look" rule, which
holds before the question of which backend a flag belongs to.

No behavior change: all nine parser.error strings are byte-identical and
in the same order, and the eight usage-error cases pass unmodified.
This commit is contained in:
2026-08-19 15:19:35 -04:00
parent ea9b6fbcd9
commit 4b06093d6c
+32 -9
View File
@@ -118,19 +118,42 @@ def _build_parser() -> _Parser:
def _validate(parser: _Parser, args: argparse.Namespace) -> None: def _validate(parser: _Parser, args: argparse.Namespace) -> None:
"""校验参数组合;任何不合法组合以退出码 1 结束(P5: 不给默认值掩盖错误)。""" """校验参数组合;任何不合法组合以退出码 1 结束(P5: 不给默认值掩盖错误)。
**校验链的顺序就是错误消息的优先级**: 先两端通用,再按 backend 分支——同时给出
多个错误参数时,报出的是链上最先命中的那条。
"""
_validate_shared(parser, args)
if args.backend == "sqlite":
_validate_sqlite(parser, args)
return
_validate_postgres(parser, args)
def _validate_shared(parser: _Parser, args: argparse.Namespace) -> None:
"""两端通用的校验。
`--vacuum` 与 `--apply` 的联动归在这里(而不是 SQLite 分支): 它是"别在只想看看的
时候重写整个库"这条安全约束,先于"这个参数属于哪个 backend"成立。
"""
if args.older_than_days < 0: if args.older_than_days < 0:
parser.error("--older-than-days 必须 >= 0") parser.error("--older-than-days 必须 >= 0")
if args.vacuum and not args.apply: if args.vacuum and not args.apply:
parser.error("--vacuum 会重写整个库文件,必须与 --apply 同时给") parser.error("--vacuum 会重写整个库文件,必须与 --apply 同时给")
if args.backend == "sqlite":
if args.path is None:
parser.error("--backend sqlite 需要 --path") def _validate_sqlite(parser: _Parser, args: argparse.Namespace) -> None:
if args.dsn is not None: """SQLite 分支: 必须有 --path,且拒绝一切 postgres 专属参数(不静默忽略)。"""
parser.error("--backend sqlite 不接受 --dsn") if args.path is None:
if args.batch_size is not None: parser.error("--backend sqlite 需要 --path")
parser.error("--batch-size 仅用于 --backend postgres") if args.dsn is not None:
return parser.error("--backend sqlite 不接受 --dsn")
if args.batch_size is not None:
parser.error("--batch-size 仅用于 --backend postgres")
def _validate_postgres(parser: _Parser, args: argparse.Namespace) -> None:
"""Postgres 分支: 必须有 --dsn,拒绝 sqlite 专属参数,并在此落 --batch-size 缺省值。"""
if args.dsn is None: if args.dsn is None:
parser.error("--backend postgres 需要 --dsn") parser.error("--backend postgres 需要 --dsn")
if args.path is not None: if args.path is not None: