feat: 扩充 Docker 命令并新增 diagnose 状态诊断
- Docker:新增只读、生命周期、清理、Compose 共 32 条命令,Linux 自动适配 podman - 危险命令 clearall/prunevolumes 未带 --yes 时仅提示并以退出码 2 结束 - 需要容器/镜像名的命令做必填参数校验,-- 之后参数计入位置参数 - diagnose:自动识别 Docker/Podman 容器或 K8s Pod,输出状态、根因、依据、建议并附日志与事件 - diagnose 中 -n 表示 namespace,其余命令 -n 仍为 --dry-run - 新增内置动作桥接与平台变体 helper,补充单元/集成/CLI 测试与 README
This commit is contained in:
@@ -31,14 +31,75 @@ type Variant struct {
|
||||
|
||||
// Command is a platform-neutral intent, e.g. "docker.clearsafe".
|
||||
type Command struct {
|
||||
ID string // hierarchical, dot-separated: "docker.clearsafe"
|
||||
Aliases []string
|
||||
Summary string
|
||||
Group string // CLI grouping, e.g. "docker"
|
||||
Action string // what the command does, including its safety contract
|
||||
ID string // hierarchical, dot-separated: "docker.clearsafe"
|
||||
Aliases []string
|
||||
Summary string
|
||||
Group string // CLI grouping, e.g. "docker"
|
||||
Action string // what the command does, including its safety contract
|
||||
|
||||
// Usage describes the positional arguments, e.g. "<容器>".
|
||||
Usage string
|
||||
// MinArgs is the number of positional arguments required before the
|
||||
// command is allowed to run. Options before "--" are not counted.
|
||||
MinArgs int
|
||||
// RequiresYes marks destructive commands: without an explicit --yes they
|
||||
// print what they would do and exit non-zero instead of running.
|
||||
RequiresYes bool
|
||||
// Namespaced marks Kubernetes-aware commands where -n means --namespace
|
||||
// (kubectl style) instead of the global --dry-run shorthand.
|
||||
Namespaced bool
|
||||
|
||||
Variants []Variant
|
||||
}
|
||||
|
||||
// ValidateArgs reports whether the caller supplied enough positional
|
||||
// arguments. Everything after "--" counts as positional; before it, arguments
|
||||
// starting with "-" are treated as options and skipped.
|
||||
func (c *Command) ValidateArgs(args []string) error {
|
||||
if c.MinArgs <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
count := 0
|
||||
positionalOnly := false
|
||||
for _, arg := range args {
|
||||
switch {
|
||||
case positionalOnly:
|
||||
count++
|
||||
case arg == "--":
|
||||
positionalOnly = true
|
||||
case strings.HasPrefix(arg, "-") && arg != "-":
|
||||
// Option; value-taking options are not distinguishable, so their
|
||||
// values may be counted later in the list. This is deliberately a
|
||||
// loose check: the underlying tool still validates precisely.
|
||||
default:
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
if count < c.MinArgs {
|
||||
return &MissingArgsError{Command: c, Got: count}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Invocation renders the CLI form of a command, e.g. "kopsc docker logs".
|
||||
func (c *Command) Invocation() string {
|
||||
return "kopsc " + strings.ReplaceAll(c.ID, ".", " ")
|
||||
}
|
||||
|
||||
// MissingArgsError reports too few positional arguments.
|
||||
type MissingArgsError struct {
|
||||
Command *Command
|
||||
Got int
|
||||
}
|
||||
|
||||
func (e *MissingArgsError) Error() string {
|
||||
usage := strings.TrimSpace(e.Command.Usage)
|
||||
return fmt.Sprintf("命令 %s 缺少参数:需要至少 %d 个(%s),实际 %d 个;用法: %s %s",
|
||||
e.Command.ID, e.Command.MinArgs, usage, e.Got, e.Command.Invocation(), usage)
|
||||
}
|
||||
|
||||
// Registry is an ordered set of commands.
|
||||
type Registry struct {
|
||||
Commands []Command
|
||||
@@ -65,6 +126,15 @@ func (r *Registry) Validate() error {
|
||||
if len(cmd.Variants) == 0 {
|
||||
return fmt.Errorf("command %q: no variants", cmd.ID)
|
||||
}
|
||||
if cmd.MinArgs < 0 {
|
||||
return fmt.Errorf("command %q: MinArgs must not be negative", cmd.ID)
|
||||
}
|
||||
if cmd.MinArgs > 0 && strings.TrimSpace(cmd.Usage) == "" {
|
||||
return fmt.Errorf("command %q: MinArgs requires a Usage string", cmd.ID)
|
||||
}
|
||||
if cmd.RequiresYes && strings.TrimSpace(cmd.Action) == "" {
|
||||
return fmt.Errorf("command %q: RequiresYes requires an Action description", cmd.ID)
|
||||
}
|
||||
|
||||
for _, alias := range cmd.Aliases {
|
||||
if strings.TrimSpace(alias) == "" {
|
||||
|
||||
Reference in New Issue
Block a user