import zipfile, os, subprocess, glob, sys, shutil BASE = os.path.dirname(os.path.abspath(__file__)) SRC = os.path.join(BASE, "src", "main", "java") RES = os.path.join(BASE, "src", "main", "resources") OUT = os.path.join(BASE, "build_tmp_classes") LIB = os.path.join(BASE, "lib") JAVAC = r"D:\Program Files\Java\jdk-17\bin\javac.exe" LOMBOK = r"C:\Users\BXD-XTYW\.m2\repository\org\projectlombok\lombok\1.18.32\lombok-1.18.32.jar" SRC_JAR = os.path.join(BASE, "target", "resource-platform-v8.jar") DST_JAR = os.path.join(BASE, "target", "resource-platform-v9.jar") # 1) 准备依赖 classpath: 从 fat jar 抽取 BOOT-INF/lib 到 lib/(若缺失), 并放入 lombok os.makedirs(LIB, exist_ok=True) if not glob.glob(os.path.join(LIB, "*.jar")): with zipfile.ZipFile(SRC_JAR) as z: for name in z.namelist(): if name.startswith("BOOT-INF/lib/") and name.endswith(".jar"): out = os.path.join(LIB, os.path.basename(name)) with open(out, "wb") as f: f.write(z.read(name)) if not os.path.exists(os.path.join(LIB, "lombok-1.18.32.jar")): shutil.copy(LOMBOK, os.path.join(LIB, "lombok-1.18.32.jar")) dep_jars = sorted(glob.glob(os.path.join(LIB, "*.jar"))) cp = ";".join(dep_jars) print("classpath entries:", len(dep_jars)) # 2) 编译全部源码 sources = [] for root, _, files in os.walk(SRC): for f in files: if f.endswith(".java"): sources.append(os.path.join(root, f)) print("source files:", len(sources)) os.makedirs(OUT, exist_ok=True) cmd = [JAVAC, "-parameters", "-encoding", "UTF-8", "-cp", cp, "-d", OUT] + sources r = subprocess.run(cmd, capture_output=True) print("javac returncode:", r.returncode) if r.returncode != 0: err = (r.stderr or b"").decode("utf-8", "replace") print("=== STDERR (first 60 lines) ===") print("\n".join(err.splitlines()[:60])) sys.exit(1) print("compiled classes:", len(glob.glob(os.path.join(OUT, "**", "*.class"), recursive=True))) # 3) 重打包: 以 v8 为基底, 替换最新编译的 class, 并注入 src/main/resources 中的资源(xml等) with zipfile.ZipFile(SRC_JAR) as zin: infos = zin.infolist() def local_for(entry_name): if entry_name.startswith("BOOT-INF/classes/") and entry_name.endswith(".class"): rel = entry_name[len("BOOT-INF/classes/"):] local = os.path.join(OUT, rel) if os.path.isfile(local): return local return None if entry_name.startswith("BOOT-INF/classes/"): rel = entry_name[len("BOOT-INF/classes/"):] local = os.path.join(RES, rel) if os.path.isfile(local): return local return None manifest_name = "META-INF/MANIFEST.MF" all_names = set(zin.namelist()) extra_resources = [] for root, _, files in os.walk(RES): for f in files: full = os.path.join(root, f) rel = os.path.relpath(full, RES).replace("\\", "/") entry = "BOOT-INF/classes/" + rel if entry not in all_names: extra_resources.append((entry, full)) # 源码中新增的类, 在基底 jar 里原本不存在, 需补打到新 jar extra_classes = [] for root, _, files in os.walk(OUT): for f in files: if f.endswith(".class"): full = os.path.join(root, f) rel = os.path.relpath(full, OUT).replace("\\", "/") entry = "BOOT-INF/classes/" + rel if entry not in all_names: extra_classes.append((entry, full)) with zipfile.ZipFile(DST_JAR, "w", compression=zipfile.ZIP_DEFLATED) as zout: mi = next(i for i in infos if i.filename == manifest_name) zout.writestr(mi, zin.read(manifest_name)) for i in infos: if i.filename == manifest_name: continue local = local_for(i.filename) if local: with open(local, "rb") as lf: data = lf.read() zi = zipfile.ZipInfo(i.filename) zi.external_attr = i.external_attr zi.date_time = i.date_time zout.writestr(zi, data) else: zout.writestr(i, zin.read(i.filename)) for entry, full in extra_resources: with open(full, "rb") as lf: data = lf.read() zout.writestr(zipfile.ZipInfo(entry), data) for entry, full in extra_classes: with open(full, "rb") as lf: data = lf.read() zout.writestr(zipfile.ZipInfo(entry), data) print("built:", DST_JAR, "exists:", os.path.exists(DST_JAR)) zm = zipfile.ZipFile(DST_JAR) print("manifest first:", zm.namelist()[0] == manifest_name) # 校验关键新类已打入 for cls in ["ProcurementCostExportVO.class", "ProcurementCostQuery.class", "ResourceController.class", "ResourceServiceImpl.class"]: entry = "BOOT-INF/classes/com/example/resourceplatform/" + ( "dto/" if cls.endswith("VO.class") or "Query" in cls else "controller/" if "Controller" in cls else "service/impl/") entry = entry + cls print("contains", entry, ":", entry in zm.namelist())