Files
kenaito-kopsc/internal/executor/builtin.go
T
odboy 400812d114 feat: 新增 file/svc/archive/sys/log/fw 分组并扩充 net、proc
- file:findbig 按大小、findrecent 按修改时间、findname 按名称查找文件
- svc:systemctl / launchctl / sc 统一接口,status、enable、disable、logs
- archive:按扩展名自动识别格式并解压,支持 tar.gz/tgz/tar.bz2/tar.xz/tar/zip/gz
- sysinfo:OS、CPU、内存、磁盘一览
- log:journalctl / log show / wevtutil 搜索关键字与查看最近日志
- fw:ufw / firewalld / iptables / ALF / netsh 统一接口,status、allow、deny
- net 新增 ping、trace(mtr 优先)、dns(dig 优先)、curl HTTP 诊断
- proc 新增 topmem、topcpu、killname
- 危险操作(svc enable/disable、proc killname、fw allow/deny)需 --yes 确认
- 注册表、executor 派发表、cli 分组说明与 README 同步更新
2026-11-02 22:42:18 +08:00

140 lines
4.6 KiB
Go

package executor
import (
"bytes"
"context"
"fmt"
"io"
"gitea.odboy.cn/odboy/kenaito-kopsc/internal/diagnose"
"gitea.odboy.cn/odboy/kenaito-kopsc/internal/platform"
)
// BuiltinRequest carries the caller's arguments and output streams to an
// in-process command implementation.
type BuiltinRequest struct {
Args []string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
Info platform.Info
// Confirmed reports that the user passed --yes; destructive builtins use
// it instead of asking for confirmation a second time.
Confirmed bool
// Plan is the resolved variant and forwarded arguments. Builtins that
// drive an external runtime (for example docker save) read the runtime's
// program name and the passthrough arguments from it.
Plan Plan
}
// Builtin executes a command inside kopsc instead of spawning a child. It is
// used where no portable system utility exists (for example du on Windows).
type Builtin func(ctx context.Context, req BuiltinRequest) error
var builtins = map[string]Builtin{
"archive.extract": runArchiveExtract,
"disk.usage": runDiskUsage,
"diagnose": runDiagnose,
"docker.df": runDockerDF,
"docker.exec": runDockerExec,
"docker.load": runDockerLoad,
"docker.logs": runDockerLogs,
"docker.restart": runDockerRestart,
"docker.rm": runDockerRM,
"docker.rm.preview": runDockerPreviewRM,
"docker.rmi": runDockerRMI,
"docker.rmi.preview": runDockerPreviewRMI,
"docker.save": runDockerSave,
"docker.stats": runDockerStats,
"docker.stop": runDockerStop,
"file.findbig": runFileFindBig,
"file.findname": runFileFindName,
"file.findrecent": runFileFindRecent,
"fw.allow": runFwAllow,
"fw.deny": runFwDeny,
"fw.status": runFwStatus,
"git.retime": runGitRetime,
"git.retime.preview": runGitRetimePreview,
"java.run": runJavaRun,
"java.run.preview": runJavaPreview,
"log.last": runLogLast,
"log.search": runLogSearch,
"net.curl": runNetCurl,
"net.dns": runNetDNS,
"net.ping": runNetPing,
"net.pids": runNetPIDs,
"net.ports": runNetPorts,
"net.trace": runNetTrace,
"proc.killname": runProcKillName,
"proc.nohup": runNohup,
"proc.topcpu": runProcTopCPU,
"proc.topmem": runProcTopMem,
"proc.wait": runProcWait,
"svc.disable": runSvcDisable,
"svc.enable": runSvcEnable,
"svc.logs": runSvcLogs,
"svc.status": runSvcStatus,
"sysinfo": runSysInfo,
"user.grant": runUserGrant,
"user.revoke": runUserRevoke,
}
// runDiagnose bridges the registry builtin to the diagnose package.
func runDiagnose(ctx context.Context, req BuiltinRequest) error {
service := diagnose.New(req.Info, diagnose.ExecRunner{}, req.Stdout, req.Stderr)
return service.Run(ctx, req.Args)
}
// Preview runs a command's ConfirmBuiltin (if any) and writes the list of
// objects the command would act on. It is used for the confirmation prompt and
// for --dry-run, so neither path needs to touch the objects themselves.
//
// The list is built from the container/image references kopsc resolves, which
// means every target is validated first: an unknown target is reported here
// rather than after the user typed --yes. Commands without a ConfirmBuiltin
// print nothing.
func Preview(ctx context.Context, plan Plan, w io.Writer) error {
name := plan.PreviewBuiltin()
if name == "" {
return nil
}
fn, ok := LookupBuiltin(name)
if !ok {
return fmt.Errorf("未注册的确认动作 %q", name)
}
// Build the list in memory first: a target that fails to resolve must not
// leave a dangling heading behind.
var buf bytes.Buffer
if err := fn(ctx, BuiltinRequest{
Args: plan.ExtraArgs,
Stdout: &buf,
Stderr: io.Discard,
Info: plan.Result.Info,
Plan: plan,
}); err != nil {
return err
}
// Only destructive commands act on a list of objects; other previews (such
// as the java command line) already carry their own heading.
if plan.Result.Command != nil && plan.Result.Command.RequiresYes {
fmt.Fprintln(w, "将影响:")
}
_, err := w.Write(buf.Bytes())
return err
}
// LookupBuiltin returns the implementation registered under name.
func LookupBuiltin(name string) (Builtin, bool) {
fn, ok := builtins[name]
return fn, ok
}
// BuiltinNames lists the registered builtin implementations.
func BuiltinNames() []string {
names := make([]string, 0, len(builtins))
for name := range builtins {
names = append(names, name)
}
return names
}