place_static_extras.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. r"""构建后放置**非 vite 产物**的静态件(P22 实逮:`vite build` 会清空 `release/web`,先放后建必被清掉)。
  4. 放置内容:
  5. · `release/web/portal/` —— 门户件(shell.html + governance_sources.json + manifest.json + templates/28 件)
  6. · `release/web/detail_v2.html` —— v2.9.2 原文经典页(仅作对照/回退视图)
  7. · `release/web/favicon.svg`
  8. 来源:`app_guanlang_v2.9.2.zip`(参考包,存在则用;可用 `--zip` 指定)。经典页用 v2.9.2 自带
  9. `src/windscada/ui/build.py` 出页(含语言包),保证与 v2.9.2 一致。
  10. 用法:python scripts/place_static_extras.py [--zip <v2.9.2 参考包路径>](或设环境变量 GUANLAN_REF_PKG)
  11. """
  12. from __future__ import annotations
  13. import argparse
  14. import os
  15. import pathlib
  16. import shutil
  17. import subprocess
  18. import sys
  19. import tempfile
  20. import zipfile
  21. HERE = pathlib.Path(__file__).resolve().parents[1]
  22. REL = HERE / 'release' / 'web'
  23. # 参考包路径**不硬编码**(可移植性门禁):由 --zip 或环境变量 GUANLAN_REF_PKG 提供
  24. DEFAULT_ZIP = os.environ.get('GUANLAN_REF_PKG') or ''
  25. def main() -> int:
  26. ap = argparse.ArgumentParser()
  27. ap.add_argument('--zip', default=DEFAULT_ZIP, help='v2.9.2 参考包(或用环境变量 GUANLAN_REF_PKG)')
  28. a = ap.parse_args()
  29. if not a.zip:
  30. print('[X] 未提供参考包路径:请用 --zip <v2.9.2 包> 或设环境变量 GUANLAN_REF_PKG;'
  31. '(跳过;门户件与经典页保持现状)')
  32. return 2
  33. zp = pathlib.Path(a.zip)
  34. if not zp.exists():
  35. print('[X] 参考包不在:%s(跳过;门户件与经典页保持现状)' % zp)
  36. return 2
  37. # 门户件
  38. out = REL / 'portal'
  39. if out.exists():
  40. shutil.rmtree(out)
  41. (out / 'templates').mkdir(parents=True, exist_ok=True)
  42. with zipfile.ZipFile(zp) as z:
  43. (out / 'shell.html').write_bytes(z.read('release/portal_src/shell.html'))
  44. (out / 'governance_sources.json').write_bytes(z.read('release/portal_src/governance_sources.json'))
  45. (out / 'manifest.json').write_bytes(z.read('release/portal_src/manifest.json'))
  46. n = 0
  47. for nm in z.namelist():
  48. if nm.startswith('release/portal_src/templates/'):
  49. (out / 'templates' / pathlib.Path(nm).name).write_bytes(z.read(nm))
  50. n += 1
  51. (REL / 'favicon.svg').write_bytes(z.read('src/windscada/ui/favicon.svg'))
  52. # 经典页:解出 src/ 与 configs/ 后用其自带 build.py 出页
  53. tmp = pathlib.Path(tempfile.mkdtemp(prefix='gl_v292_'))
  54. want = [m for m in z.namelist() if m.startswith('src/') or m.startswith('configs/')]
  55. z.extractall(tmp, members=want)
  56. pyx = HERE / '.venv' / 'Scripts' / 'python.exe'
  57. p = subprocess.run([str(pyx), '-X', 'utf8', '-m', 'src.windscada.ui.build', 'zh'],
  58. cwd=str(tmp), capture_output=True, timeout=900)
  59. if p.returncode == 0 and p.stdout:
  60. (REL / 'detail_v2.html').write_bytes(p.stdout)
  61. shutil.rmtree(tmp, ignore_errors=True)
  62. print('[OK] 门户件 shell + %d 模板 · favicon · 经典页 %s'
  63. % (n, '已出页' if (REL / 'detail_v2.html').exists() else '未出页'))
  64. return 0
  65. if __name__ == '__main__':
  66. raise SystemExit(main())