#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Pack a project (Bootloader/ or App/) together with the shared layers (top-level Drivers/ + Shared/) into a sendable zip. Structure change (2026-08-18): Drivers/ and Shared/ now live at the repo top level and are shared by both projects. The zip reproduces the same layout, so the receiver unzips anywhere and the ..\\..\\Drivers / ..\\..\\Shared references in the .uvprojx resolve correctly. Usage: python pack.py bl -> Output/bootloader_package.zip python pack.py app -> Output/app_package.zip Intermediate build artifacts (.o/.d/.crf/.axf/... and MDK Objects/Output/Listings) are excluded to keep the package small and clean. """ import os import sys import zipfile ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # intermediate build artifacts to exclude from the zip EXCLUDE_EXT = {'.o', '.d', '.crf', '.axf', '.lst', '.dep', '.htm', '.map', '.bak', '.uvguix'} # MDK build-output dirs (case-insensitive) - never descend into them EXCLUDE_DIRS = {'objects', 'output', 'listings'} def add_dir(zf, src_dir, arc_base): """Add src_dir tree into zip under arc_base, skipping build artifacts.""" n = 0 for base, dirs, files in os.walk(src_dir): rel = os.path.relpath(base, src_dir) parts = [p.lower() for p in rel.split(os.sep) if p not in ('', '.')] if any(p in EXCLUDE_DIRS for p in parts): dirs[:] = [] # do not descend into MDK build-output dirs continue for f in files: if os.path.splitext(f)[1].lower() in EXCLUDE_EXT: continue src = os.path.join(base, f) dst = os.path.join(arc_base, rel, f) if rel != '.' else os.path.join(arc_base, f) zf.write(src, dst) n += 1 return n def pack(proj, zip_path): """zip 内布局与仓库一致: / + Drivers/ + Shared/(共享层来自顶层)""" n = 0 with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf: n += add_dir(zf, os.path.join(ROOT, proj), proj) n += add_dir(zf, os.path.join(ROOT, 'Drivers'), 'Drivers') n += add_dir(zf, os.path.join(ROOT, 'Shared'), 'Shared') return n def main(): if len(sys.argv) < 2: print('usage: python pack.py bl|app') sys.exit(1) mode = sys.argv[1].lower() if mode == 'bl': proj, zipname, uv = 'Bootloader', 'bootloader_package.zip', 'Bootloader.uvprojx' elif mode == 'app': proj, zipname, uv = 'App', 'app_package.zip', 'project.uvprojx' else: print('unknown mode: %s (use bl or app)' % mode) sys.exit(1) out_dir = os.path.join(ROOT, 'Output') os.makedirs(out_dir, exist_ok=True) zip_path = os.path.join(out_dir, zipname) # 注:不预先删除旧 zip('w' 模式会直接截断覆盖,避免依赖删除旧文件的权限/回收站) n = pack(proj, zip_path) print('[OK] %d files -> %s' % (n, zip_path)) print(' zip layout: %s/ + Drivers/ + Shared/ (same as repo, unzip anywhere)' % proj) print(' receiver: unzip, open %s\\MDK-ARM\\%s in Keil and build.' % (proj, uv)) if __name__ == '__main__': main()