90 lines
3.7 KiB
Python
90 lines
3.7 KiB
Python
"""采集 T-103 一次性尺码 reveal 的 before/after 本机证据。"""
|
||||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import argparse
|
|||
|
|
from math import isfinite
|
|||
|
|
from pathlib import Path
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
|
|||
|
|
CLIENT_ROOT = Path(__file__).resolve().parents[1]
|
|||
|
|
sys.path.insert(0, str(CLIENT_ROOT / "src"))
|
|||
|
|
|
|||
|
|
from cmbuyer_client.device.adb import AdbClient, DeviceConnectionError, SubprocessAdbRunner
|
|||
|
|
from cmbuyer_client.device.baseline import NoReconnectUiautomatorConnector
|
|||
|
|
from cmbuyer_client.pdd.sku_reveal_spike import SkuRevealSpikeCapturer, SkuRevealSpikeError
|
|||
|
|
from cmbuyer_client.pdd.sku_selection import EXPECTED_GOODS_ID, SkuSelectionError
|
|||
|
|
from cmbuyer_client.pdd.sku_selection_runner import SkuSelectionRunError
|
|||
|
|
|
|||
|
|
|
|||
|
|
def parse_arguments(argv: list[str] | None = None) -> argparse.Namespace:
|
|||
|
|
parser = argparse.ArgumentParser(description="采集 T-103 一次性尺码 reveal 的本机证据。")
|
|||
|
|
parser.add_argument("--serial", required=True, help="ADB device serial;禁止自动选择。")
|
|||
|
|
parser.add_argument("--goods-id", required=True, help="固定 T-103 已取证 goods_id。")
|
|||
|
|
parser.add_argument("--output-dir", required=True, type=Path, help="全新本机证据目录;不得覆盖。")
|
|||
|
|
parser.add_argument("--timeout", type=float, default=30.0, help="整趟动作与只读调和时限(秒)。")
|
|||
|
|
parser.add_argument("--adb", default="adb", help="adb 可执行文件路径。")
|
|||
|
|
return parser.parse_args(argv)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def validate_arguments(arguments: argparse.Namespace) -> None:
|
|||
|
|
if type(arguments.serial) is not str or not arguments.serial.strip():
|
|||
|
|
raise ValueError("必须显式提供非空 --serial。")
|
|||
|
|
if type(arguments.goods_id) is not str or arguments.goods_id != EXPECTED_GOODS_ID:
|
|||
|
|
raise ValueError("--goods-id 不是 T-103 已取证商品。")
|
|||
|
|
if (
|
|||
|
|
not isinstance(arguments.timeout, (int, float))
|
|||
|
|
or isinstance(arguments.timeout, bool)
|
|||
|
|
or arguments.timeout <= 0
|
|||
|
|
or not isfinite(arguments.timeout)
|
|||
|
|
):
|
|||
|
|
raise ValueError("--timeout 必须是大于 0 的有限数值。")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main(argv: list[str] | None = None) -> int:
|
|||
|
|
arguments = parse_arguments(argv)
|
|||
|
|
try:
|
|||
|
|
validate_arguments(arguments)
|
|||
|
|
except ValueError as error:
|
|||
|
|
print(f"失败:{error}", file=sys.stderr)
|
|||
|
|
return 2
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
import adbutils
|
|||
|
|
import uiautomator2 as u2
|
|||
|
|
except ImportError:
|
|||
|
|
print("失败:缺少 uiautomator2;请在采购工具虚拟环境中运行。", file=sys.stderr)
|
|||
|
|
return 2
|
|||
|
|
|
|||
|
|
capturer = SkuRevealSpikeCapturer(
|
|||
|
|
AdbClient(SubprocessAdbRunner(arguments.adb), timeout_seconds=arguments.timeout),
|
|||
|
|
NoReconnectUiautomatorConnector(
|
|||
|
|
adbutils.AdbClient(socket_timeout=arguments.timeout).device_list,
|
|||
|
|
u2.connect,
|
|||
|
|
),
|
|||
|
|
timeout_seconds=arguments.timeout,
|
|||
|
|
)
|
|||
|
|
try:
|
|||
|
|
result = capturer.capture(
|
|||
|
|
arguments.serial,
|
|||
|
|
arguments.goods_id,
|
|||
|
|
arguments.output_dir,
|
|||
|
|
)
|
|||
|
|
except (DeviceConnectionError, SkuSelectionError, SkuSelectionRunError, SkuRevealSpikeError):
|
|||
|
|
# 不回显页面正文、节点、serial、坐标、路径或第三方异常。
|
|||
|
|
print("规格 reveal 取证失败:已停止,未发布本地证据目录。", file=sys.stderr)
|
|||
|
|
return 1
|
|||
|
|
except OSError:
|
|||
|
|
print("规格 reveal 取证失败:无法创建或发布本地证据目录。", file=sys.stderr)
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
print(f"规格 reveal 取证完成:{result.output_directory}")
|
|||
|
|
print(f"manifest:{result.manifest_path}")
|
|||
|
|
print("人工复核:请保持手机不动,确认颜色仍选中、S/M 均未选且未进入提交页。")
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
raise SystemExit(main())
|