feat: 将更多 Docker 命令改为内置实现,统一按名称/ID 解析目标

- exec/rm/rmi/stop/restart 支持名称、ID 或唯一 ID 前缀,目标不存在或
  前缀有歧义时在调用 docker 前报错;exec 默认 -it 并以 -- 分隔命令
- logs 新增 --since/--grep/--save;df 改为按占用排序的可读排行;
  stats 默认单次快照,无参数时统计全部运行中容器
- 破坏性确认:Command.ConfirmBuiltin 提供将删除对象的清单,
  rm/rmi 无 --yes 时列清单并退出码 2,拒绝 -f,运行中容器提示先 stop
- 抽出 executor/dockertargets.go 统一镜像/容器解析与 docker 调用
This commit is contained in:
2026-11-01 08:01:12 +08:00
parent bd6f20d7c5
commit f5ae80c1a8
18 changed files with 2308 additions and 226 deletions
+17 -6
View File
@@ -152,9 +152,7 @@ func (a *App) newLeaf(cmd *registry.Command, name string) *cobra.Command {
plan := executor.Plan{Result: result, ExtraArgs: extra}
if cmd.RequiresYes && !yes && !dryRun {
a.printConfirmation(cmd, plan)
a.exitCode = 2
return nil
return a.printConfirmation(cmd, plan)
}
return plan.Run(context.Background(), executor.Options{
@@ -168,14 +166,27 @@ func (a *App) newLeaf(cmd *registry.Command, name string) *cobra.Command {
return leaf
}
// printConfirmation explains a destructive command and how to approve it.
func (a *App) printConfirmation(cmd *registry.Command, plan executor.Plan) {
// printConfirmation explains a destructive command and how to approve it. If
// the command has a preview builtin, the objects it would touch are listed
// first (and an unknown target is reported before asking for --yes).
func (a *App) printConfirmation(cmd *registry.Command, plan executor.Plan) error {
if err := executor.Preview(context.Background(), plan, a.Stdout); err != nil {
return err
}
w := a.Stdout
fmt.Fprintln(w, "这是破坏性命令,未执行。")
fmt.Fprintf(w, "命令: %s\n", cmd.Invocation())
fmt.Fprintf(w, "将执行: %s\n", plan.Display())
fmt.Fprintf(w, "影响: %s\n\n", cmd.Action)
fmt.Fprintf(w, "确认执行请追加 --yes:\n %s --yes\n", cmd.Invocation())
// Repeat the caller's own arguments so the suggestion is copy-pasteable.
suggested := cmd.Invocation() + " --yes"
if len(plan.ExtraArgs) > 0 {
suggested += " " + strings.Join(plan.ExtraArgs, " ")
}
fmt.Fprintf(w, "确认执行请追加 --yes:\n %s\n", suggested)
a.exitCode = 2
return nil
}
// parseLeafArgs splits leaf arguments: kopsc-level flags before the first `--`