继续收敛插件宿主进程错误
保留插件工作区扫描与进程状态读取错误 保留插件停止 kill/wait 错误并修正主动终止退出码判定
This commit is contained in:
@@ -513,7 +513,8 @@ fn workspace_plugin_sources(root: &Path) -> Result<Vec<ScannedPluginSource>, Str
|
||||
Err(error) => return Err(format!("读取插件工作区失败:{error}")),
|
||||
};
|
||||
let mut sources = Vec::new();
|
||||
for entry in entries.flatten() {
|
||||
for entry in entries {
|
||||
let entry = entry.map_err(|error| format!("读取插件工作区目录项失败:{error}"))?;
|
||||
let plugin_root = entry.path();
|
||||
if !plugin_root.is_dir() || !plugin_root.join(PLUGIN_MANIFEST_FILE_NAME).is_file() {
|
||||
continue;
|
||||
@@ -976,10 +977,19 @@ impl PluginHost {
|
||||
.as_ref()
|
||||
.is_some_and(|existing| existing.status == "failed");
|
||||
let mut running = existing.and_then(|existing| existing.running);
|
||||
let exited = running
|
||||
.as_mut()
|
||||
.and_then(|running| running.child.try_wait().ok().flatten())
|
||||
.is_some();
|
||||
let process_error =
|
||||
running
|
||||
.as_mut()
|
||||
.and_then(|running| match running.child.try_wait() {
|
||||
Ok(Some(status)) => Some(if let Some(code) = status.code() {
|
||||
format!("插件进程已退出:exitCode={code}")
|
||||
} else {
|
||||
"插件进程已被信号终止".to_string()
|
||||
}),
|
||||
Ok(None) => None,
|
||||
Err(error) => Some(format!("读取插件进程状态失败:{error}")),
|
||||
});
|
||||
let exited = process_error.is_some();
|
||||
if exited {
|
||||
running = None;
|
||||
}
|
||||
@@ -1002,11 +1012,7 @@ impl PluginHost {
|
||||
manifest,
|
||||
root: source.root,
|
||||
status,
|
||||
last_error: if exited {
|
||||
Some("插件进程已退出".to_string())
|
||||
} else {
|
||||
previous_error
|
||||
},
|
||||
last_error: process_error.or(previous_error),
|
||||
running,
|
||||
},
|
||||
);
|
||||
@@ -1186,17 +1192,37 @@ impl PluginHost {
|
||||
.plugins
|
||||
.get_mut(id)
|
||||
.ok_or_else(|| "插件不存在".to_string())?;
|
||||
let mut stop_error = None;
|
||||
if let Some(mut running) = record.running.take() {
|
||||
let _ = running.child.kill();
|
||||
let _ = running.child.wait();
|
||||
if let Err(error) = running.child.kill() {
|
||||
stop_error = Some(format!("终止插件进程失败:{error}"));
|
||||
}
|
||||
match running.child.wait() {
|
||||
Ok(_) if stop_error.is_none() => {}
|
||||
Err(error) => {
|
||||
stop_error = Some(format!("等待插件进程退出失败:{error}"));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
record.status = if record.manifest.enabled {
|
||||
record.status = if stop_error.is_some() {
|
||||
"failed".to_string()
|
||||
} else if record.manifest.enabled {
|
||||
"stopped".to_string()
|
||||
} else {
|
||||
"disabled".to_string()
|
||||
};
|
||||
record.last_error = None;
|
||||
audit(&root, id, "stop", true, None);
|
||||
record.last_error = stop_error.clone();
|
||||
audit(
|
||||
&root,
|
||||
id,
|
||||
"stop",
|
||||
stop_error.is_none(),
|
||||
stop_error.as_deref(),
|
||||
);
|
||||
if let Some(error) = stop_error {
|
||||
return Err(error);
|
||||
}
|
||||
self.summary_locked(record)
|
||||
}
|
||||
|
||||
@@ -1214,7 +1240,9 @@ impl PluginHost {
|
||||
}
|
||||
let mut cleanup = Ok(());
|
||||
if !enabled {
|
||||
let _ = self.stop(id);
|
||||
self.stop(id)
|
||||
.map(|_| ())
|
||||
.map_err(|error| format!("插件停止失败,未切换禁用状态:{error}"))?;
|
||||
if let Some(editor) = crate::editor_adapters::ManagedEditor::for_plugin(id) {
|
||||
let state = self
|
||||
.state
|
||||
|
||||
@@ -99,3 +99,4 @@ DirectProject 回合失败在确认不是客户端内部不可归类故障时,
|
||||
- 认证状态订阅底层原先先把 IPC 失败转成空注销函数,导致上层新增的错误提示也收不到;现让订阅拒绝向登录页传播,后台身份投影失败时清除身份并留痕。
|
||||
- 发布构建预检原先把 `package.json` 元数据/读取/解析错误当成“没有 build”,把 `package-lock.json` 读取/解析错误当成“没有锁定版本”;现分别区分 NotFound 与真实读盘/JSON 错误,保留相对工作区路径和底层正文。
|
||||
- 发布尝试账本和工作区偏好文件原先把损坏、权限、类型和 JSON 解析失败当成空账本/默认偏好;现只有文件不存在才使用默认,其他读取错误沿发布幂等和建项目录命令返回具体正文。
|
||||
- 插件主机扫描工作区、读取进程状态、停止插件和禁用插件时原先吞掉目录项/`try_wait`/kill/wait 错误;现保留插件状态错误并阻止“停止失败却显示已禁用”,正常主动 kill 的非零退出码不再误报。
|
||||
|
||||
Reference in New Issue
Block a user