import sys import os import json import zipfile import argparse # 切换到项目根目录 os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) def get_board_type(): with open("build/compile_commands.json") as f: data = json.load(f) for item in data: if not item["file"].endswith("main.cc"): continue command = item["command"] # extract -DBOARD_TYPE=xxx board_type = command.split("-DBOARD_TYPE=\\\"")[1].split("\\\"")[0].strip() return board_type return None def get_project_version(): with open("CMakeLists.txt") as f: for line in f: if line.startswith("set(PROJECT_VER"): return line.split("\"")[1].split("\"")[0].strip() return None def merge_bin(): if os.system("idf.py merge-bin") != 0: print("merge bin failed") sys.exit(1) def zip_bin(board_type, project_version): if not os.path.exists("releases"): os.makedirs("releases") output_path = f"releases/v{project_version}_{board_type}.zip" if os.path.exists(output_path): os.remove(output_path) with zipfile.ZipFile(output_path, 'w', compression=zipfile.ZIP_DEFLATED) as zipf: zipf.write("build/merged-binary.bin", arcname="merged-binary.bin") print(f"zip bin to {output_path} done") def release_current(): merge_bin() board_type = get_board_type() print("board type:", board_type) project_version = get_project_version() print("project version:", project_version) zip_bin(board_type, project_version) def get_all_board_types(): board_configs = {} with open("main/CMakeLists.txt", encoding='utf-8') as f: lines = f.readlines() for i, line in enumerate(lines): # 查找 if(CONFIG_BOARD_TYPE_*) 行 if "if(CONFIG_BOARD_TYPE_" in line: config_name = line.strip().split("if(")[1].split(")")[0] # 查找下一行的 set(BOARD_TYPE "xxx") next_line = lines[i + 1].strip() if next_line.startswith("set(BOARD_TYPE"): board_type = next_line.split('"')[1] board_configs[config_name] = board_type return board_configs def release(board_type, board_config, config_filename="config.json"): config_path = f"main/boards/{board_type}/{config_filename}" if not os.path.exists(config_path): print(f"跳过 {board_type} 因为 {config_filename} 不存在") return # Print Project Version project_version = get_project_version() print(f"Project Version: {project_version}", config_path) with open(config_path, "r") as f: config = json.load(f) target = config["target"] builds = config["builds"] for build in builds: name = build["name"] if not name.startswith(board_type): raise ValueError(f"name {name} 必须以 {board_type} 开头") output_path = f"releases/v{project_version}_{name}.zip" if os.path.exists(output_path): print(f"跳过 {board_type} 因为 {output_path} 已存在") continue sdkconfig_append = [f"{board_config}=y"] for append in build.get("sdkconfig_append", []): sdkconfig_append.append(append) print(f"name: {name}") print(f"target: {target}") for append in sdkconfig_append: print(f"sdkconfig_append: {append}") # unset IDF_TARGET os.environ.pop("IDF_TARGET", None) # Call set-target if os.system(f"idf.py set-target {target}") != 0: print("set-target failed") sys.exit(1) # Append sdkconfig with open("sdkconfig", "a") as f: f.write("\n") for append in sdkconfig_append: f.write(f"{append}\n") # Build with macro BOARD_NAME defined to name if os.system(f"idf.py -DBOARD_NAME={name} build") != 0: print("build failed") sys.exit(1) # Call merge-bin if os.system("idf.py merge-bin") != 0: print("merge-bin failed") sys.exit(1) # Zip bin zip_bin(name, project_version) print("-" * 80) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("board", nargs="?", default=None, help="板子类型或 all") parser.add_argument("-c", "--config", default="config.json", help="指定 config 文件名,默认 config.json") args = parser.parse_args() if args.board: board_configs = get_all_board_types() found = False for board_config, board_type in board_configs.items(): if args.board == 'all' or board_type == args.board: release(board_type, board_config, config_filename=args.config) found = True if not found: print(f"未找到板子类型: {args.board}") print("可用的板子类型:") for board_type in board_configs.values(): print(f" {board_type}") else: release_current()