Files
starRiverProperty/scripts/decompile_ninca_crk_lib_modules.py
反编译工作区 8b15445328 feat: add service config templates and extraction script
Former-commit-id: 1de24b7eb79676d1aba9d799a58c5a753290cf52
2026-05-01 19:38:01 +08:00

270 lines
10 KiB
Python

#!/usr/bin/env python3
"""
Extract listed ninca-crk-* lib jars from fat jar, CFR-decompile each into maven-ninca-crk-from-lib/<artifactId>/,
emit parent + child POMs (embedded pom from jar when present, sanitized parent).
"""
from __future__ import annotations
import os
import re
import shutil
import subprocess
import sys
import tempfile
import zipfile
from pathlib import Path
FAT_JAR_DEFAULT = Path(
"/media/zebra/9e8fa357-7db6-4d70-88ed-d5de5a059a663/"
"星河湾星中星/星中心/ninca_crk_std_01-ninca_crk_std_backend/ninca-crk-std-backend-V2.9.2_20210730.jar"
)
REPO_ROOT = Path(__file__).resolve().parents[1]
OUT_ROOT = REPO_ROOT / "maven-ninca-crk-from-lib"
CFR_JAR = Path("/tmp/cfr-0.152.jar")
TARGET_NAMES = [
"ninca-crk-access-control-biz-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-access-control-common-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-access-control-data-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-access-control-facade-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-access-control-interface-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-access-control-service-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-access-control-web-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-conference-attendance-biz-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-conference-attendance-common-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-conference-attendance-data-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-conference-attendance-facade-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-conference-attendance-interface-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-conference-attendance-service-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-conference-attendance-web-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-smart-attendance-biz-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-smart-attendance-common-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-smart-attendance-data-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-smart-attendance-facade-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-smart-attendance-interface-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-smart-attendance-service-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-smart-attendance-web-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-visitor-management-biz-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-visitor-management-common-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-visitor-management-data-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-visitor-management-facade-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-visitor-management-interface-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-visitor-management-service-2.9.1_210630-SNAPSHOT.jar",
"ninca-crk-visitor-management-web-2.9.1_210630-SNAPSHOT.jar",
]
GROUP_ID = "cn.cloudwalk.ninca"
REACTOR_VERSION = "2.9.1_210630-SNAPSHOT"
JAVA_VERSION = "1.8"
def artifact_dir(jar_name: str) -> str:
return jar_name.replace(".jar", "").replace("-2.9.1_210630-SNAPSHOT", "")
def ensure_cfr() -> Path:
if CFR_JAR.is_file():
return CFR_JAR
raise SystemExit(
"Missing CFR at {} — download:\n"
" curl -fsSL -o {} "
"https://github.com/leibnitz27/cfr/releases/download/0.152/cfr-0.152.jar".format(CFR_JAR, CFR_JAR)
)
def extract_embedded_pom(zf: zipfile.ZipFile, inner_path: str) -> str | None:
try:
return zf.read(inner_path).decode("utf-8", errors="replace")
except KeyError:
return None
def find_embedded_pom_xml(zf: zipfile.ZipFile) -> tuple[str | None, str | None]:
"""Return (pom_xml_content, relative_path_in_zip)."""
for n in zf.namelist():
if n.endswith("/pom.xml") and "/META-INF/maven/" in n and "/ninca-crk-" in n:
return extract_embedded_pom(zf, n), n
return None, None
def sanitize_pom_xml(raw: str, artifact_id: str) -> str:
"""Remove embedded parent; attach reactor parent after modelVersion."""
raw = raw.lstrip("\ufeff").strip()
raw = re.sub(r"<parent\b[^>]*>[\s\S]*?</parent>\s*", "", raw, count=1, flags=re.I)
parent_block = (
" <parent>\n"
" <groupId>%s</groupId>\n"
" <artifactId>ninca-crk-from-lib-reactor</artifactId>\n"
" <version>%s</version>\n"
" <relativePath>../pom.xml</relativePath>\n"
" </parent>\n" % (GROUP_ID, REACTOR_VERSION)
)
m = re.search(r"</modelVersion>\s*", raw, flags=re.I)
if not m:
raise ValueError("embedded pom missing modelVersion")
pos = m.end()
return raw[:pos] + parent_block + raw[pos:]
def minimal_pom(artifact_id: str, description: str) -> str:
return """<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>{gid}</groupId>
<artifactId>ninca-crk-from-lib-reactor</artifactId>
<version>{ver}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>{aid}</artifactId>
<name>{aid}</name>
<description>{desc}</description>
<properties>
<maven.compiler.source>{jv}</maven.compiler.source>
<maven.compiler.target>{jv}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
""".format(
gid=GROUP_ID,
ver=REACTOR_VERSION,
aid=artifact_id,
desc=description,
jv=JAVA_VERSION,
)
def reactor_pom(module_dirs: list[str]) -> str:
mods = "".join(" <module>{}</module>\n".format(m) for m in module_dirs)
return """<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>{gid}</groupId>
<artifactId>ninca-crk-from-lib-reactor</artifactId>
<version>{ver}</version>
<packaging>pom</packaging>
<name>ninca-crk-from-lib-reactor</name>
<description>
CFR 反编译自交付 fat jar lib/ 内 ninca-crk 四条业务线(access-control / conference-attendance /
smart-attendance / visitor-management)共 28 个构件;用于源码走查与对照,不代表官方原始工程结构。
</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>{jv}</java.version>
<maven.compiler.source>${{java.version}}</maven.compiler.source>
<maven.compiler.target>${{java.version}}</maven.compiler.target>
</properties>
<modules>
{mods} </modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${{java.version}}</source>
<target>${{java.version}}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
""".format(
gid=GROUP_ID,
ver=REACTOR_VERSION,
mods=mods,
jv=JAVA_VERSION,
)
def run_cfr(jar_path: Path, java_out: Path) -> None:
java_out.mkdir(parents=True, exist_ok=True)
cmd = [
"java",
"-jar",
str(ensure_cfr()),
str(jar_path),
"--outputdir",
str(java_out),
"--silent",
"true",
]
subprocess.run(cmd, check=True)
def main() -> int:
fat_jar = Path(sys.argv[1]) if len(sys.argv) > 1 else FAT_JAR_DEFAULT
if not fat_jar.is_file():
print("Fat jar not found:", fat_jar, file=sys.stderr)
return 1
if OUT_ROOT.exists():
shutil.rmtree(OUT_ROOT)
OUT_ROOT.mkdir(parents=True)
module_dirs: list[str] = []
tmpdir = Path(tempfile.mkdtemp(prefix="crk_lib_extract_"))
try:
with zipfile.ZipFile(fat_jar, "r") as zf:
for name in TARGET_NAMES:
inner = "lib/" + name
if inner not in zf.namelist():
print("MISSING in fat jar:", inner, file=sys.stderr)
return 2
extract_path = tmpdir / name
with zf.open(inner) as src, open(extract_path, "wb") as dst:
shutil.copyfileobj(src, dst)
aid = artifact_dir(name)
mod_path = OUT_ROOT / aid
mod_path.mkdir(parents=True)
java_root = mod_path / "src" / "main" / "java"
java_root.mkdir(parents=True)
run_cfr(extract_path, java_root)
with zipfile.ZipFile(extract_path, "r") as inner_zf:
embedded, emb_path = find_embedded_pom_xml(inner_zf)
desc = "CFR from {} (embedded pom: {})".format(name, emb_path or "none")
if embedded:
try:
pom_body = sanitize_pom_xml(embedded, aid)
(mod_path / "pom.xml").write_text(pom_body, encoding="utf-8")
except Exception as exc:
print("WARN sanitize pom:", aid, exc, file=sys.stderr)
(mod_path / "pom.xml").write_text(minimal_pom(aid, desc), encoding="utf-8")
else:
(mod_path / "pom.xml").write_text(minimal_pom(aid, desc), encoding="utf-8")
module_dirs.append(aid)
(OUT_ROOT / "pom.xml").write_text(reactor_pom(module_dirs), encoding="utf-8")
readme = OUT_ROOT / "README.txt"
readme.write_text(
"Generated by scripts/decompile_ninca_crk_lib_modules.py\n"
"Source fat jar: {}\n".format(fat_jar)
+ "CFR: {}\n".format(CFR_JAR)
+ "\n反编译产物仅供走查;首次编译需在私服可用的环境下补齐依赖。\n",
encoding="utf-8",
)
finally:
shutil.rmtree(tmpdir, ignore_errors=True)
print("OK ->", OUT_ROOT)
return 0
if __name__ == "__main__":
sys.exit(main())