-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrunTask.py
More file actions
286 lines (245 loc) · 9.48 KB
/
runTask.py
File metadata and controls
286 lines (245 loc) · 9.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import time
import argparse
import subprocess
import psutil
import csv
from pathlib import Path
from datetime import datetime
# ==================== 用户配置区 ====================
JAVA_VERSIONS = {
"8": "/home/byx/.jdks/corretto-1.8.0_442/bin/java", # Java 8 路径
"17": "/home/byx/.jdks/corretto-17.0.14/bin/java" # Java 11 路径
}
JAR_TASKS = {
# 格式:任务名 -> (JAR路径, 配置文件名, 工作目录)
"cha": (
"/home/byx/projects/Tai-e/build/tai-e-all-0.5.2-SNAPSHOT.jar",
"cha-config.yml",
"/home/byx/projects/Tai-e" # None表示使用项目目录
),
"cs1call": (
"/home/byx/projects/Tai-e/build/tai-e-all-0.5.2-SNAPSHOT.jar",
"cs1call-config.yml",
"/home/byx/projects/Tai-e" # None表示使用项目目录
),
"ci": (
"/home/byx/projects/Tai-e/build/tai-e-all-0.5.2-SNAPSHOT.jar",
"ci-config.yml",
"/home/byx/projects/Tai-e" # None表示使用项目目录
),
"ci_app": (
"/home/byx/projects/Tai-e/build/tai-e-all-0.5.2-SNAPSHOT.jar",
"ci_app-config.yml",
"/home/byx/projects/Tai-e"
)
}
# ==================================================
def load_excluded_projects(csv_path):
"""读取特殊异常项目列表"""
excluded = []
try:
with open(csv_path, 'r', newline='', encoding='utf-8') as f:
reader = csv.reader(f)
# 跳过可能存在的标题行 [3](@ref)
header = next(reader, None) # 兼容空文件
# 读取所有行的第一列数据 [3,5](@ref)
excluded = [row[0] for row in reader if row]
except FileNotFoundError:
print(f"警告:未找到文件 {csv_path}")
return excluded
def run_command(task_name: str, java_path: str, jar_path: str,
config_file: str, project_dir: Path,
work_dir: Path = None):
"""执行命令并生成任务专属日志"""
# 创建任务专属日志目录
task_log_dir = project_dir / f"{task_name}_logs"
task_log_dir.mkdir(exist_ok=True)
# 生成带时间戳的日志文件
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
log_file = task_log_dir / f"run_{timestamp}.log"
# 确定工作目录
final_work_dir = work_dir or project_dir
final_work_dir = final_work_dir.resolve()
# 构建命令
cmd = [
java_path,
"-jar", jar_path,
"--options-file", str(project_dir / config_file)
]
# 执行监控
start_time = time.time()
peak_mem = 0
exit_code = -1
try:
with open(log_file, "w") as log_handle:
# 记录元信息
log_handle.write(
f"[Task Info]\n"
f"Task Name: {task_name}\n"
f"Java Path: {java_path}\n"
f"JAR Path: {jar_path}\n"
f"Config File: {config_file}\n"
f"Project Dir: {project_dir}\n"
f"Work Dir: {final_work_dir}\n"
f"Log File: {log_file}\n"
f"\n[Command]\n{' '.join(cmd)}\n\n"
f"[Output]\n"
)
# 启动进程
process = subprocess.Popen(
cmd,
stdout=log_handle,
stderr=subprocess.STDOUT,
cwd=final_work_dir,
text=True
)
# 内存监控
ps_process = psutil.Process(process.pid)
while process.poll() is None:
try:
mem = ps_process.memory_info().rss
peak_mem = max(peak_mem, mem)
time.sleep(0.1)
except (psutil.NoSuchProcess, psutil.AccessDenied):
break
exit_code = process.wait()
except Exception as e:
with open(log_file, "a") as f:
f.write(f"\n[ERROR] {str(e)}")
# 记录性能数据
with open(log_file, "a") as f:
f.write(
f"\n[Performance]\n"
f"Start Time: {datetime.fromtimestamp(start_time).strftime('%Y-%m-%d %H:%M:%S')}\n"
f"Duration: {time.time() - start_time:.2f}s\n"
f"Peak Memory: {peak_mem / 1024**2:.2f} MB\n"
f"Exit Code: {exit_code}\n"
)
return {
"task": task_name,
"project": project_dir.name,
"exit_code": exit_code,
"duration": round(time.time() - start_time, 2),
"log_path": str(log_file)
}
def main():
# 参数解析
parser = argparse.ArgumentParser(
description="多任务日志分离执行器",
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
# Java版本选择
java_group = parser.add_mutually_exclusive_group(required=True)
java_group.add_argument("--java-version",
choices=JAVA_VERSIONS.keys(),
help="预设Java版本")
java_group.add_argument("--java",
help="手动指定Java路径")
# 任务选择
task_group = parser.add_mutually_exclusive_group(required=True)
task_group.add_argument("--task",
choices=JAR_TASKS.keys(),
help="预设任务名称")
task_group.add_argument("--jar",
help="手动指定JAR路径(需配合--config使用)")
# 可选参数
parser.add_argument("--config",
help="配置文件名(手动模式必填)")
parser.add_argument("--work-dir",
help="覆盖工作目录(优先于预设任务的配置)")
parser.add_argument("--root", required=True,
help="包含子项目目录的根路径")
args = parser.parse_args()
# 解析Java路径
java_path = args.java or JAVA_VERSIONS[args.java_version]
if not Path(java_path).exists():
raise FileNotFoundError(f"Java路径无效: {java_path}")
# 解析任务配置
task_name = "custom"
if args.task:
task_name = args.task
task_config = JAR_TASKS[task_name]
jar_path = task_config[0]
config_file = task_config[1]
default_work_dir = task_config[2] if len(task_config) > 2 else None
final_work_dir = args.work_dir or default_work_dir
else:
jar_path = args.jar
config_file = args.config
final_work_dir = args.work_dir
if not config_file:
raise ValueError("手动指定JAR时需要提供--config参数")
# 路径验证
if not Path(jar_path).exists():
raise FileNotFoundError(f"JAR文件不存在: {jar_path}")
# 处理工作目录路径
if final_work_dir:
final_work_dir = Path(final_work_dir).resolve()
if not final_work_dir.exists():
raise FileNotFoundError(f"工作目录不存在: {final_work_dir}")
# 验证根目录
root_dir = Path(args.root)
if not root_dir.is_dir():
raise NotADirectoryError(f"无效的项目根目录: {root_dir}")
# 初始化总日志路径
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
summary_path = Path(__file__).parent / ".task_summary"/ f"{task_name}"
summary_path.mkdir(exist_ok=True)
summary_log = summary_path / f"task_summary_{timestamp}.log"
# 初始化结果记录
results = []
# 使用示例
excluded_list = load_excluded_projects(root_dir/".reports"/"blacklist.csv")
excluded_list.append('.lib')
excluded_list.append('.idea')
excluded_list.append('.task_summary')
excluded_list.append('.reports')
print(f"需排除的项目:{excluded_list}")
# 遍历处理子目录
for project_dir in root_dir.iterdir():
if project_dir.name in excluded_list:
print(f"需排除的项目:{project_dir}")
continue
if project_dir.is_dir():
print(f"\n{' 开始处理 ':^40}")
print(f"项目: {project_dir.name}")
print(f"任务: {task_name}")
# 验证配置文件
config_path = project_dir / config_file
if not config_path.exists():
print(f" ! 配置文件缺失: {config_file}")
continue
# 执行任务
result = run_command(
task_name=task_name,
java_path=java_path,
jar_path=jar_path,
config_file=config_file,
project_dir=project_dir,
work_dir=final_work_dir
)
# 记录结果
results.append(result)
print(f" √ 完成 | 耗时: {result['duration']}s | 状态码: {result['exit_code']}")
print(f" 日志路径: {result['log_path']}")
# 生成总日志
with open(summary_log, "w") as f:
f.write(f"Task Summary ({datetime.now().strftime('%Y-%m-%d %H:%M:%S')})\n")
f.write("="*50 + "\n")
f.write(f"Total Tasks: {len(results)}\n")
f.write(f"Success Tasks: {sum(1 for r in results if r['exit_code'] == 0)}\n\n")
f.write("Details:\n")
f.write("-"*50 + "\n")
for result in results:
status = "SUCCESS" if result["exit_code"] == 0 else "FAILED"
f.write(
f"Project: {result['project']}\n"
f"Task: {result['task']}\n"
f"Duration: {result['duration']}s\n"
f"Status: {status} (Code: {result['exit_code']})\n"
f"Log: {result['log_path']}\n"
f"{'-'*30}\n"
)
print(f"\n任务执行总结已保存至: {summary_log}")
if __name__ == "__main__":
main()