|
| 1 | +from PySide6.QtCore import QThread, Signal |
1 | 2 | from PySide6.QtWidgets import QFileDialog, QHBoxLayout, QVBoxLayout, QWidget |
2 | 3 | from qfluentwidgets import ( |
3 | 4 | Action, |
|
36 | 37 | show_warning, |
37 | 38 | ) |
38 | 39 | from script_chainer.utils.process_utils import launch_in_terminal |
39 | | -from script_chainer.utils.runner_utils import ( |
40 | | - build_runner_command, |
41 | | -) |
| 40 | +from script_chainer.utils.runner_utils import build_runner_command |
| 41 | + |
| 42 | + |
| 43 | +class ChainRunner(QThread): |
| 44 | + """后台逐条启动脚本链,每条按自身 block 决定阻塞/非阻塞,结束后经信号汇总结果。""" |
| 45 | + |
| 46 | + chain_finished = Signal(int, list) |
| 47 | + |
| 48 | + def __init__(self, chain_name: str, specs: list[tuple[int, bool, str]], parent=None): |
| 49 | + super().__init__(parent) |
| 50 | + self.chain_name = chain_name |
| 51 | + self.specs = specs |
| 52 | + |
| 53 | + def run(self) -> None: |
| 54 | + launched = 0 |
| 55 | + failed: list[str] = [] |
| 56 | + for script_index, block, display_name in self.specs: |
| 57 | + try: |
| 58 | + cmd, cwd = build_runner_command(self.chain_name, script_index) |
| 59 | + proc = launch_in_terminal(command=cmd, cwd=cwd, block=block) |
| 60 | + except Exception: |
| 61 | + failed.append(display_name) |
| 62 | + continue |
| 63 | + # 阻塞脚本非零退出 → 计入失败;非阻塞 rc 为 wt 的 0,按已启动计 |
| 64 | + if proc.returncode not in (0, None): |
| 65 | + failed.append(display_name) |
| 66 | + else: |
| 67 | + launched += 1 |
| 68 | + self.chain_finished.emit(launched, failed) |
42 | 69 |
|
43 | 70 |
|
44 | 71 | class ScriptSettingRootInterface(VerticalScrollInterface): |
@@ -201,26 +228,32 @@ def on_import_python_script_clicked(self) -> None: |
201 | 228 | self.update_chain_display() |
202 | 229 |
|
203 | 230 | def on_run_chain_clicked(self) -> None: |
204 | | - """拉起独立 runner 运行当前脚本链。""" |
| 231 | + """按配置顺序逐条启动当前脚本链,每条按自身 block 决定阻塞/非阻塞。""" |
205 | 232 | if self.chosen_config is None or self._runner_launch_in_progress: |
206 | 233 | return |
207 | 234 |
|
| 235 | + specs = [ |
| 236 | + (i, cfg.block, cfg.display_name) |
| 237 | + for i, cfg in enumerate(self.chosen_config.script_list) |
| 238 | + if cfg.enabled |
| 239 | + ] |
| 240 | + if not specs: |
| 241 | + show_warning(self.window(), '无法运行', '没有已启用的脚本') |
| 242 | + return |
| 243 | + |
208 | 244 | self._runner_launch_in_progress = True |
209 | 245 | self.run_chain_btn.setEnabled(False) |
210 | | - chain_name = self.chosen_config.module_name |
211 | | - try: |
212 | | - cmd, cwd = build_runner_command(chain_name) |
213 | | - launch_in_terminal( |
214 | | - command=cmd, |
215 | | - cwd=cwd, |
216 | | - title=f'运行脚本链 {chain_name}', |
217 | | - ) |
218 | | - show_success(self.window(), '运行全部', f'已在终端启动脚本链 {chain_name}') |
219 | | - except Exception as e: |
220 | | - show_error(self.window(), '启动失败', str(e)) |
221 | | - finally: |
222 | | - self._runner_launch_in_progress = False |
223 | | - self.run_chain_btn.setEnabled(True) |
| 246 | + self._chain_runner = ChainRunner(self.chosen_config.module_name, specs, parent=self) |
| 247 | + self._chain_runner.chain_finished.connect(self._on_chain_run_finished) |
| 248 | + self._chain_runner.start() |
| 249 | + |
| 250 | + def _on_chain_run_finished(self, launched: int, failed: list) -> None: |
| 251 | + self._runner_launch_in_progress = False |
| 252 | + self.run_chain_btn.setEnabled(True) |
| 253 | + if failed: |
| 254 | + show_error(self.window(), '运行异常', f'{len(failed)} 个脚本启动失败:{", ".join(failed)}') |
| 255 | + else: |
| 256 | + show_success(self.window(), '运行全部', f'已启动 {launched} 个脚本') |
224 | 257 |
|
225 | 258 | def update_chain_display(self) -> None: |
226 | 259 | """更新脚本链的显示""" |
|
0 commit comments