118 lines
3.4 KiB
Python
118 lines
3.4 KiB
Python
"""Verify the public PyInstaller onedir output and reject internal artifacts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
DIST = ROOT / "dist" / "SensorBench"
|
|
|
|
# Paths / substrings that must never appear in a public customer build.
|
|
FORBIDDEN_RELATIVE_PATHS = (
|
|
"steps",
|
|
"steps/default.json",
|
|
"config/options.json",
|
|
"internal",
|
|
)
|
|
|
|
FORBIDDEN_NAME_FRAGMENTS = (
|
|
"sensor_bench_operator",
|
|
"sensor_bench.app",
|
|
"operator-ui",
|
|
)
|
|
|
|
FORBIDDEN_LOCALE_KEYS = (
|
|
"workflow",
|
|
)
|
|
|
|
FORBIDDEN_TEXT_SNIPPETS = (
|
|
"Inspection Workflow",
|
|
"检测流程",
|
|
"新样品",
|
|
"冯总",
|
|
"operator-ui",
|
|
)
|
|
|
|
|
|
def require(path: Path) -> None:
|
|
if not path.exists():
|
|
raise FileNotFoundError(f"Missing build artifact: {path}")
|
|
|
|
|
|
def forbid(path: Path, *, reason: str) -> None:
|
|
if path.exists():
|
|
raise RuntimeError(f"Public dist must not include {reason}: {path}")
|
|
|
|
|
|
def _iter_text_files(root: Path) -> list[Path]:
|
|
files: list[Path] = []
|
|
for path in root.rglob("*"):
|
|
if not path.is_file():
|
|
continue
|
|
if path.suffix.lower() in {".json", ".txt", ".md", ".py", ".toc", ".html"}:
|
|
files.append(path)
|
|
# PyInstaller may leave .pyc / .py modules under _internal
|
|
if path.suffix.lower() == ".pyc" and "operator" in path.name.lower():
|
|
files.append(path)
|
|
return files
|
|
|
|
|
|
def _assert_no_forbidden_names(root: Path) -> None:
|
|
for path in root.rglob("*"):
|
|
rel = path.relative_to(root).as_posix().lower()
|
|
name = path.name.lower()
|
|
for fragment in FORBIDDEN_NAME_FRAGMENTS:
|
|
if fragment.lower() in rel or fragment.lower() in name:
|
|
raise RuntimeError(
|
|
f"Public dist contains forbidden name '{fragment}': {path}"
|
|
)
|
|
|
|
|
|
def _assert_locale_public(path: Path) -> None:
|
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
for key in FORBIDDEN_LOCALE_KEYS:
|
|
if key in data:
|
|
raise RuntimeError(f"Public locale {path.name} still contains '{key}'")
|
|
status = data.get("status")
|
|
if isinstance(status, dict) and "workflow_done" in status:
|
|
raise RuntimeError(f"Public locale {path.name} still contains status.workflow_done")
|
|
|
|
|
|
def _assert_no_forbidden_text(root: Path) -> None:
|
|
for path in _iter_text_files(root):
|
|
try:
|
|
text = path.read_text(encoding="utf-8", errors="ignore")
|
|
except Exception: # noqa: BLE001
|
|
continue
|
|
for snippet in FORBIDDEN_TEXT_SNIPPETS:
|
|
if snippet in text:
|
|
raise RuntimeError(
|
|
f"Public dist text contains forbidden snippet {snippet!r} in {path}"
|
|
)
|
|
|
|
|
|
def main() -> int:
|
|
require(DIST / "SensorBench.exe")
|
|
require(DIST / "config" / "locales" / "zh_CN.json")
|
|
require(DIST / "config" / "locales" / "en_US.json")
|
|
require(DIST / "config" / "ddjx01.json")
|
|
require(DIST / "_internal")
|
|
|
|
for rel in FORBIDDEN_RELATIVE_PATHS:
|
|
forbid(DIST / rel, reason=rel)
|
|
|
|
_assert_no_forbidden_names(DIST)
|
|
_assert_locale_public(DIST / "config" / "locales" / "zh_CN.json")
|
|
_assert_locale_public(DIST / "config" / "locales" / "en_US.json")
|
|
_assert_no_forbidden_text(DIST / "config")
|
|
|
|
print(f"Verified public SensorBench dist layout: {DIST}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|