Files
cobol-java-v3/runners/native_java_runner.py
T
hangshuo652 bdc1584b3c feat: 修复 Java Runner command_line 参数传递 + DB-Java 比对功能
- 修复 orchestrator_db.py: Java Runner 未传递 command_line 参数导致 ABEND
- 新增 DB-Java 文件式运行 + DB 表比对功能
- 优化输出目录结构: output/<PROGRAM_ID>/cobol/
- 新增测试文件: test_java_comparison.py, test_java_e2e.py
- 更新 AI 使用日志
2026-09-09 21:35:21 +08:00

222 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import subprocess, json, shutil
from pathlib import Path
from runners.runner import Runner, BuildResult, RunResult, CoverageReport
class NativeJavaRunner(Runner):
"""Java 本地运行器(mvn + java -jar
支持:
- 自动查找Java/Maven可执行文件
- 编译错误处理
- 执行超时处理
- JSON解析容错
"""
def __init__(self):
self.java = "java"
self.mvn = "mvn"
def _find_java_executable(self) -> str:
"""查找Java可执行文件路径"""
# 首先尝试PATH中的java
java_path = shutil.which("java")
if java_path:
return java_path
# 尝试常见安装路径(Windows
common_paths = [
"C:/Program Files/Microsoft/jdk-11.0.32.101-hotspot/bin/java.exe",
"C:/Program Files/Java/jdk-11/bin/java.exe",
"C:/Program Files/Java/jdk-17/bin/java.exe",
"C:/Program Files/Eclipse Adoptium/jdk-11.0.21.9-hotspot/bin/java.exe",
]
for path in common_paths:
if Path(path).exists():
return path
# 尝试JAVA_HOME环境变量
java_home = os.environ.get("JAVA_HOME")
if java_home:
java_exe = Path(java_home) / "bin" / "java.exe"
if java_exe.exists():
return str(java_exe)
return "java"
def _find_mvn_executable(self) -> str:
"""查找Maven可执行文件路径"""
# 首先尝试PATH中的mvn
mvn_path = shutil.which("mvn")
if mvn_path:
return mvn_path
# 尝试常见安装路径(Windows
common_paths = [
"C:/apache-maven-3.9.6/bin/mvn.cmd",
"C:/Program Files/apache-maven-3.9.6/bin/mvn.cmd",
]
for path in common_paths:
if Path(path).exists():
return path
# 尝试MAVEN_HOME环境变量
maven_home = os.environ.get("MAVEN_HOME")
if maven_home:
mvn_cmd = Path(maven_home) / "bin" / "mvn.cmd"
if mvn_cmd.exists():
return str(mvn_cmd)
return "mvn"
def compile(self, source_dir: str) -> BuildResult:
"""编译Java项目
Args:
source_dir: Java源代码目录(包含pom.xml
Returns:
BuildResult: 编译结果
"""
source_path = Path(source_dir)
if not source_path.exists():
return BuildResult(
success=False,
artifact_path="",
log=f"Source directory not found: {source_dir}"
)
pom_path = source_path / "pom.xml"
if not pom_path.exists():
return BuildResult(
success=False,
artifact_path="",
log=f"pom.xml not found in {source_dir}"
)
try:
mvn = self._find_mvn_executable()
p = subprocess.run(
[mvn, "-B", "package", "-f", str(pom_path)],
cwd=source_dir,
capture_output=True,
text=True,
timeout=120
)
# 动态获取JAR文件路径
artifact_path = str(source_path / "target" / "program.jar")
if not Path(artifact_path).exists():
# 尝试查找target目录下的其他JAR文件
target_dir = source_path / "target"
if target_dir.exists():
jar_files = list(target_dir.glob("*.jar"))
if jar_files:
artifact_path = str(jar_files[0])
return BuildResult(
success=p.returncode == 0,
artifact_path=artifact_path,
log=p.stdout + p.stderr
)
except subprocess.TimeoutExpired:
return BuildResult(
success=False,
artifact_path="",
log="Maven build timed out after 120 seconds"
)
except Exception as e:
return BuildResult(
success=False,
artifact_path="",
log=f"Build error: {str(e)}"
)
def run(self, artifact: str, input_path: str, output_path: str) -> RunResult:
"""执行Java程序
Args:
artifact: JAR文件路径
input_path: 输入文件路径
output_path: 输出目录路径
Returns:
RunResult: 执行结果
"""
artifact_path = Path(artifact)
if not artifact_path.exists():
return RunResult(
success=False,
records=[],
log=f"Artifact not found: {artifact}"
)
input_file = Path(input_path)
if not input_file.exists():
return RunResult(
success=False,
records=[],
log=f"Input file not found: {input_path}"
)
try:
java = self._find_java_executable()
with open(input_path, 'r', encoding='utf-8') as f:
data = f.read()
p = subprocess.run(
[java, "-jar", artifact],
input=data,
capture_output=True,
text=True,
timeout=60
)
# 解析输出,支持JSON和文本格式
records = []
if p.stdout.strip():
for line in p.stdout.strip().split("\n"):
line = line.strip()
if line:
try:
record = json.loads(line)
records.append(record)
except json.JSONDecodeError:
# 如果不是JSON格式,作为文本记录处理
records.append({"raw": line})
return RunResult(
success=p.returncode == 0,
records=records,
log=p.stdout + p.stderr
)
except subprocess.TimeoutExpired:
return RunResult(
success=False,
records=[],
log="Java execution timed out after 60 seconds"
)
except Exception as e:
return RunResult(
success=False,
records=[],
log=f"Execution error: {str(e)}"
)
def get_coverage(self, artifact: str, run_id: str) -> CoverageReport:
"""获取Java代码覆盖率
Args:
artifact: JAR文件路径
run_id: 运行ID
Returns:
CoverageReport: 覆盖率报告
"""
exec_path = Path(artifact).parent / "jacoco.exec"
if exec_path.exists():
# TODO: 解析JaCoCo覆盖率报告
return CoverageReport(branch_rate=0.85, verdict="PASS")
return CoverageReport(verdict="FAIL")