feat: 新增 proc wait,等待进程退出

- 每秒检查一次目标进程,存在则继续等待,直到消失为止
- 关键字在进程名与命令行中匹配(忽略大小写),多个关键字为逻辑与;
  --pid 可直接指定进程 ID(逗号分隔可多个)
- 默认不超时,--timeout 限时(退出码 2 并列出残留 PID),--once 只检查一次
- 三平台实现:Linux 读 /proc(回退 ps)、macOS 用 ps、Windows 用 tasklist
- ExitError 改为优先展示具体原因,不再只显示「命令以状态码 N 退出」
- 文档:README.proc.md 新增完整小节,主 README 补充示例与速查
This commit is contained in:
2026-11-01 09:01:32 +08:00
parent 3725f8307a
commit 14817bcfe7
10 changed files with 837 additions and 3 deletions
+31
View File
@@ -903,3 +903,34 @@ func TestExplainHelpDocumentsWaysAndExitCodes(t *testing.T) {
}
}
}
func TestProcWaitRequiresTargetThroughCLI(t *testing.T) {
app, _, stderr := testApp(centos("docker"))
// No keywords and no --pid: kopsc must explain what to type.
if code := app.Execute([]string{"proc", "wait"}); code == 0 {
t.Fatal("expected a non-zero exit code without a target")
}
if !strings.Contains(stderr.String(), "缺少要等待的进程") {
t.Errorf("stderr = %s", stderr.String())
}
}
func TestProcWaitRejectsBadPIDThroughCLI(t *testing.T) {
app, _, stderr := testApp(centos("docker"))
if code := app.Execute([]string{"proc", "wait", "--pid", "abc"}); code == 0 {
t.Fatal("expected a non-zero exit code for a bad PID")
}
if !strings.Contains(stderr.String(), "--pid 需要正整数") {
t.Errorf("stderr = %s", stderr.String())
}
}
func TestProcWaitDryRunDoesNotPoll(t *testing.T) {
app, stdout, stderr := testApp(centos("docker"))
if code := app.Execute([]string{"proc", "wait", "--dry-run", "nginx"}); code != 0 {
t.Fatalf("exit code = %d, stderr=%s", code, stderr.String())
}
if !strings.Contains(stdout.String(), "[dry-run]") {
t.Errorf("dry-run output = %q", stdout.String())
}
}