release.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import sys
  2. import os
  3. import json
  4. import zipfile
  5. import argparse
  6. # 切换到项目根目录
  7. os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  8. def get_board_type():
  9. with open("build/compile_commands.json") as f:
  10. data = json.load(f)
  11. for item in data:
  12. if not item["file"].endswith("main.cc"):
  13. continue
  14. command = item["command"]
  15. # extract -DBOARD_TYPE=xxx
  16. board_type = command.split("-DBOARD_TYPE=\\\"")[1].split("\\\"")[0].strip()
  17. return board_type
  18. return None
  19. def get_project_version():
  20. with open("CMakeLists.txt") as f:
  21. for line in f:
  22. if line.startswith("set(PROJECT_VER"):
  23. return line.split("\"")[1].split("\"")[0].strip()
  24. return None
  25. def merge_bin():
  26. if os.system("idf.py merge-bin") != 0:
  27. print("merge bin failed")
  28. sys.exit(1)
  29. def zip_bin(board_type, project_version):
  30. if not os.path.exists("releases"):
  31. os.makedirs("releases")
  32. output_path = f"releases/v{project_version}_{board_type}.zip"
  33. if os.path.exists(output_path):
  34. os.remove(output_path)
  35. with zipfile.ZipFile(output_path, 'w', compression=zipfile.ZIP_DEFLATED) as zipf:
  36. zipf.write("build/merged-binary.bin", arcname="merged-binary.bin")
  37. print(f"zip bin to {output_path} done")
  38. def release_current():
  39. merge_bin()
  40. board_type = get_board_type()
  41. print("board type:", board_type)
  42. project_version = get_project_version()
  43. print("project version:", project_version)
  44. zip_bin(board_type, project_version)
  45. def get_all_board_types():
  46. board_configs = {}
  47. with open("main/CMakeLists.txt", encoding='utf-8') as f:
  48. lines = f.readlines()
  49. for i, line in enumerate(lines):
  50. # 查找 if(CONFIG_BOARD_TYPE_*) 行
  51. if "if(CONFIG_BOARD_TYPE_" in line:
  52. config_name = line.strip().split("if(")[1].split(")")[0]
  53. # 查找下一行的 set(BOARD_TYPE "xxx")
  54. next_line = lines[i + 1].strip()
  55. if next_line.startswith("set(BOARD_TYPE"):
  56. board_type = next_line.split('"')[1]
  57. board_configs[config_name] = board_type
  58. return board_configs
  59. def release(board_type, board_config, config_filename="config.json"):
  60. config_path = f"main/boards/{board_type}/{config_filename}"
  61. if not os.path.exists(config_path):
  62. print(f"跳过 {board_type} 因为 {config_filename} 不存在")
  63. return
  64. # Print Project Version
  65. project_version = get_project_version()
  66. print(f"Project Version: {project_version}", config_path)
  67. with open(config_path, "r") as f:
  68. config = json.load(f)
  69. target = config["target"]
  70. builds = config["builds"]
  71. for build in builds:
  72. name = build["name"]
  73. if not name.startswith(board_type):
  74. raise ValueError(f"name {name} 必须以 {board_type} 开头")
  75. output_path = f"releases/v{project_version}_{name}.zip"
  76. if os.path.exists(output_path):
  77. print(f"跳过 {board_type} 因为 {output_path} 已存在")
  78. continue
  79. sdkconfig_append = [f"{board_config}=y"]
  80. for append in build.get("sdkconfig_append", []):
  81. sdkconfig_append.append(append)
  82. print(f"name: {name}")
  83. print(f"target: {target}")
  84. for append in sdkconfig_append:
  85. print(f"sdkconfig_append: {append}")
  86. # unset IDF_TARGET
  87. os.environ.pop("IDF_TARGET", None)
  88. # Call set-target
  89. if os.system(f"idf.py set-target {target}") != 0:
  90. print("set-target failed")
  91. sys.exit(1)
  92. # Append sdkconfig
  93. with open("sdkconfig", "a") as f:
  94. f.write("\n")
  95. for append in sdkconfig_append:
  96. f.write(f"{append}\n")
  97. # Build with macro BOARD_NAME defined to name
  98. if os.system(f"idf.py -DBOARD_NAME={name} build") != 0:
  99. print("build failed")
  100. sys.exit(1)
  101. # Call merge-bin
  102. if os.system("idf.py merge-bin") != 0:
  103. print("merge-bin failed")
  104. sys.exit(1)
  105. # Zip bin
  106. zip_bin(name, project_version)
  107. print("-" * 80)
  108. if __name__ == "__main__":
  109. parser = argparse.ArgumentParser()
  110. parser.add_argument("board", nargs="?", default=None, help="板子类型或 all")
  111. parser.add_argument("-c", "--config", default="config.json", help="指定 config 文件名,默认 config.json")
  112. args = parser.parse_args()
  113. if args.board:
  114. board_configs = get_all_board_types()
  115. found = False
  116. for board_config, board_type in board_configs.items():
  117. if args.board == 'all' or board_type == args.board:
  118. release(board_type, board_config, config_filename=args.config)
  119. found = True
  120. if not found:
  121. print(f"未找到板子类型: {args.board}")
  122. print("可用的板子类型:")
  123. for board_type in board_configs.values():
  124. print(f" {board_type}")
  125. else:
  126. release_current()