From eb8ba489090625986bbf207576717556386742d8 Mon Sep 17 00:00:00 2001
From: Cai <cai@nbcai.cc>
Date: Tue, 18 Aug 2026 18:15:28 +0800
Subject: [PATCH] chore: 更新2026-08-18股票估值每日台账
---
dev/project-dev/hibor_batch_executor.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 94 insertions(+), 3 deletions(-)
diff --git a/dev/project-dev/hibor_batch_executor.py b/dev/project-dev/hibor_batch_executor.py
index 9b6e393..2bfd787 100644
--- a/dev/project-dev/hibor_batch_executor.py
+++ b/dev/project-dev/hibor_batch_executor.py
@@ -19,6 +19,8 @@
MAX_ITEMS = 10
MAX_GENERATED_PATH_CHARS = 220
DEFAULT_ITEM_TIMEOUT_SECONDS = 660
+ADB_PREFLIGHT_TIMEOUT_SECONDS = 15
+AUTO_DEVICE_SERIAL = "auto"
PACKAGE_NAME = "cn.com.hibor"
CACHE_ROOT = "/sdcard/Android/data/cn.com.hibor/files/myfile/"
SHORT_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]{0,23}$")
@@ -313,6 +315,86 @@
)
+def _parse_adb_devices(stdout: bytes) -> dict[str, str]:
+ try:
+ text = stdout.decode("utf-8")
+ except UnicodeError as exc:
+ raise BatchInputError("adb devices output is not valid UTF-8") from exc
+ lines = [line.strip() for line in text.splitlines()]
+ try:
+ header_index = lines.index("List of devices attached")
+ except ValueError as exc:
+ raise BatchInputError("adb devices output is missing its header") from exc
+
+ devices: dict[str, str] = {}
+ for line in lines[header_index + 1:]:
+ if not line or line.startswith("*"):
+ continue
+ fields = line.split()
+ if len(fields) < 2:
+ raise BatchInputError(f"cannot parse adb device row: {line}")
+ serial, state = fields[0], fields[1]
+ if serial in devices:
+ raise BatchInputError(f"adb returned duplicate device serial: {serial}")
+ devices[serial] = state
+ return devices
+
+
+def resolve_device_serial(
+ adb_executable: str,
+ requested_serial: str,
+ *,
+ cwd: Path,
+ environment: Mapping[str, str],
+ runner: Runner | None = None,
+ timeout_seconds: int = ADB_PREFLIGHT_TIMEOUT_SECONDS,
+) -> str:
+ if timeout_seconds < 1:
+ raise BatchInputError("ADB preflight timeout must be positive")
+ runner = runner or _default_runner
+ try:
+ completed = runner(
+ [adb_executable, "devices", "-l"], cwd, environment, timeout_seconds
+ )
+ except subprocess.TimeoutExpired as exc:
+ raise BatchInputError(
+ f"ADB device preflight timed out after {timeout_seconds}s"
+ ) from exc
+ except OSError as exc:
+ raise BatchInputError(
+ f"cannot run ADB device preflight: {type(exc).__name__}"
+ ) from exc
+ if int(completed.returncode) != 0:
+ stderr = _as_bytes(completed.stderr).decode("utf-8", errors="replace").strip()
+ detail = stderr[-500:] if stderr else f"exit code {completed.returncode}"
+ raise BatchInputError(f"ADB device preflight failed: {detail}")
+
+ devices = _parse_adb_devices(_as_bytes(completed.stdout))
+ if requested_serial == AUTO_DEVICE_SERIAL:
+ if len(devices) != 1:
+ raise BatchInputError(
+ "runtime.device_serial=auto requires exactly one connected ADB device; "
+ f"found {len(devices)}"
+ )
+ serial, state = next(iter(devices.items()))
+ if state != "device":
+ raise BatchInputError(
+ f"the only connected ADB device is not ready: {serial} ({state})"
+ )
+ return serial
+
+ state = devices.get(requested_serial)
+ if state is None:
+ raise BatchInputError(
+ f"configured ADB device is not connected: {requested_serial}"
+ )
+ if state != "device":
+ raise BatchInputError(
+ f"configured ADB device is not ready: {requested_serial} ({state})"
+ )
+ return requested_serial
+
+
def _as_bytes(value: bytes | str | None) -> bytes:
if value is None:
return b""
@@ -409,6 +491,7 @@
python_executable: str | None = None,
kernel_entry: Path | None = None,
runner: Runner | None = None,
+ device_runner: Runner | None = None,
item_timeout_seconds: int = DEFAULT_ITEM_TIMEOUT_SECONDS,
) -> dict[str, Any]:
if item_timeout_seconds < 1:
@@ -421,6 +504,17 @@
batch_root = project_root / "ana-data" / "tmp" / "hibor-runs" / batch["batch_id"]
if batch_root.exists() or batch_root.is_symlink():
raise BatchInputError(f"batch output already exists; choose a new batch_id: {batch_root}")
+
+ environment = dict(os.environ)
+ environment["PYTHONUTF8"] = "1"
+ environment["PYTHONIOENCODING"] = "utf-8"
+ batch["runtime"]["device_serial"] = resolve_device_serial(
+ batch["runtime"]["adb_executable"],
+ batch["runtime"]["device_serial"],
+ cwd=project_root,
+ environment=environment,
+ runner=device_runner,
+ )
task_specs = [
build_task_spec(batch, item, index, batch_root / "r" / f"{index:02d}")
@@ -439,9 +533,6 @@
started_ns = time.monotonic_ns()
rows: list[dict[str, Any]] = []
item_timings: list[dict[str, Any]] = []
- environment = dict(os.environ)
- environment["PYTHONUTF8"] = "1"
- environment["PYTHONIOENCODING"] = "utf-8"
for index, (item, task_spec) in enumerate(zip(batch["items"], task_specs), 1):
task_path = batch_root / "t" / f"{index:02d}.json"
--
Gitblit v1.9.3