上传代码
This commit is contained in:
@@ -7,12 +7,22 @@ import json
|
||||
import shutil
|
||||
import threading
|
||||
import atexit
|
||||
import tempfile
|
||||
|
||||
# ==================== BCL 工具配置 ====================
|
||||
# 相对于本脚本所在目录的 BwZipBCLTool.exe 路径(位于 `project2json/解压计算配置工具/` 下)
|
||||
BCL_TOOL_RELATIVE_PATH = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"解压计算配置工具",
|
||||
"BwZipBCLTool.exe",
|
||||
)
|
||||
# ======================================================
|
||||
|
||||
# ==================== 配置区 ====================
|
||||
JAVA_WORKING_DIR = "D:/eclipseworkspace/bwyAnalysis2.3.2/analysis-server"
|
||||
JAR_NAME = "booway-analysis-server-null.jar"
|
||||
SERVER_URL = "http://localhost:8090/api/doAnalysis"
|
||||
# ==============================================
|
||||
# ================================================
|
||||
|
||||
# 全局变量:Java 进程
|
||||
java_process = None
|
||||
@@ -81,37 +91,218 @@ def check_server_ready(timeout=30):
|
||||
|
||||
def convert_json_to_readable(input_file, output_file=None):
|
||||
"""
|
||||
将JSON文件转换为可读格式并保存
|
||||
|
||||
参数:
|
||||
input_file: 输入JSON文件路径
|
||||
output_file: 输出文件路径,如果为None则自动生成
|
||||
升级版:支持编码检测和容错
|
||||
"""
|
||||
if output_file is None:
|
||||
base_name = os.path.splitext(input_file)[0]
|
||||
output_file = f"{base_name}_pretty.json"
|
||||
|
||||
# 确保输出目录存在
|
||||
os.makedirs(os.path.dirname(output_file) if os.path.dirname(output_file) else ".", exist_ok=True)
|
||||
|
||||
encodings = ["utf-8", "gbk", "gb18030", "latin1"] # 常见编码
|
||||
data = None
|
||||
|
||||
for enc in encodings:
|
||||
try:
|
||||
with open(input_file, "r", encoding=enc) as f:
|
||||
data = json.load(f)
|
||||
print(f"✔ 使用编码 {enc} 成功读取 {input_file}")
|
||||
break
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"❌ 读取失败 {input_file}: {e}")
|
||||
return None
|
||||
|
||||
if data is None:
|
||||
print(f"❌ 所有编码尝试失败: {input_file}")
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(input_file, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
if output_file is None:
|
||||
base_name = os.path.splitext(input_file)[0]
|
||||
output_file = f"{base_name}.json"
|
||||
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f"✅ JSON美化成功: {output_file}")
|
||||
print(f"✅ 美化成功: {output_file}")
|
||||
return output_file
|
||||
except Exception as e:
|
||||
print(f"❌ 转换JSON失败 {input_file}: {e}")
|
||||
print(f"❌ 写入失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def convert_project_to_json(input_folder, output_folder):
|
||||
def _parse_version_key(name: str):
|
||||
"""将形如 '1.20' 的版本字符串转换为可比较的元组。(主, 次, 补丁...)
|
||||
非法格式将返回一个极小值以便被忽略。
|
||||
"""
|
||||
try:
|
||||
parts = [int(p) for p in name.strip().split(".") if p.isdigit()]
|
||||
if not parts:
|
||||
return (-1,)
|
||||
return tuple(parts)
|
||||
except Exception:
|
||||
return (-1,)
|
||||
|
||||
|
||||
def _copy_dir_contents(src_dir: str, dst_dir: str):
|
||||
"""将 src_dir 下的所有文件/子目录复制到 dst_dir(不包含 src_dir 这一层目录)。"""
|
||||
os.makedirs(dst_dir, exist_ok=True)
|
||||
for entry in os.listdir(src_dir):
|
||||
s = os.path.join(src_dir, entry)
|
||||
d = os.path.join(dst_dir, entry)
|
||||
if os.path.isdir(s):
|
||||
# 复制子目录
|
||||
if os.path.exists(d):
|
||||
shutil.rmtree(d)
|
||||
shutil.copytree(s, d)
|
||||
else:
|
||||
shutil.copy2(s, d)
|
||||
|
||||
|
||||
def run_bcl_tool_and_copy_best(
|
||||
project_path: str,
|
||||
final_copy_dir: str,
|
||||
desktop_base: str = None,
|
||||
exe_path: str = None,
|
||||
exts: tuple[str, ...] | None = None,
|
||||
cleanup_temp: bool = True,
|
||||
):
|
||||
"""
|
||||
运行 BwZipBCLTool.exe 解析 BCL,并将临时输出目录下“版本号最大”的子文件夹内容复制到 final_copy_dir。
|
||||
|
||||
参数:
|
||||
project_path: .zwqd 工程文件路径或包含该文件的目录
|
||||
final_copy_dir: 版本号最大的文件夹内的所有文件复制到的最终目录
|
||||
desktop_base: 临时输出目录所在的桌面路径,默认为当前用户桌面
|
||||
exe_path: BwZipBCLTool.exe 的完整路径,默认使用 BCL_TOOL_RELATIVE_PATH
|
||||
|
||||
返回:
|
||||
(bool, str): (是否成功, 最佳版本目录路径或错误信息)
|
||||
"""
|
||||
try:
|
||||
exe_path = exe_path or BCL_TOOL_RELATIVE_PATH
|
||||
if not os.path.exists(exe_path):
|
||||
return False, f"未找到 BCL 工具: {exe_path}"
|
||||
|
||||
# 构建候选工程文件列表
|
||||
# 默认:尝试目录内所有文件;若传入 exts,则只筛选指定后缀
|
||||
candidates: list[str] = []
|
||||
if os.path.isfile(project_path):
|
||||
candidates = [project_path]
|
||||
elif os.path.isdir(project_path):
|
||||
names = sorted(os.listdir(project_path))
|
||||
if exts:
|
||||
lower_exts = tuple(e.lower() for e in exts)
|
||||
candidates.extend([os.path.join(project_path, n) for n in names if n.lower().endswith(lower_exts)])
|
||||
else:
|
||||
candidates.extend(
|
||||
[os.path.join(project_path, n) for n in names if os.path.isfile(os.path.join(project_path, n))]
|
||||
)
|
||||
else:
|
||||
return False, f"路径不存在: {project_path}"
|
||||
|
||||
if not candidates:
|
||||
return False, f"在 '{project_path}' 未找到可供解析的工程文件"
|
||||
|
||||
last_error = None
|
||||
for eng_file in candidates:
|
||||
# 临时目录放到桌面
|
||||
if desktop_base is None:
|
||||
desktop_base = os.path.join(os.path.expanduser("~"), "Desktop")
|
||||
os.makedirs(desktop_base, exist_ok=True)
|
||||
temp_out_dir = tempfile.mkdtemp(prefix="bcl_", dir=desktop_base)
|
||||
|
||||
print(f"🚀 调用 BCL 工具: {exe_path}")
|
||||
print(f" ├─ 工程文件: {eng_file}")
|
||||
print(f" └─ 临时输出: {temp_out_dir}")
|
||||
|
||||
try:
|
||||
# 运行外部工具
|
||||
result = subprocess.run(
|
||||
[exe_path, eng_file, temp_out_dir],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
shell=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
stderr = (result.stderr or "").strip()
|
||||
stdout = (result.stdout or "").strip()
|
||||
last_error = f"BCL 工具执行失败 (code={result.returncode})\nSTDOUT: {stdout}\nSTDERR: {stderr}"
|
||||
continue
|
||||
|
||||
# 在临时目录下查找版本号子目录
|
||||
subdirs = [d for d in os.listdir(temp_out_dir) if os.path.isdir(os.path.join(temp_out_dir, d))]
|
||||
if not subdirs:
|
||||
last_error = f"BCL 工具未在输出目录生成任何子目录: {temp_out_dir}"
|
||||
continue
|
||||
|
||||
best_dir_name = max(subdirs, key=_parse_version_key)
|
||||
best_dir_path = os.path.join(temp_out_dir, best_dir_name)
|
||||
print(f"🏆 发现最佳版本目录: {best_dir_name}")
|
||||
|
||||
# 若下层只有单一子目录则继续下探;若存在多个子目录,且其名称像版本号(如 1.2.13),则选取版本号最大者继续下探
|
||||
def _descend_if_single_subdir(path: str) -> str:
|
||||
try:
|
||||
while True:
|
||||
entries = [os.path.join(path, e) for e in os.listdir(path)]
|
||||
files = [p for p in entries if os.path.isfile(p)]
|
||||
dirs = [p for p in entries if os.path.isdir(p)]
|
||||
if files:
|
||||
return path
|
||||
if len(dirs) == 1:
|
||||
path = dirs[0]
|
||||
continue
|
||||
if len(dirs) > 1:
|
||||
# 如果多子目录都像版本号,则选择最大的版本继续下探
|
||||
dir_names = [os.path.basename(d) for d in dirs]
|
||||
|
||||
def looks_like_version(name: str) -> bool:
|
||||
parts = name.split(".")
|
||||
if not parts:
|
||||
return False
|
||||
return all(p.isdigit() for p in parts)
|
||||
|
||||
version_like = [d for d, n in zip(dirs, dir_names) if looks_like_version(n)]
|
||||
if version_like:
|
||||
best_dir = max(version_like, key=lambda p: _parse_version_key(os.path.basename(p)))
|
||||
path = best_dir
|
||||
continue
|
||||
# 否则停止下探,返回当前层
|
||||
return path
|
||||
return path
|
||||
except Exception:
|
||||
return path
|
||||
|
||||
copy_root = _descend_if_single_subdir(best_dir_path)
|
||||
|
||||
# 复制内容到最终目录
|
||||
os.makedirs(final_copy_dir, exist_ok=True)
|
||||
_copy_dir_contents(copy_root, final_copy_dir)
|
||||
print(f"✅ 已将最佳版本目录内的文件复制到: {final_copy_dir}")
|
||||
|
||||
return True, copy_root
|
||||
finally:
|
||||
if cleanup_temp:
|
||||
try:
|
||||
shutil.rmtree(temp_out_dir, ignore_errors=True)
|
||||
# print(f"🧹 已清理临时目录: {temp_out_dir}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 所有候选均失败
|
||||
return False, (last_error or "未找到可用的工程文件以执行 BCL 工具")
|
||||
except Exception as e:
|
||||
return False, f"运行 BCL 工具出错: {e}"
|
||||
|
||||
|
||||
def convert_project_to_json(input_folder, output_folder, best_version_dest_folder=None):
|
||||
"""
|
||||
将工程文件夹转换为JSON,并移动到输出文件夹(含美化)
|
||||
|
||||
参数:
|
||||
input_folder: 工程文件所在目录(包含 .zwzj 文件)
|
||||
output_folder: 转换后的 JSON 文件输出目录
|
||||
best_version_dest_folder: 若提供,则会在流程开始前运行 BCL 工具,并将最佳版本目录内容复制到该路径
|
||||
|
||||
返回:
|
||||
tuple(bool, int): (是否成功, 成功转移并美化的文件数量)
|
||||
@@ -147,13 +338,21 @@ def convert_project_to_json(input_folder, output_folder):
|
||||
print(f"❌ 创建输出目录失败: {e}")
|
||||
return False, 0
|
||||
|
||||
# 3. 启动 Java 服务
|
||||
# 3. 若用户指定了 BCL 最终复制目录,则先进行 BCL 解析与复制
|
||||
if best_version_dest_folder:
|
||||
ok, info = run_bcl_tool_and_copy_best(input_folder, best_version_dest_folder)
|
||||
if ok:
|
||||
print(f"🧩 BCL 解析已完成,最佳版本输出目录: {info}")
|
||||
else:
|
||||
print(f"⚠️ BCL 解析步骤失败: {info}")
|
||||
|
||||
# 4. 启动 Java 服务
|
||||
if not start_java_server():
|
||||
return False, 0
|
||||
if not check_server_ready():
|
||||
return False, 0
|
||||
|
||||
# 4. 调用 API 开始分析
|
||||
# 5. 调用 API 开始分析
|
||||
params = {"filePath": input_folder.replace("\\", "/")}
|
||||
print(f"🌐 调用 API: {SERVER_URL}?{requests.compat.urlencode(params)}")
|
||||
|
||||
@@ -171,10 +370,10 @@ def convert_project_to_json(input_folder, output_folder):
|
||||
print(f"❌ 调用 API 出错: {e}")
|
||||
return False, 0
|
||||
|
||||
# 5. 等待并检测 JSON 文件生成完成(改进版)
|
||||
# 6. 等待并检测 JSON 文件生成完成(改进版)
|
||||
print("⏳ 正在等待 JSON 文件生成完成...")
|
||||
json_files = []
|
||||
max_wait_time = 600
|
||||
max_wait_time = 6000
|
||||
check_interval = 2
|
||||
|
||||
start_time = time.time()
|
||||
@@ -209,7 +408,7 @@ def convert_project_to_json(input_folder, output_folder):
|
||||
print(f"❌ 在 {max_wait_time} 秒内未生成任何 JSON 文件。")
|
||||
return False, 0
|
||||
|
||||
# 6. 查找所有 .json 文件
|
||||
# 7. 查找所有 .json 文件
|
||||
json_files = [f for f in os.listdir(input_folder) if f.endswith(".json")]
|
||||
if not json_files:
|
||||
print(f"❌ 未在 {input_folder} 中生成 JSON 文件。")
|
||||
@@ -217,7 +416,7 @@ def convert_project_to_json(input_folder, output_folder):
|
||||
|
||||
print(f"📄 发现 {len(json_files)} 个 JSON 文件: {json_files}")
|
||||
|
||||
# 7. 转换为可读格式并移动到输出目录
|
||||
# 8. 转换为可读格式并移动到输出目录
|
||||
transferred_count = 0
|
||||
for file_name in json_files:
|
||||
src_path = os.path.join(input_folder, file_name)
|
||||
@@ -255,10 +454,11 @@ atexit.register(cleanup)
|
||||
# ==================== 使用示例 ====================
|
||||
if __name__ == "__main__":
|
||||
# 示例调用
|
||||
input_dir = r"project2json/uploads"
|
||||
output_dir = r"project2json/outputs/json"
|
||||
input_dir = r"data/output/uploads"
|
||||
output_dir = r"data/output/json"
|
||||
best_bcl_dest = r"data/output/bcl"
|
||||
|
||||
success = convert_project_to_json(input_dir, output_dir)
|
||||
success, _count = convert_project_to_json(input_dir, output_dir, best_bcl_dest)
|
||||
|
||||
if success:
|
||||
print("\n🎉 ✅ 全部流程执行成功!")
|
||||
|
||||
Reference in New Issue
Block a user