embed_version_config.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #!/usr/bin/env python3
  2. """
  3. 版本配置嵌入脚本
  4. 在构建过程中将 .github/versions.json 的内容嵌入到 version_menu.js 中
  5. 完全基于 .github/versions.json,无硬编码版本信息
  6. 支持自动备份和还原 version_menu.js
  7. """
  8. import json
  9. import os
  10. import sys
  11. from pathlib import Path
  12. import shutil
  13. def load_versions_config():
  14. """加载 .github/versions.json 文件"""
  15. versions_file = Path(__file__).parent.parent.parent.parent / '.github' / 'versions.json'
  16. if not versions_file.exists():
  17. print(f"警告: 找不到版本配置文件 {versions_file}")
  18. return None
  19. try:
  20. with open(versions_file, 'r', encoding='utf-8') as f:
  21. config = json.load(f)
  22. if not isinstance(config, dict) or 'versions' not in config:
  23. print(f"错误: 版本配置文件格式不正确 {versions_file}")
  24. return None
  25. return config
  26. except Exception as e:
  27. print(f"错误: 无法读取版本配置文件: {e}")
  28. return None
  29. def embed_config_to_js(versions_config):
  30. if not versions_config:
  31. return """
  32. // 获取嵌入的版本配置(在构建时由脚本生成)
  33. function getEmbeddedVersionConfig() {
  34. return null; // 无可用版本配置
  35. }
  36. """
  37. # 确保配置格式正确
  38. config_js = json.dumps(versions_config, ensure_ascii=False, indent=2)
  39. embedded_config_js = f"""
  40. // 获取嵌入的版本配置(在构建时由脚本生成)
  41. function getEmbeddedVersionConfig() {{
  42. return {config_js};
  43. }}
  44. """
  45. return embedded_config_js
  46. def backup_js(js_file):
  47. bak_file = js_file.with_suffix('.js.bak')
  48. if js_file.exists():
  49. shutil.copy2(js_file, bak_file)
  50. print(f"已备份 {js_file} -> {bak_file}")
  51. return bak_file
  52. def restore_js(js_file):
  53. bak_file = js_file.with_suffix('.js.bak')
  54. if bak_file.exists():
  55. shutil.copy2(bak_file, js_file)
  56. print(f"已还原 {bak_file} -> {js_file}")
  57. return True
  58. else:
  59. print(f"未找到备份文件 {bak_file}")
  60. return False
  61. def update_version_menu_js(restore_after=False):
  62. versions_config = load_versions_config()
  63. embedded_config_js = embed_config_to_js(versions_config)
  64. js_file = Path(__file__).parent.parent / '_static' / 'version_menu.js'
  65. # 备份
  66. bak_file = backup_js(js_file)
  67. try:
  68. with open(js_file, 'r', encoding='utf-8') as f:
  69. content = f.read()
  70. except Exception as e:
  71. print(f"错误: 无法读取 {js_file}: {e}")
  72. return False
  73. # 使用括号深度匹配方式安全替换函数体,避免 JSON 中的 '}' 提前终止
  74. start_marker = '// 获取嵌入的版本配置(在构建时由脚本生成)'
  75. func_sig = 'function getEmbeddedVersionConfig()'
  76. start_idx = content.find(start_marker)
  77. replaced = False
  78. if start_idx != -1:
  79. sig_idx = content.find(func_sig, start_idx)
  80. if sig_idx != -1:
  81. brace_start = content.find('{', sig_idx)
  82. if brace_start != -1:
  83. depth = 0
  84. i = brace_start
  85. while i < len(content):
  86. ch = content[i]
  87. if ch == '{':
  88. depth += 1
  89. elif ch == '}':
  90. depth -= 1
  91. if depth == 0:
  92. # 包含右大括号本身
  93. end_idx = i + 1
  94. # 用嵌入代码整体替换这段函数定义
  95. content = content[:start_idx] + embedded_config_js.strip() + content[end_idx:]
  96. replaced = True
  97. print("替换现有嵌入配置函数(括号深度)")
  98. break
  99. i += 1
  100. if not replaced:
  101. # 查找插入位置 - 在 fetchVersionInfo 函数之前插入
  102. fetch_marker = 'async function fetchVersionInfo()'
  103. fetch_idx = content.find(fetch_marker)
  104. if fetch_idx != -1:
  105. content = content[:fetch_idx] + embedded_config_js.strip() + '\n\n ' + content[fetch_idx:]
  106. print("在 fetchVersionInfo 函数前插入嵌入配置函数")
  107. else:
  108. # 如果找不到 fetchVersionInfo,在文件开头插入
  109. content = embedded_config_js.strip() + '\n\n' + content
  110. print("在文件开头插入嵌入配置函数")
  111. try:
  112. with open(js_file, 'w', encoding='utf-8') as f:
  113. f.write(content)
  114. print(f"成功更新 {js_file}")
  115. if versions_config:
  116. print(f"嵌入版本配置: {len(versions_config.get('versions', []))} 个版本")
  117. for version in versions_config.get('versions', []):
  118. print(f" - {version['name']}: {version['display_name']} -> {version['url_path']}")
  119. else:
  120. print("嵌入兜底配置: 无可用版本")
  121. except Exception as e:
  122. print(f"错误: 无法写入 {js_file}: {e}")
  123. return False
  124. # 可选还原
  125. if restore_after:
  126. restore_js(js_file)
  127. return True
  128. def main():
  129. restore_after = False
  130. if len(sys.argv) > 1 and sys.argv[1] == '--restore-after':
  131. restore_after = True
  132. print("开始嵌入版本配置...")
  133. if update_version_menu_js(restore_after=restore_after):
  134. print("版本配置嵌入完成")
  135. # 如果不是立即恢复,则在构建完成后自动恢复
  136. if not restore_after:
  137. print("注意: 构建完成后请手动运行 'python utils/embed_version_config.py --restore-after' 来恢复备份文件")
  138. return 0
  139. else:
  140. print("版本配置嵌入失败")
  141. return 1
  142. if __name__ == '__main__':
  143. sys.exit(main())