From 2ef4616ed2b37df946db8c20c30a77ba90838741 Mon Sep 17 00:00:00 2001 From: Zero Date: Sat, 7 Oct 2023 18:01:31 +0800 Subject: [PATCH 01/14] feat: refactor command with multiple engines --- cancel.go | 5 + cmd/cmd/commands/run.go | 47 +++ cmd/cmd/main.go | 19 ++ command.go | 108 +++---- engine/docker/config.go | 14 + engine/docker/connect.go | 90 ++++++ engine/docker/docker.go | 27 ++ engine/docker/utils.go | 89 ++++++ engine/engine.go | 20 ++ engine/host/cancel.go | 15 + engine/host/config.go | 12 + engine/host/host.go | 35 +++ engine/host/io.go | 18 ++ engine/host/start.go | 128 ++++++++ engine/host/wait.go | 11 + go.mod | 90 +++++- go.sum | 402 ++++++++++++++++++++++++- io.go | 15 + new.go | 26 -- run.go | 9 + start.go | 11 + tmp/command_old.go | 86 ++++++ command_test.go => tmp/command_test.go | 10 +- wait.go | 5 + 24 files changed, 1189 insertions(+), 103 deletions(-) create mode 100644 cancel.go create mode 100644 cmd/cmd/commands/run.go create mode 100644 cmd/cmd/main.go create mode 100644 engine/docker/config.go create mode 100644 engine/docker/connect.go create mode 100644 engine/docker/docker.go create mode 100644 engine/docker/utils.go create mode 100644 engine/engine.go create mode 100644 engine/host/cancel.go create mode 100644 engine/host/config.go create mode 100644 engine/host/host.go create mode 100644 engine/host/io.go create mode 100644 engine/host/start.go create mode 100644 engine/host/wait.go create mode 100644 io.go delete mode 100644 new.go create mode 100644 run.go create mode 100644 start.go create mode 100644 tmp/command_old.go rename command_test.go => tmp/command_test.go (95%) create mode 100644 wait.go diff --git a/cancel.go b/cancel.go new file mode 100644 index 0000000..87cf2d3 --- /dev/null +++ b/cancel.go @@ -0,0 +1,5 @@ +package command + +func (c *command) Cancel() error { + return c.engine.Cancel() +} diff --git a/cmd/cmd/commands/run.go b/cmd/cmd/commands/run.go new file mode 100644 index 0000000..d8d8c9c --- /dev/null +++ b/cmd/cmd/commands/run.go @@ -0,0 +1,47 @@ +package commands + +import ( + "github.com/go-zoox/cli" + "github.com/go-zoox/command" +) + +func Run(app *cli.MultipleProgram) { + app.Register("run", &cli.Command{ + Name: "run", + Usage: "command run", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "engine", + Usage: "command engine", + Aliases: []string{"e"}, + EnvVars: []string{"ENGINE"}, + Value: "host", + }, + &cli.StringFlag{ + Name: "command", + Usage: "the command", + Aliases: []string{"c"}, + EnvVars: []string{"COMMAND"}, + Required: true, + }, + &cli.StringFlag{ + Name: "shell", + Usage: "the command shell", + Aliases: []string{"s"}, + EnvVars: []string{"SHELL"}, + }, + }, + Action: func(ctx *cli.Context) (err error) { + cmd, err := command.New(&command.Config{ + Engine: ctx.String("engine"), + Command: ctx.String("command"), + Shell: ctx.String("shell"), + }) + if err != nil { + return err + } + + return cmd.Run() + }, + }) +} diff --git a/cmd/cmd/main.go b/cmd/cmd/main.go new file mode 100644 index 0000000..941233b --- /dev/null +++ b/cmd/cmd/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "github.com/go-zoox/cli" + "github.com/go-zoox/command" + "github.com/go-zoox/command/cmd/cmd/commands" +) + +func main() { + app := cli.NewMultipleProgram(&cli.MultipleProgramConfig{ + Name: "cmd", + Usage: "Powerful command runner", + Version: command.Version, + }) + + commands.Run(app) + + app.Run() +} diff --git a/command.go b/command.go index 7e00881..49dadf7 100644 --- a/command.go +++ b/command.go @@ -1,86 +1,60 @@ package command import ( - "encoding/json" "fmt" - "io" - "os" - "os/exec" + + "github.com/go-zoox/command/engine" + "github.com/go-zoox/command/engine/host" ) -// Command is better os/exec command -type Command struct { - Script string `json:"content"` - Context string `json:"context"` - Environment map[string]string `json:"environment"` - Shell string `json:"shell"` - // - Stdout io.Writer - Stderr io.Writer +type Command interface { + Start() error + Wait() error + Cancel() error // - cmd *exec.Cmd + Run() error } -// Run runs the command -func (c *Command) Run() error { - environment := os.Environ() - - for k, v := range c.Environment { - environment = append(environment, fmt.Sprintf("%s=%s", k, v)) - } - - shell := c.Shell - if shell == "" { - shell = os.Getenv("SHELL") - if shell == "" { - shell = "sh" - } - } - - cmd := exec.Command(shell, "-c", c.Script) - cmd.Dir = c.Context - cmd.Env = environment - - cmd.Stdout = c.Stdout - if cmd.Stdout == nil { - cmd.Stdout = os.Stdout - } - - cmd.Stderr = c.Stderr - if cmd.Stderr == nil { - cmd.Stderr = os.Stderr - } - - c.cmd = cmd - - if err := cmd.Run(); err != nil { - return err - } - - return nil +type Config struct { + Engine string + Command string + WorkDir string + Environment map[string]string + User string + Shell string } -// Config gets the config of command -func (c *Command) Config() (string, error) { - cfg, err := json.MarshalIndent(c, "", " ") - if err != nil { - return "", err +func New(cfg *Config) (cmd Command, err error) { + if cfg.Engine == "" { + cfg.Engine = host.Engine } - return string(cfg), nil -} + if cfg.Shell == "" { + cfg.Shell = "/bin/sh" + } -// MustConfig gets the config of command -func (c *Command) MustConfig() string { - cfg, err := c.Config() - if err != nil { - return "" + var engine engine.Engine + switch cfg.Engine { + case host.Engine: + engine, err = host.New(&host.Config{ + Command: cfg.Command, + WorkDir: cfg.WorkDir, + Environment: cfg.Environment, + User: cfg.User, + Shell: cfg.Shell, + }) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unsupported command engine: %s", cfg.Engine) } - return cfg + return &command{ + engine: engine, + }, nil } -// ExitCode gets the exit code of process -func (c *Command) ExitCode() int { - return c.cmd.ProcessState.ExitCode() +type command struct { + engine engine.Engine } diff --git a/engine/docker/config.go b/engine/docker/config.go new file mode 100644 index 0000000..fad3765 --- /dev/null +++ b/engine/docker/config.go @@ -0,0 +1,14 @@ +package docker + +type Config struct { + Shell string + Environment map[string]string + WorkDir string + + // + User string + + Image string + + InitCommand string +} diff --git a/engine/docker/connect.go b/engine/docker/connect.go new file mode 100644 index 0000000..6c91434 --- /dev/null +++ b/engine/docker/connect.go @@ -0,0 +1,90 @@ +package docker + +import ( + "context" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + dockerClient "github.com/docker/docker/client" + "github.com/go-zoox/terminal/server/session" + "github.com/go-zoox/uuid" +) + +func (d *docker) Connect(ctx context.Context) (session session.Session, err error) { + args := []string{} + if d.cfg.InitCommand != "" { + args = append(args, "-c", d.cfg.InitCommand) + } + + env := []string{} + for k, v := range d.cfg.Environment { + env = append(env, fmt.Sprintf("%s=%s", k, v)) + } + + c, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv) + if err != nil { + return nil, err + } + + cfg := &container.Config{ + Image: d.cfg.Image, + Cmd: append([]string{d.cfg.Shell}, args...), + User: d.cfg.User, + Tty: true, + OpenStdin: true, + AttachStdin: true, + AttachStdout: true, + AttachStderr: true, + StdinOnce: true, + WorkingDir: d.cfg.WorkDir, + Env: env, + } + + hostCfg := &container.HostConfig{} + + res, err := c.ContainerCreate(ctx, cfg, hostCfg, nil, nil, uuid.V4()) + if err != nil { + return nil, err + } + containerID := res.ID + + stream, err := c.ContainerAttach(ctx, containerID, types.ContainerAttachOptions{ + Stream: true, + Stdin: true, + Stdout: true, + Stderr: true, + // Logs: true, + }) + if err != nil { + return nil, err + } + + rct := &ResizableContainerTerminal{ + Ctx: ctx, + Client: c, + ContainerID: containerID, + ReadCh: make(chan []byte), + Stream: &stream, + } + session = rct + + go func() { + for { + buf := make([]byte, 1024) + n, err := stream.Conn.Read(buf) + if err != nil { + return + } + + rct.ReadCh <- buf[:n] + } + }() + + err = c.ContainerStart(ctx, containerID, types.ContainerStartOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to start container: %v", err) + } + + return +} diff --git a/engine/docker/docker.go b/engine/docker/docker.go new file mode 100644 index 0000000..74fa8ee --- /dev/null +++ b/engine/docker/docker.go @@ -0,0 +1,27 @@ +package docker + +import ( + "github.com/go-zoox/terminal/server/driver" +) + +type Docker interface { + driver.Driver +} + +type docker struct { + cfg *Config +} + +func New(cfg *Config) Docker { + if cfg.Image == "" { + cfg.Image = "whatwewant/zmicro:v1" + } + + if cfg.Shell == "" { + cfg.Shell = "/bin/sh" + } + + return &docker{ + cfg: cfg, + } +} diff --git a/engine/docker/utils.go b/engine/docker/utils.go new file mode 100644 index 0000000..9841d41 --- /dev/null +++ b/engine/docker/utils.go @@ -0,0 +1,89 @@ +package docker + +import ( + "context" + "fmt" + "io" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + dockerClient "github.com/docker/docker/client" + "github.com/go-zoox/logger" +) + +type ResizableContainerTerminal struct { + Ctx context.Context + Client *dockerClient.Client + ContainerID string + ReadCh chan []byte + Stream *types.HijackedResponse + // + exitCode int +} + +func (rct *ResizableContainerTerminal) Close() error { + // if err := rct.Stream.CloseWrite(); err != nil { + // return err + // } + + rct.Stream.Close() + + return rct.Client.ContainerRemove(rct.Ctx, rct.ContainerID, types.ContainerRemoveOptions{ + Force: true, + }) +} + +func (rct *ResizableContainerTerminal) Read(p []byte) (n int, err error) { + return copy(p, <-rct.ReadCh), nil +} + +func (rct *ResizableContainerTerminal) Write(p []byte) (n int, err error) { + n, err = rct.Stream.Conn.Write(p) + if err != nil { + logger.Errorf("Failed to write to pty master: %s", err) + return 0, err + } + + return +} + +func (rct *ResizableContainerTerminal) Resize(rows, cols int) error { + inspect, err := rct.Client.ContainerInspect(rct.Ctx, rct.ContainerID) + if err != nil { + return err + } + + if inspect.State.Status != "running" { + // return fmt.Errorf("container is not running") + return nil + } + + return rct.Client.ContainerResize(rct.Ctx, rct.ContainerID, types.ResizeOptions{ + Height: uint(rows), + Width: uint(cols), + }) +} + +func (rct *ResizableContainerTerminal) Wait() error { + resultC, errC := rct.Client.ContainerWait(rct.Ctx, rct.ContainerID, container.WaitConditionNotRunning) + select { + case err := <-errC: + if err != nil && err != io.EOF { + return fmt.Errorf("container exit error: %#v", err) + } + + logger.Infof("container exited") + + case result := <-resultC: + if result.StatusCode != 0 { + rct.exitCode = int(result.StatusCode) + return fmt.Errorf("container exited with non-zero status: %d", result.StatusCode) + } + } + + return nil +} + +func (rct *ResizableContainerTerminal) ExitCode() int { + return rct.exitCode +} diff --git a/engine/engine.go b/engine/engine.go new file mode 100644 index 0000000..db946e2 --- /dev/null +++ b/engine/engine.go @@ -0,0 +1,20 @@ +package engine + +import "io" + +type Engine interface { + Start() error + Wait() error + Cancel() error + // + SetStdin(stdin io.Reader) error + SetStdout(stdout io.Writer) error + SetStderr(stderr io.Writer) error +} + +type Config struct { + Shell string + Command string + Environment map[string]string + WorkDir string +} diff --git a/engine/host/cancel.go b/engine/host/cancel.go new file mode 100644 index 0000000..671c572 --- /dev/null +++ b/engine/host/cancel.go @@ -0,0 +1,15 @@ +package host + +import "errors" + +func (h *host) Cancel() error { + if h.cmd == nil { + return errors.New("command: not started") + } + + if err := h.cmd.Process.Kill(); err != nil { + return err + } + + return nil +} diff --git a/engine/host/config.go b/engine/host/config.go new file mode 100644 index 0000000..0957bf8 --- /dev/null +++ b/engine/host/config.go @@ -0,0 +1,12 @@ +package host + +type Config struct { + Command string + Environment map[string]string + WorkDir string + User string + Shell string + + // + IsHistoryDisabled bool +} diff --git a/engine/host/host.go b/engine/host/host.go new file mode 100644 index 0000000..a366502 --- /dev/null +++ b/engine/host/host.go @@ -0,0 +1,35 @@ +package host + +import ( + "io" + "os" + "os/exec" + + "github.com/go-zoox/command/engine" +) + +const Engine = "host" + +type host struct { + cfg *Config + // + cmd *exec.Cmd + // + + // + stdin io.Reader + stdout io.Writer + stderr io.Writer +} + +func New(cfg *Config) (engine.Engine, error) { + h := &host{ + cfg: cfg, + // + stdin: os.Stdin, + stdout: os.Stdout, + stderr: os.Stderr, + } + + return h, nil +} diff --git a/engine/host/io.go b/engine/host/io.go new file mode 100644 index 0000000..1b283d3 --- /dev/null +++ b/engine/host/io.go @@ -0,0 +1,18 @@ +package host + +import "io" + +func (h *host) SetStdin(stdin io.Reader) error { + h.stdin = stdin + return nil +} + +func (h *host) SetStdout(stdout io.Writer) error { + h.stdout = stdout + return nil +} + +func (h *host) SetStderr(stderr io.Writer) error { + h.stderr = stderr + return nil +} diff --git a/engine/host/start.go b/engine/host/start.go new file mode 100644 index 0000000..6f0ef3e --- /dev/null +++ b/engine/host/start.go @@ -0,0 +1,128 @@ +package host + +import ( + "errors" + "fmt" + "io" + "os" + "os/exec" + "os/user" + "syscall" + + "github.com/go-zoox/core-utils/cast" + "github.com/go-zoox/logger" +) + +func (h *host) Start() error { + if h.cmd != nil { + return errors.New("command: already started") + } + + logger.Debugf("start command: %s %s %s", h.cfg.Shell, "-c", h.cfg.Command) + h.cmd = exec.Command(h.cfg.Shell, "-c", h.cfg.Command) + + if err := applyEnv(h.cmd, h.cfg.Environment); err != nil { + return err + } + + if err := applyWorkDir(h.cmd, h.cfg.WorkDir); err != nil { + return err + } + + if err := applyUser(h.cmd, h.cfg.User); err != nil { + return err + } + + if err := applyHistory(h.cmd, h.cfg.IsHistoryDisabled); err != nil { + return err + } + + if err := applyStdin(h.cmd, h.stdin); err != nil { + return nil + } + + if err := applyStdout(h.cmd, h.stdout); err != nil { + return nil + } + + if err := applyStderr(h.cmd, h.stderr); err != nil { + return nil + } + + return h.cmd.Start() +} + +func applyEnv(cmd *exec.Cmd, environment map[string]string) error { + cmd.Env = append(os.Environ(), "TERM=xterm") + + for k, v := range environment { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) + } + + return nil +} + +func applyWorkDir(cmd *exec.Cmd, workDir string) error { + cmd.Dir = workDir + return nil +} + +func applyUser(cmd *exec.Cmd, username string) error { + if username == "" { + return nil + } + + userX, err := user.Lookup(username) + if err != nil { + return err + } + + logger.Infof("[command] uid=%s gid=%s", userX.Uid, userX.Gid) + + uid := cast.ToInt(userX.Uid) + gid := cast.ToInt(userX.Gid) + + cmd.SysProcAttr = &syscall.SysProcAttr{} + cmd.SysProcAttr.Credential = &syscall.Credential{ + Uid: uint32(uid), + Gid: uint32(gid), + } + + cmd.Env = append( + cmd.Env, + "USER="+username, + "HOME="+userX.HomeDir, + "LOGNAME="+username, + "UID="+userX.Uid, + "GID="+userX.Gid, + ) + + return nil +} + +func applyHistory(cmd *exec.Cmd, disable bool) error { + if disable { + cmd.Env = append(cmd.Env, "HISTFILE=/dev/null") + } + + return nil +} + +func applyStdin(cmd *exec.Cmd, stdin io.Reader) error { + cmd.Stdin = stdin + return nil +} + +func applyStdout(cmd *exec.Cmd, stdout io.Writer) error { + cmd.Stdout = stdout + if cmd.Stderr == nil { + return applyStderr(cmd, stdout) + } + + return nil +} + +func applyStderr(cmd *exec.Cmd, stderr io.Writer) error { + cmd.Stderr = stderr + return nil +} diff --git a/engine/host/wait.go b/engine/host/wait.go new file mode 100644 index 0000000..f296664 --- /dev/null +++ b/engine/host/wait.go @@ -0,0 +1,11 @@ +package host + +import "errors" + +func (h *host) Wait() error { + if h.cmd == nil { + return errors.New("command: not started") + } + + return h.cmd.Wait() +} diff --git a/go.mod b/go.mod index 6b0f372..724f766 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,95 @@ module github.com/go-zoox/command go 1.18 -require github.com/go-zoox/testify v1.0.0 +require ( + github.com/docker/docker v24.0.6+incompatible + github.com/go-zoox/cli v1.3.6 + github.com/go-zoox/core-utils v1.2.14 + github.com/go-zoox/logger v1.4.6 + github.com/go-zoox/terminal v1.4.7 + github.com/go-zoox/testify v1.0.2 + github.com/go-zoox/uuid v0.0.1 +) require ( - github.com/go-zoox/core-utils v1.0.4 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/creack/pty v1.1.18 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-zoox/cache v1.0.4 // indirect + github.com/go-zoox/chalk v1.0.2 // indirect + github.com/go-zoox/compress v1.0.1 // indirect + github.com/go-zoox/concurrency v1.2.0 // indirect + github.com/go-zoox/config v1.2.10 // indirect + github.com/go-zoox/cookie v1.2.0 // indirect + github.com/go-zoox/counter v1.2.0 // indirect + github.com/go-zoox/cron v1.1.2 // indirect + github.com/go-zoox/crypto v1.1.8 // indirect + github.com/go-zoox/datetime v1.2.2 // indirect + github.com/go-zoox/debug v1.0.2 // indirect + github.com/go-zoox/dotenv v1.2.3 // indirect + github.com/go-zoox/encoding v1.2.1 // indirect + github.com/go-zoox/errors v1.0.2 // indirect + github.com/go-zoox/fetch v1.7.16 // indirect + github.com/go-zoox/fs v1.3.13 // indirect + github.com/go-zoox/gzip v1.0.0 // indirect + github.com/go-zoox/headers v1.0.8 // indirect + github.com/go-zoox/i18n v1.0.3 // indirect + github.com/go-zoox/ini v1.0.4 // indirect + github.com/go-zoox/jobqueue v1.0.0 // indirect + github.com/go-zoox/jsonrpc v1.2.2 // indirect + github.com/go-zoox/jwt v1.3.0 // indirect + github.com/go-zoox/kv v1.5.2 // indirect + github.com/go-zoox/proxy v1.5.3 // indirect + github.com/go-zoox/pubsub v1.2.2 // indirect + github.com/go-zoox/random v1.0.4 // indirect + github.com/go-zoox/ratelimit v1.2.0 // indirect + github.com/go-zoox/safe v1.0.1 // indirect + github.com/go-zoox/session v1.2.0 // indirect + github.com/go-zoox/tag v1.2.3 // indirect + github.com/go-zoox/zoox v1.12.8 // indirect + github.com/goccy/go-yaml v1.11.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/redis/go-redis/v9 v9.1.0 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sevlyar/go-daemon v0.1.6 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/stretchr/testify v1.8.4 // indirect + github.com/tidwall/gjson v1.16.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 // indirect + github.com/urfave/cli/v2 v2.25.7 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/term v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.6.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gotest.tools/v3 v3.5.1 // indirect ) diff --git a/go.sum b/go.sum index 97f73d1..33454eb 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,402 @@ -github.com/go-zoox/core-utils v1.0.4 h1:hkED3IlciYfTYnk7LrO+lBGC/+I1KSjQpJL6+K1v7Rg= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= +github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg= +github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/go-zoox/cache v1.0.4 h1:5THsoP8ETyNyrzkt34/LMWwdf3SceBctvTaDUWRpMoI= +github.com/go-zoox/cache v1.0.4/go.mod h1:E+rxSaCqW0o/fM5KQSueJlEcUZQ9x3penrSMh8RBCqc= +github.com/go-zoox/chalk v1.0.1/go.mod h1:z5+qvE9nEJI5uT4px2tyoFa/xxkqf3CUo22KmXLKbNI= +github.com/go-zoox/chalk v1.0.2 h1:DCWft37fogmvqF37JdbGSLg28L/tQeA8u0lMvb62KOg= +github.com/go-zoox/chalk v1.0.2/go.mod h1:z5+qvE9nEJI5uT4px2tyoFa/xxkqf3CUo22KmXLKbNI= +github.com/go-zoox/cli v1.3.6 h1:+A4l9aBBvqO/xXjwZ1PCcX0ue/HZ/Ft0Wp/dDq27iVE= +github.com/go-zoox/cli v1.3.6/go.mod h1:25ox3mVRJdRSyLJLvK8OHYEuXtMtfkTseWkJjlK9kM4= +github.com/go-zoox/compress v1.0.1 h1:EyNxo5NscMLua5fvUdiGSF+BwhuTfMeyppu7OwKAW7Q= +github.com/go-zoox/compress v1.0.1/go.mod h1:iV6CcNulf3OuEfA1h1VOsaBqYH81cVSg5wNi5HDx2h4= +github.com/go-zoox/concurrency v1.2.0 h1:iucwSWQ0Y9fFIG+eZvyHjMrIPSnaKJTGfOcGbIx91yg= +github.com/go-zoox/concurrency v1.2.0/go.mod h1:rghauUPHEDp8HJzaVlU851HWqiAqD8lUVp45K/dtNvw= +github.com/go-zoox/config v1.2.10 h1:mebuz6O0N81OXOCwtV+LKOiFuAfZ5wyaGsuzkGSSpf4= +github.com/go-zoox/config v1.2.10/go.mod h1:KnSEhz7AVMqQfznJzgpzFhQfgy8UZYeone/osbvnVUE= +github.com/go-zoox/cookie v1.2.0 h1:MO33lPQ/QGJIAEzgrsAfEpJc25lcJ/XR0w+smM19sNQ= +github.com/go-zoox/cookie v1.2.0/go.mod h1:+xEawxty0L+z+4EIvTF2AaHUkUM7oIecGZ9XrEaYqsI= github.com/go-zoox/core-utils v1.0.4/go.mod h1:EknM3KLL6/kagL95wZbWE7mRRcYCG/fHqiJ/EH0ihAs= -github.com/go-zoox/testify v1.0.0 h1:zXuj+JMcudM/dWk8HgMfCKpGYDcyHbTUBGxH35SGubU= -github.com/go-zoox/testify v1.0.0/go.mod h1:6+UZ2gOcwcnUvR5lclGRnLrE3/mLoQMAGExjrZgs3aA= +github.com/go-zoox/core-utils v1.0.12/go.mod h1:EknM3KLL6/kagL95wZbWE7mRRcYCG/fHqiJ/EH0ihAs= +github.com/go-zoox/core-utils v1.0.13/go.mod h1:EknM3KLL6/kagL95wZbWE7mRRcYCG/fHqiJ/EH0ihAs= +github.com/go-zoox/core-utils v1.2.14 h1:Z6x9QTgfBfhbSOOPEDLqLs9UGBWkXgBpVPlJ4pI68yk= +github.com/go-zoox/core-utils v1.2.14/go.mod h1:raOOwr2l2sJQyjR0Dg33sg0ry4U1/L2eNTuLFRpUXWs= +github.com/go-zoox/counter v1.0.1/go.mod h1:PICilZTrnO4dFstDPlXpjc6sdWYBG7hm/XDmjAcHaX0= +github.com/go-zoox/counter v1.2.0 h1:a1sMgYmnOza4UgjDD/fLs+HqTPG2Kh54v2IH41uIi7Q= +github.com/go-zoox/counter v1.2.0/go.mod h1:dCAErDaaxnnqQrfPNkJYklqSQrZ9SKzH3iiciJa3BH4= +github.com/go-zoox/cron v1.1.2 h1:4iEIXIYu8MFRWBZccPaQ7wkpmvBs/N6a0FzWYiup9AU= +github.com/go-zoox/cron v1.1.2/go.mod h1:7aOIpwGDyyg+NqX+041NO+9f8FhAngWiLqBPBN6kZ9k= +github.com/go-zoox/crypto v1.0.3/go.mod h1:HaWRg4tHZamqNyOnNoaK+Rw5eto+su66i8bMMP8UCBU= +github.com/go-zoox/crypto v1.1.8 h1:oI2KPLy+SsGeb+h5A99n9MTQVp4jBhwJWkqjStUzz9I= +github.com/go-zoox/crypto v1.1.8/go.mod h1:JqgNr9HcFFGQkMCGLJ9djtfg/RWVLxtunG01HD3lUXM= +github.com/go-zoox/datetime v1.0.4/go.mod h1:os6lYW/GXNpCIseFrBr8DNcOiPuwl5Ttc/kxo4JnMjw= +github.com/go-zoox/datetime v1.2.2 h1:JrI4ekdsvpsenGzrNQAOmobBTYyotaXD3YDXngvCbM4= +github.com/go-zoox/datetime v1.2.2/go.mod h1:qvaCrzjhq/g/gstx4sx06Nl4ll2pLSrkRa9ueLjrZ9A= +github.com/go-zoox/debug v1.0.1/go.mod h1:7HvnBeV1dVuuGVnXSLdJ5OE6X/wIXAjIEyiaA7NqQPA= +github.com/go-zoox/debug v1.0.2 h1:nnaSGUC1F3218P3BN6ZhRR5GNKtx5DKZ1RtsvAhIjyA= +github.com/go-zoox/debug v1.0.2/go.mod h1:7HvnBeV1dVuuGVnXSLdJ5OE6X/wIXAjIEyiaA7NqQPA= +github.com/go-zoox/dotenv v1.0.7/go.mod h1:N2bXxghq3Zk+lpiOxv+m+0yjnGubVqJGJDR/9jWm3N0= +github.com/go-zoox/dotenv v1.1.0/go.mod h1:elKALomz436YKX4Syo+f02ozIQYq2yFaprj6jL6GnCQ= +github.com/go-zoox/dotenv v1.2.3 h1:9wx4sL2u/FrRLkzoOb7ozYii6NoGsl05KoGdZm1ebIE= +github.com/go-zoox/dotenv v1.2.3/go.mod h1:hhl5WZUxI+DNJN6Zos1y7Nq0jDCXciphswPSYtInqg0= +github.com/go-zoox/encoding v1.0.5/go.mod h1:WFF+m/IWYHtClMrcKnrdZHHf3cdIF8de2uTOILPM7lw= +github.com/go-zoox/encoding v1.0.7/go.mod h1:h6ZgI27IaUSBq1ntaZjnSruPdRFuBLNUmfp57TaPxs4= +github.com/go-zoox/encoding v1.2.1 h1:38rQRsfL1f1YHZaqsPaGcNMkPnzatnPlYiHioUh9F4A= +github.com/go-zoox/encoding v1.2.1/go.mod h1:NdcM7Ln73oVW3vJgx3MH4fJknCcdQfq+NgJ0tuCo7tU= +github.com/go-zoox/errors v1.0.2 h1:1NLMoEVlDU1+qrvvPj+rrJXOvQPdeZ3DekVBFrI5PFY= +github.com/go-zoox/errors v1.0.2/go.mod h1:HJ5NKQb9cu3IbI0Jayw7xZiblLBEIglpaIOMxvQnWnk= +github.com/go-zoox/fetch v1.3.5/go.mod h1:AkS6v/DlotjmUs+7qJsoFGFkpROr9LVtiKYb000v3Kw= +github.com/go-zoox/fetch v1.4.4/go.mod h1:WExVnds3HZ1A6jJu9KuqtICfkJpvUdR4uONUnw9TG+0= +github.com/go-zoox/fetch v1.7.16 h1:3bRoF2bG+M5PnWoFXka64PfHRx35Y60Mu70z2F5USDM= +github.com/go-zoox/fetch v1.7.16/go.mod h1:zaDVj8s8gPFzEeFFsD2oWc5D1z8uKKQwwnilmPdSQOk= +github.com/go-zoox/fs v1.2.4/go.mod h1:aywpClMqf6YO8+QnuwC3p3EvFWe88h0tWH65rpxtY00= +github.com/go-zoox/fs v1.2.5/go.mod h1:aywpClMqf6YO8+QnuwC3p3EvFWe88h0tWH65rpxtY00= +github.com/go-zoox/fs v1.3.13 h1:fe0uvtXCM+9s51z/CnQ5kxB4hBYaK55tkrE9gq0385U= +github.com/go-zoox/fs v1.3.13/go.mod h1:wCM+UQkjFTxNjOOCNlGcN3k9FeXXUwn9bFnpyjOn55c= +github.com/go-zoox/gzip v1.0.0 h1:11ZTgxAPgexmZ/NJaEEuN2FDCJuvg9sips+XDR+48Yw= +github.com/go-zoox/gzip v1.0.0/go.mod h1:7g9vTpKek1dft1Yi1Ryi4A6dq9snMgq94Qq8wSte8L0= +github.com/go-zoox/headers v1.0.8 h1:HZJisMHhKwdySVNbV4Awc5kaMxFfAwBIHpcWOGch+iw= +github.com/go-zoox/headers v1.0.8/go.mod h1:WEgEbewswEw4n4qS1iG68Kn/vOQVCAKGwwuZankc6so= +github.com/go-zoox/i18n v1.0.3 h1:PqeOKyhI9MxbA9TyWDgm7zcCL5WRSlxhANHWou04VHk= +github.com/go-zoox/i18n v1.0.3/go.mod h1:WURpyaWOrVVN4f3mEQtl5A0kie5bK4ExQJ0PnHSOfTI= +github.com/go-zoox/ini v1.0.4 h1:N4mUbAO0juYIRrv3ysjKtpEn/+yQv57eQietsgpkAYQ= +github.com/go-zoox/ini v1.0.4/go.mod h1:SisQneNLb1EBeZ5bA5GnrJd8FNg372hQrPh+gb3IzV4= +github.com/go-zoox/jobqueue v1.0.0 h1:pVv/eGI0CLLHUP3rDVyn0ALzsobtaxTOnkWw/JhW9Vg= +github.com/go-zoox/jobqueue v1.0.0/go.mod h1:jUCZxrQcM28orhac67eNLU7SBiVNXehxSelj7j4MM88= +github.com/go-zoox/jsonrpc v1.2.2 h1:asaoJgJkfyH5eblLQ1WzrZDe8ERL6v9GT4pKR/LJ3IE= +github.com/go-zoox/jsonrpc v1.2.2/go.mod h1:HdxJW/T0hkVHlfm+ULRnNEqvTtvZ7o4qxdQGQW76khM= +github.com/go-zoox/jwt v1.0.0/go.mod h1:a6ANQHmSs+b9GJv5aad2cQLl8opFmP3hMOxZtgXRmis= +github.com/go-zoox/jwt v1.3.0 h1:beyPOdiiNrNK8dqFijt5kdtaeh1dZKtM7/kaCMGbV0U= +github.com/go-zoox/jwt v1.3.0/go.mod h1:Cfc+t0XhNCgDjXLR5sK6ao7qz1GSIq896gZ1usNb7t8= +github.com/go-zoox/kv v1.4.1/go.mod h1:dc3whoIvGrYmQA2wi6g6ZE0oOtRg+loxaJEj6bLKlJA= +github.com/go-zoox/kv v1.4.3/go.mod h1:hRCBcPBHilKmeSEsn4o67LBaXurX0+m3Tq9Ec4aIRWk= +github.com/go-zoox/kv v1.5.2 h1:LQI3YiC163NTxGzoM+OdZ2ubimyoc7kHSp40FDBSC6k= +github.com/go-zoox/kv v1.5.2/go.mod h1:u/IbVscKbZk4AyDvvnsK9DiaWshH/Nz3twlGDRyC9pA= +github.com/go-zoox/logger v1.2.0/go.mod h1:mBImRV6zpbGtiIjDz/C9vWi80wWc2OTOl9N9P0SAJgk= +github.com/go-zoox/logger v1.4.6 h1:zHUaB6KQ9rD/N3hM0JJ3/JCNdgtedf4mVBBNNSyWCOg= +github.com/go-zoox/logger v1.4.6/go.mod h1:o7ddvv/gMoMa0TomPhHoIz11ZWRbQ92pF6rwYbOY3iQ= +github.com/go-zoox/proxy v1.2.3/go.mod h1:T+gbngAtIgvambbYibAbzrjwdu8j5pduJdA2j6RYi94= +github.com/go-zoox/proxy v1.5.3 h1:HoWKuWBLHkFlHsI0tOr0t0IkKTpcDeypSjBv5BNHG4Q= +github.com/go-zoox/proxy v1.5.3/go.mod h1:KLWeJqfQk1upCvEdXt3tEuM8xSu0ApbA9FNLOmyHysY= +github.com/go-zoox/pubsub v1.2.2 h1:dpcFlZRSGhX0YqT/WoOJgP5bP2VDqswPqXiiFZCki1w= +github.com/go-zoox/pubsub v1.2.2/go.mod h1:LWX0NAg80hkeGdZf7PJOEGnyN6CXooCxpIlh2MxESDo= +github.com/go-zoox/random v1.0.0/go.mod h1:W+PTQiInxaCngiXpSvycucAKvu1tE/tKlZ9kaMp2/Ys= +github.com/go-zoox/random v1.0.4 h1:icckpkCowQ0eGiiMkHFOJz9Qc9noOcinP+ggqWUIBH4= +github.com/go-zoox/random v1.0.4/go.mod h1:W+PTQiInxaCngiXpSvycucAKvu1tE/tKlZ9kaMp2/Ys= +github.com/go-zoox/ratelimit v1.0.1/go.mod h1:5MtLMrfQRbZHI+tKC4eyHZorrZX005Sy/Dldnk8qYOU= +github.com/go-zoox/ratelimit v1.2.0 h1:BWytTr0HG5xBZvelEDNIqiXT4yavFH+QwpMgSjLt3+M= +github.com/go-zoox/ratelimit v1.2.0/go.mod h1:gbnJYgl6heLTs3aRM5C8FC9ehSIO3cmEFWzbDe/m8yo= +github.com/go-zoox/safe v1.0.1 h1:JwWK7xCyv7eyzBbwzQvhK/Ajm8gG2Q9Cvd/KXpdF2zI= +github.com/go-zoox/safe v1.0.1/go.mod h1:lT0iEBmpoia7xfh2bWzdurzdv++4QRUAfeEzIhCnpoA= +github.com/go-zoox/session v1.2.0 h1:hzjcZYV3+cVmocnC6MazhtELONMtRlIuEezCYvbxY9Q= +github.com/go-zoox/session v1.2.0/go.mod h1:SLHzCK3DDknqot28deZQFBPz5hm9QHcUeRra8y9GT8E= +github.com/go-zoox/tag v1.0.2/go.mod h1:TNFY+IN6FgsD0KGV6mrnuVXONUq7zpH01k53BcNsT8k= +github.com/go-zoox/tag v1.0.6/go.mod h1:jrbJgC1dZAN5+vZlmrUKu1/UpbOo0xVyCC1MfLpGGqk= +github.com/go-zoox/tag v1.0.9/go.mod h1:jrbJgC1dZAN5+vZlmrUKu1/UpbOo0xVyCC1MfLpGGqk= +github.com/go-zoox/tag v1.1.0/go.mod h1:yMB7bMseqbOshUW9O9Dqfq0C7Mmy9OkccV/meEJHICs= +github.com/go-zoox/tag v1.2.3 h1:HDQpRu8rA1xSJt6c+v0O7TfzTjPq5aDtyzW/15aTh94= +github.com/go-zoox/tag v1.2.3/go.mod h1:z9z4iZb/XPE4HwTXJgPIdwgH90c2NysGxIMq9tW+GuU= +github.com/go-zoox/terminal v1.4.7 h1:UUtvdN95wmfdjiIjAwcwJDJsE4BEHH8mQ1bqD83SAU0= +github.com/go-zoox/terminal v1.4.7/go.mod h1:VEk5VxyHAtkMzV4Qg9iFowUcZuYyO6ECcNLh67jMq58= +github.com/go-zoox/testify v1.0.2 h1:G5sQ3xm0uwCuytnMhgnqZ5BItCt2DN3n2wLBqlIJEWA= +github.com/go-zoox/testify v1.0.2/go.mod h1:L35iVL6xDKDL/TQOTRWyNL4H4nm8bzs6nde5XA7PYnY= +github.com/go-zoox/uuid v0.0.1 h1:txqmDavRTq68gzzqWfJQLorFyUp9a7M2lmq2KcwPGPA= +github.com/go-zoox/uuid v0.0.1/go.mod h1:0/F4LdfLqFdyqOf7aXoiYXRkXHU324JQ5DZEytXYBPM= +github.com/go-zoox/zoox v1.2.19/go.mod h1:xk3S3L58ugJIDyuZMCYrj3qIGLSxddbkARwTRkpxPVE= +github.com/go-zoox/zoox v1.12.8 h1:6Mo507JhfAzfVC7huS/2kr6EAP4PjhflgY8gUjtMrXg= +github.com/go-zoox/zoox v1.12.8/go.mod h1:W31vOF9Wo37KjJNFcD/4An0NU9lXH15vgaV7IDDp2r4= +github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= +github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54= +github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= +github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sevlyar/go-daemon v0.1.6 h1:EUh1MDjEM4BI109Jign0EaknA2izkOyi0LV3ro3QQGs= +github.com/sevlyar/go-daemon v0.1.6/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= +github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/io.go b/io.go new file mode 100644 index 0000000..d3c3f6f --- /dev/null +++ b/io.go @@ -0,0 +1,15 @@ +package command + +import "io" + +func (c *command) SetStdin(stdin io.Reader) error { + return c.engine.SetStdin(stdin) +} + +func (c *command) SetStdout(stdout io.Writer) error { + return c.engine.SetStdout(stdout) +} + +func (c *command) SetStderr(stderr io.Writer) error { + return c.engine.SetStderr(stderr) +} diff --git a/new.go b/new.go deleted file mode 100644 index 8cdede9..0000000 --- a/new.go +++ /dev/null @@ -1,26 +0,0 @@ -package command - -// NewOptions is the options for new -type NewOptions struct { - Context string - Environment map[string]string - Shell string -} - -// New creates a Command -func New(script string, options ...*NewOptions) *Command { - var context string - var environment map[string]string - var shell = "/bin/sh" - if len(options) > 0 && options[0] != nil { - context = options[0].Context - environment = options[0].Environment - } - - return &Command{ - Script: script, - Context: context, - Environment: environment, - Shell: shell, - } -} diff --git a/run.go b/run.go new file mode 100644 index 0000000..11b5526 --- /dev/null +++ b/run.go @@ -0,0 +1,9 @@ +package command + +func (c *command) Run() error { + if err := c.Start(); err != nil { + return err + } + + return c.Wait() +} diff --git a/start.go b/start.go new file mode 100644 index 0000000..14598a0 --- /dev/null +++ b/start.go @@ -0,0 +1,11 @@ +package command + +import "errors" + +func (c *command) Start() error { + if c.engine == nil { + return errors.New("engine not set") + } + + return c.engine.Start() +} diff --git a/tmp/command_old.go b/tmp/command_old.go new file mode 100644 index 0000000..82e342b --- /dev/null +++ b/tmp/command_old.go @@ -0,0 +1,86 @@ +package command + +import ( + "encoding/json" + "fmt" + "io" + "os" + "os/exec" +) + +// command is better os/exec command +type command struct { + Script string `json:"content"` + Context string `json:"context"` + Environment map[string]string `json:"environment"` + Shell string `json:"shell"` + // + Stdout io.Writer + Stderr io.Writer + // + cmd *exec.Cmd +} + +// Run runs the command +func (c *command) Run() error { + environment := os.Environ() + + for k, v := range c.Environment { + environment = append(environment, fmt.Sprintf("%s=%s", k, v)) + } + + shell := c.Shell + if shell == "" { + shell = os.Getenv("SHELL") + if shell == "" { + shell = "sh" + } + } + + cmd := exec.Command(shell, "-c", c.Script) + cmd.Dir = c.Context + cmd.Env = environment + + cmd.Stdout = c.Stdout + if cmd.Stdout == nil { + cmd.Stdout = os.Stdout + } + + cmd.Stderr = c.Stderr + if cmd.Stderr == nil { + cmd.Stderr = os.Stderr + } + + c.cmd = cmd + + if err := cmd.Run(); err != nil { + return err + } + + return nil +} + +// Config gets the config of command +func (c *command) Config() (string, error) { + cfg, err := json.MarshalIndent(c, "", " ") + if err != nil { + return "", err + } + + return string(cfg), nil +} + +// MustConfig gets the config of command +func (c *command) MustConfig() string { + cfg, err := c.Config() + if err != nil { + return "" + } + + return cfg +} + +// ExitCode gets the exit code of process +func (c *command) ExitCode() int { + return c.cmd.ProcessState.ExitCode() +} diff --git a/command_test.go b/tmp/command_test.go similarity index 95% rename from command_test.go rename to tmp/command_test.go index 63ba0ee..65fb758 100644 --- a/command_test.go +++ b/tmp/command_test.go @@ -8,7 +8,7 @@ import ( ) func TestCommand(t *testing.T) { - cmd := &Command{ + cmd := &command{ Script: `echo "hello world"`, } @@ -25,7 +25,7 @@ func TestCommand(t *testing.T) { } func TestCommandWithContext(t *testing.T) { - cmd := &Command{ + cmd := &command{ Script: `echo "PWD: $PWD"`, Context: `/tmp`, } @@ -43,7 +43,7 @@ func TestCommandWithContext(t *testing.T) { } func TestCommandWithEnvironment(t *testing.T) { - cmd := &Command{ + cmd := &command{ Script: `echo "PWD: $PWD"`, Context: `/tmp`, Environment: map[string]string{ @@ -68,7 +68,7 @@ func TestCommandWithEnvironment(t *testing.T) { } func TestCommandWithShell(t *testing.T) { - cmd := &Command{ + cmd := &command{ Script: `echo "PWD: $PWD"`, Context: `/tmp`, Environment: map[string]string{ @@ -95,7 +95,7 @@ func TestCommandWithShell(t *testing.T) { func TestCommandWithMultilines(t *testing.T) { output := &Output{} - cmd := &Command{ + cmd := &command{ Script: ` echo 1 echo 2 diff --git a/wait.go b/wait.go new file mode 100644 index 0000000..6ffd5f2 --- /dev/null +++ b/wait.go @@ -0,0 +1,5 @@ +package command + +func (c *command) Wait() error { + return c.engine.Wait() +} From 82b5139be88d9bac22021ee37309f4cefcf92855 Mon Sep 17 00:00:00 2001 From: Zero Date: Sat, 7 Oct 2023 19:55:21 +0800 Subject: [PATCH 02/14] feat: support terminal --- cmd/cmd/commands/exec.go | 208 +++++++++++++++++++++++++++++++++++++ cmd/cmd/commands/run.go | 47 --------- cmd/cmd/main.go | 2 +- command.go | 3 + engine/engine.go | 8 +- engine/host/cancel.go | 6 -- engine/host/create.go | 121 ++++++++++++++++++++++ engine/host/host.go | 4 + engine/host/start.go | 111 -------------------- engine/host/terminal.go | 41 ++++++++ engine/host/wait.go | 6 -- go.mod | 49 ++------- go.sum | 214 --------------------------------------- terminal.go | 7 ++ terminal/terminal.go | 15 +++ 15 files changed, 414 insertions(+), 428 deletions(-) create mode 100644 cmd/cmd/commands/exec.go delete mode 100644 cmd/cmd/commands/run.go create mode 100644 engine/host/create.go create mode 100644 engine/host/terminal.go create mode 100644 terminal.go create mode 100644 terminal/terminal.go diff --git a/cmd/cmd/commands/exec.go b/cmd/cmd/commands/exec.go new file mode 100644 index 0000000..58c8e16 --- /dev/null +++ b/cmd/cmd/commands/exec.go @@ -0,0 +1,208 @@ +package commands + +import ( + "fmt" + "io" + "os" + "os/signal" + "syscall" + "time" + + "github.com/eiannone/keyboard" + "github.com/go-zoox/cli" + "github.com/go-zoox/command" + "github.com/go-zoox/command/terminal" + + "golang.org/x/term" +) + +func Exec(app *cli.MultipleProgram) { + app.Register("exec", &cli.Command{ + Name: "exec", + Usage: "command execute", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "engine", + Usage: "command engine", + Aliases: []string{"e"}, + EnvVars: []string{"ENGINE"}, + Value: "host", + }, + &cli.StringFlag{ + Name: "command", + Usage: "the command", + Aliases: []string{"c"}, + EnvVars: []string{"COMMAND"}, + }, + &cli.StringFlag{ + Name: "shell", + Usage: "the command shell", + Aliases: []string{"s"}, + EnvVars: []string{"SHELL"}, + }, + &cli.BoolFlag{ + Name: "tty", + Usage: "Allocate a pseudo-TTY. The default is false, which disables TTY allocation.", + Aliases: []string{"t"}, + EnvVars: []string{"TTY"}, + }, + }, + Action: func(ctx *cli.Context) (err error) { + cmd, err := command.New(&command.Config{ + Engine: ctx.String("engine"), + Command: ctx.String("command"), + Shell: ctx.String("shell"), + }) + if err != nil { + return err + } + + if ctx.Bool("tty") { + term, err := cmd.Terminal() + if err != nil { + return err + } + defer term.Close() + + go func() { + buf := make([]byte, 1024) + for { + n, err := term.Read(buf) + if err != nil && err != io.EOF { + os.Stderr.Write([]byte(err.Error())) + os.Exit(term.ExitCode()) + return + } + + os.Stdout.Write(buf[:n]) + } + }() + + if err := connectKeyboard(term); err != nil { + return err + } + + return nil + } + + return cmd.Run() + }, + }) +} + +func connectKeyboard(t terminal.Terminal) error { + // resize + if err := resizeTerminal(t); err != nil { + return err + } + + // 监听操作系统信号 + sigWinch := make(chan os.Signal, 1) + signal.Notify(sigWinch, syscall.SIGWINCH) + // 启动循环来检测终端窗口大小是否发生变化 + go func() { + for { + select { + case <-sigWinch: + resizeTerminal(t) + default: + time.Sleep(time.Millisecond * 100) + } + } + }() + + if err := keyboard.Open(); err != nil { + return err + } + defer func() { + _ = keyboard.Close() + }() + + for { + char, key, err := keyboard.GetKey() + if err != nil { + return err + } + + // fmt.Printf("You pressed: rune:%q, key %X\r\n", char, key) + if key == keyboard.KeyCtrlD { + break + } + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + + // key == 0 => char + if key == 0 { + _, err = t.Write([]byte{byte(char)}) + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + } else { + switch key { + case keyboard.KeyF1: + _, err = t.Write([]byte{0x1b, 0x4f, 0x50}) + case keyboard.KeyF2: + _, err = t.Write([]byte{0x1b, 0x4f, 0x51}) + case keyboard.KeyF3: + _, err = t.Write([]byte{0x1b, 0x4f, 0x52}) + case keyboard.KeyF4: + _, err = t.Write([]byte{0x1b, 0x4f, 0x53}) + case keyboard.KeyF5: + _, err = t.Write([]byte{0x1b, 0x5b, 0x31, 0x35, 0x7e}) + case keyboard.KeyF6: + _, err = t.Write([]byte{0x1b, 0x5b, 0x31, 0x37, 0x7e}) + case keyboard.KeyF7: + _, err = t.Write([]byte{0x1b, 0x5b, 0x31, 0x38, 0x7e}) + case keyboard.KeyF8: + _, err = t.Write([]byte{0x1b, 0x5b, 0x31, 0x39, 0x7e}) + case keyboard.KeyF9: + _, err = t.Write([]byte{0x1b, 0x5b, 0x32, 0x30, 0x7e}) + case keyboard.KeyF10: + _, err = t.Write([]byte{0x1b, 0x5b, 0x32, 0x31, 0x7e}) + case keyboard.KeyF11: + _, err = t.Write([]byte{0x1b, 0x5b, 0x32, 0x33, 0x7e}) + case keyboard.KeyF12: + _, err = t.Write([]byte{0x1b, 0x5b, 0x32, 0x34, 0x7e}) + case keyboard.KeyInsert: + _, err = t.Write([]byte{0x1b, 0x5b, 0x32, 0x7e}) + case keyboard.KeyDelete: + _, err = t.Write([]byte{0x1b, 0x5b, 0x33, 0x7e}) + case keyboard.KeyHome: + _, err = t.Write([]byte{0x1b, 0x5b, 0x48}) + case keyboard.KeyEnd: + _, err = t.Write([]byte{0x1b, 0x5b, 0x46}) + case keyboard.KeyPgup: + _, err = t.Write([]byte{0x1b, 0x5b, 0x35, 0x7e}) + case keyboard.KeyPgdn: + _, err = t.Write([]byte{0x1b, 0x5b, 0x36, 0x7e}) + case keyboard.KeyArrowUp: + _, err = t.Write([]byte{0x1b, 0x5b, 0x41}) + case keyboard.KeyArrowDown: + _, err = t.Write([]byte{0x1b, 0x5b, 0x42}) + case keyboard.KeyArrowRight: + _, err = t.Write([]byte{0x1b, 0x5b, 0x43}) + case keyboard.KeyArrowLeft: + _, err = t.Write([]byte{0x1b, 0x5b, 0x44}) + default: + _, err = t.Write([]byte{byte(key)}) + } + + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + } + } + + return nil +} + +func resizeTerminal(t terminal.Terminal) error { + fd := int(os.Stdin.Fd()) + columns, rows, err := term.GetSize(fd) + if err != nil { + return err + } + + return t.Resize(rows, columns) +} diff --git a/cmd/cmd/commands/run.go b/cmd/cmd/commands/run.go deleted file mode 100644 index d8d8c9c..0000000 --- a/cmd/cmd/commands/run.go +++ /dev/null @@ -1,47 +0,0 @@ -package commands - -import ( - "github.com/go-zoox/cli" - "github.com/go-zoox/command" -) - -func Run(app *cli.MultipleProgram) { - app.Register("run", &cli.Command{ - Name: "run", - Usage: "command run", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "engine", - Usage: "command engine", - Aliases: []string{"e"}, - EnvVars: []string{"ENGINE"}, - Value: "host", - }, - &cli.StringFlag{ - Name: "command", - Usage: "the command", - Aliases: []string{"c"}, - EnvVars: []string{"COMMAND"}, - Required: true, - }, - &cli.StringFlag{ - Name: "shell", - Usage: "the command shell", - Aliases: []string{"s"}, - EnvVars: []string{"SHELL"}, - }, - }, - Action: func(ctx *cli.Context) (err error) { - cmd, err := command.New(&command.Config{ - Engine: ctx.String("engine"), - Command: ctx.String("command"), - Shell: ctx.String("shell"), - }) - if err != nil { - return err - } - - return cmd.Run() - }, - }) -} diff --git a/cmd/cmd/main.go b/cmd/cmd/main.go index 941233b..7006ece 100644 --- a/cmd/cmd/main.go +++ b/cmd/cmd/main.go @@ -13,7 +13,7 @@ func main() { Version: command.Version, }) - commands.Run(app) + commands.Exec(app) app.Run() } diff --git a/command.go b/command.go index 49dadf7..f66ec2b 100644 --- a/command.go +++ b/command.go @@ -5,6 +5,7 @@ import ( "github.com/go-zoox/command/engine" "github.com/go-zoox/command/engine/host" + "github.com/go-zoox/command/terminal" ) type Command interface { @@ -13,6 +14,8 @@ type Command interface { Cancel() error // Run() error + // + Terminal() (terminal.Terminal, error) } type Config struct { diff --git a/engine/engine.go b/engine/engine.go index db946e2..f377f11 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -1,6 +1,10 @@ package engine -import "io" +import ( + "io" + + "github.com/go-zoox/command/terminal" +) type Engine interface { Start() error @@ -10,6 +14,8 @@ type Engine interface { SetStdin(stdin io.Reader) error SetStdout(stdout io.Writer) error SetStderr(stderr io.Writer) error + // + Terminal() (terminal.Terminal, error) } type Config struct { diff --git a/engine/host/cancel.go b/engine/host/cancel.go index 671c572..1c5d1ae 100644 --- a/engine/host/cancel.go +++ b/engine/host/cancel.go @@ -1,12 +1,6 @@ package host -import "errors" - func (h *host) Cancel() error { - if h.cmd == nil { - return errors.New("command: not started") - } - if err := h.cmd.Process.Kill(); err != nil { return err } diff --git a/engine/host/create.go b/engine/host/create.go new file mode 100644 index 0000000..7c59ceb --- /dev/null +++ b/engine/host/create.go @@ -0,0 +1,121 @@ +package host + +import ( + "errors" + "fmt" + "io" + "os" + "os/exec" + "os/user" + "syscall" + + "github.com/go-zoox/logger" + "github.com/spf13/cast" +) + +func (h *host) create() error { + if h.cmd != nil { + return errors.New("command: already created") + } + + args := []string{} + if h.cfg.Command != "" { + args = append(args, "-c", h.cfg.Command) + } + + logger.Debugf("create command: %s %v", h.cfg.Shell, args) + h.cmd = exec.Command(h.cfg.Shell, args...) + + if err := applyEnv(h.cmd, h.cfg.Environment); err != nil { + return err + } + + if err := applyWorkDir(h.cmd, h.cfg.WorkDir); err != nil { + return err + } + + // if err := applyUser(h.cmd, h.cfg.User); err != nil { + // return err + // } + + if err := applyHistory(h.cmd, h.cfg.IsHistoryDisabled); err != nil { + return err + } + + return nil +} + +func applyEnv(cmd *exec.Cmd, environment map[string]string) error { + cmd.Env = append(os.Environ(), "TERM=xterm") + + for k, v := range environment { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) + } + + return nil +} + +func applyWorkDir(cmd *exec.Cmd, workDir string) error { + cmd.Dir = workDir + return nil +} + +func applyUser(cmd *exec.Cmd, username string) error { + if username == "" { + return nil + } + + userX, err := user.Lookup(username) + if err != nil { + return err + } + + logger.Infof("[command] uid=%s gid=%s", userX.Uid, userX.Gid) + + uid := cast.ToInt(userX.Uid) + gid := cast.ToInt(userX.Gid) + + cmd.SysProcAttr = &syscall.SysProcAttr{} + cmd.SysProcAttr.Credential = &syscall.Credential{ + Uid: uint32(uid), + Gid: uint32(gid), + } + + cmd.Env = append( + cmd.Env, + "USER="+username, + "HOME="+userX.HomeDir, + "LOGNAME="+username, + "UID="+userX.Uid, + "GID="+userX.Gid, + ) + + return nil +} + +func applyHistory(cmd *exec.Cmd, disable bool) error { + if disable { + cmd.Env = append(cmd.Env, "HISTFILE=/dev/null") + } + + return nil +} + +func applyStdin(cmd *exec.Cmd, stdin io.Reader) error { + cmd.Stdin = stdin + return nil +} + +func applyStdout(cmd *exec.Cmd, stdout io.Writer) error { + cmd.Stdout = stdout + if cmd.Stderr == nil { + return applyStderr(cmd, stdout) + } + + return nil +} + +func applyStderr(cmd *exec.Cmd, stderr io.Writer) error { + cmd.Stderr = stderr + return nil +} diff --git a/engine/host/host.go b/engine/host/host.go index a366502..115f4c7 100644 --- a/engine/host/host.go +++ b/engine/host/host.go @@ -31,5 +31,9 @@ func New(cfg *Config) (engine.Engine, error) { stderr: os.Stderr, } + if err := h.create(); err != nil { + return nil, err + } + return h, nil } diff --git a/engine/host/start.go b/engine/host/start.go index 6f0ef3e..4ae2097 100644 --- a/engine/host/start.go +++ b/engine/host/start.go @@ -1,42 +1,6 @@ package host -import ( - "errors" - "fmt" - "io" - "os" - "os/exec" - "os/user" - "syscall" - - "github.com/go-zoox/core-utils/cast" - "github.com/go-zoox/logger" -) - func (h *host) Start() error { - if h.cmd != nil { - return errors.New("command: already started") - } - - logger.Debugf("start command: %s %s %s", h.cfg.Shell, "-c", h.cfg.Command) - h.cmd = exec.Command(h.cfg.Shell, "-c", h.cfg.Command) - - if err := applyEnv(h.cmd, h.cfg.Environment); err != nil { - return err - } - - if err := applyWorkDir(h.cmd, h.cfg.WorkDir); err != nil { - return err - } - - if err := applyUser(h.cmd, h.cfg.User); err != nil { - return err - } - - if err := applyHistory(h.cmd, h.cfg.IsHistoryDisabled); err != nil { - return err - } - if err := applyStdin(h.cmd, h.stdin); err != nil { return nil } @@ -51,78 +15,3 @@ func (h *host) Start() error { return h.cmd.Start() } - -func applyEnv(cmd *exec.Cmd, environment map[string]string) error { - cmd.Env = append(os.Environ(), "TERM=xterm") - - for k, v := range environment { - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) - } - - return nil -} - -func applyWorkDir(cmd *exec.Cmd, workDir string) error { - cmd.Dir = workDir - return nil -} - -func applyUser(cmd *exec.Cmd, username string) error { - if username == "" { - return nil - } - - userX, err := user.Lookup(username) - if err != nil { - return err - } - - logger.Infof("[command] uid=%s gid=%s", userX.Uid, userX.Gid) - - uid := cast.ToInt(userX.Uid) - gid := cast.ToInt(userX.Gid) - - cmd.SysProcAttr = &syscall.SysProcAttr{} - cmd.SysProcAttr.Credential = &syscall.Credential{ - Uid: uint32(uid), - Gid: uint32(gid), - } - - cmd.Env = append( - cmd.Env, - "USER="+username, - "HOME="+userX.HomeDir, - "LOGNAME="+username, - "UID="+userX.Uid, - "GID="+userX.Gid, - ) - - return nil -} - -func applyHistory(cmd *exec.Cmd, disable bool) error { - if disable { - cmd.Env = append(cmd.Env, "HISTFILE=/dev/null") - } - - return nil -} - -func applyStdin(cmd *exec.Cmd, stdin io.Reader) error { - cmd.Stdin = stdin - return nil -} - -func applyStdout(cmd *exec.Cmd, stdout io.Writer) error { - cmd.Stdout = stdout - if cmd.Stderr == nil { - return applyStderr(cmd, stdout) - } - - return nil -} - -func applyStderr(cmd *exec.Cmd, stderr io.Writer) error { - cmd.Stderr = stderr - return nil -} diff --git a/engine/host/terminal.go b/engine/host/terminal.go new file mode 100644 index 0000000..633d61a --- /dev/null +++ b/engine/host/terminal.go @@ -0,0 +1,41 @@ +package host + +import ( + "os" + "os/exec" + + "github.com/creack/pty" + "github.com/go-zoox/command/terminal" +) + +func (h *host) Terminal() (terminal.Terminal, error) { + terminal, err := pty.Start(h.cmd) + if err != nil { + return nil, err + } + + return &Terminal{ + File: terminal, + Cmd: h.cmd, + }, nil +} + +type Terminal struct { + *os.File + Cmd *exec.Cmd +} + +func (rt *Terminal) Resize(rows, cols int) error { + return pty.Setsize(rt.File, &pty.Winsize{ + Rows: uint16(rows), + Cols: uint16(cols), + }) +} + +func (rt *Terminal) Wait() error { + return rt.Cmd.Wait() +} + +func (rt *Terminal) ExitCode() int { + return rt.Cmd.ProcessState.ExitCode() +} diff --git a/engine/host/wait.go b/engine/host/wait.go index f296664..64f419e 100644 --- a/engine/host/wait.go +++ b/engine/host/wait.go @@ -1,11 +1,5 @@ package host -import "errors" - func (h *host) Wait() error { - if h.cmd == nil { - return errors.New("command: not started") - } - return h.cmd.Wait() } diff --git a/go.mod b/go.mod index 724f766..2a76a55 100644 --- a/go.mod +++ b/go.mod @@ -1,68 +1,43 @@ module github.com/go-zoox/command -go 1.18 +go 1.20 require ( + github.com/creack/pty v1.1.18 github.com/docker/docker v24.0.6+incompatible + github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 github.com/go-zoox/cli v1.3.6 - github.com/go-zoox/core-utils v1.2.14 github.com/go-zoox/logger v1.4.6 github.com/go-zoox/terminal v1.4.7 github.com/go-zoox/testify v1.0.2 github.com/go-zoox/uuid v0.0.1 + github.com/spf13/cast v1.5.1 + golang.org/x/term v0.12.0 ) require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/creack/pty v1.1.18 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 // indirect github.com/fatih/color v1.15.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-redis/redis/v8 v8.11.5 // indirect - github.com/go-zoox/cache v1.0.4 // indirect + github.com/go-playground/validator/v10 v10.10.0 // indirect github.com/go-zoox/chalk v1.0.2 // indirect - github.com/go-zoox/compress v1.0.1 // indirect - github.com/go-zoox/concurrency v1.2.0 // indirect github.com/go-zoox/config v1.2.10 // indirect - github.com/go-zoox/cookie v1.2.0 // indirect - github.com/go-zoox/counter v1.2.0 // indirect - github.com/go-zoox/cron v1.1.2 // indirect - github.com/go-zoox/crypto v1.1.8 // indirect + github.com/go-zoox/core-utils v1.2.14 // indirect github.com/go-zoox/datetime v1.2.2 // indirect - github.com/go-zoox/debug v1.0.2 // indirect github.com/go-zoox/dotenv v1.2.3 // indirect github.com/go-zoox/encoding v1.2.1 // indirect - github.com/go-zoox/errors v1.0.2 // indirect - github.com/go-zoox/fetch v1.7.16 // indirect github.com/go-zoox/fs v1.3.13 // indirect - github.com/go-zoox/gzip v1.0.0 // indirect - github.com/go-zoox/headers v1.0.8 // indirect - github.com/go-zoox/i18n v1.0.3 // indirect github.com/go-zoox/ini v1.0.4 // indirect - github.com/go-zoox/jobqueue v1.0.0 // indirect - github.com/go-zoox/jsonrpc v1.2.2 // indirect - github.com/go-zoox/jwt v1.3.0 // indirect - github.com/go-zoox/kv v1.5.2 // indirect - github.com/go-zoox/proxy v1.5.3 // indirect - github.com/go-zoox/pubsub v1.2.2 // indirect - github.com/go-zoox/random v1.0.4 // indirect - github.com/go-zoox/ratelimit v1.2.0 // indirect - github.com/go-zoox/safe v1.0.1 // indirect - github.com/go-zoox/session v1.2.0 // indirect github.com/go-zoox/tag v1.2.3 // indirect - github.com/go-zoox/zoox v1.12.8 // indirect github.com/goccy/go-yaml v1.11.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.3.1 // indirect - github.com/gorilla/websocket v1.5.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -71,26 +46,16 @@ require ( github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/redis/go-redis/v9 v9.1.0 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sevlyar/go-daemon v0.1.6 // indirect - github.com/spf13/cast v1.5.1 // indirect github.com/stretchr/testify v1.8.4 // indirect - github.com/tidwall/gjson v1.16.0 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.1 // indirect github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 // indirect github.com/urfave/cli/v2 v2.25.7 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/crypto v0.13.0 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.6.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/go.sum b/go.sum index 33454eb..a5ffeb3 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,6 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= -github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -18,8 +10,6 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= @@ -32,122 +22,38 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg= github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= -github.com/go-zoox/cache v1.0.4 h1:5THsoP8ETyNyrzkt34/LMWwdf3SceBctvTaDUWRpMoI= -github.com/go-zoox/cache v1.0.4/go.mod h1:E+rxSaCqW0o/fM5KQSueJlEcUZQ9x3penrSMh8RBCqc= -github.com/go-zoox/chalk v1.0.1/go.mod h1:z5+qvE9nEJI5uT4px2tyoFa/xxkqf3CUo22KmXLKbNI= github.com/go-zoox/chalk v1.0.2 h1:DCWft37fogmvqF37JdbGSLg28L/tQeA8u0lMvb62KOg= github.com/go-zoox/chalk v1.0.2/go.mod h1:z5+qvE9nEJI5uT4px2tyoFa/xxkqf3CUo22KmXLKbNI= github.com/go-zoox/cli v1.3.6 h1:+A4l9aBBvqO/xXjwZ1PCcX0ue/HZ/Ft0Wp/dDq27iVE= github.com/go-zoox/cli v1.3.6/go.mod h1:25ox3mVRJdRSyLJLvK8OHYEuXtMtfkTseWkJjlK9kM4= -github.com/go-zoox/compress v1.0.1 h1:EyNxo5NscMLua5fvUdiGSF+BwhuTfMeyppu7OwKAW7Q= -github.com/go-zoox/compress v1.0.1/go.mod h1:iV6CcNulf3OuEfA1h1VOsaBqYH81cVSg5wNi5HDx2h4= -github.com/go-zoox/concurrency v1.2.0 h1:iucwSWQ0Y9fFIG+eZvyHjMrIPSnaKJTGfOcGbIx91yg= -github.com/go-zoox/concurrency v1.2.0/go.mod h1:rghauUPHEDp8HJzaVlU851HWqiAqD8lUVp45K/dtNvw= github.com/go-zoox/config v1.2.10 h1:mebuz6O0N81OXOCwtV+LKOiFuAfZ5wyaGsuzkGSSpf4= github.com/go-zoox/config v1.2.10/go.mod h1:KnSEhz7AVMqQfznJzgpzFhQfgy8UZYeone/osbvnVUE= -github.com/go-zoox/cookie v1.2.0 h1:MO33lPQ/QGJIAEzgrsAfEpJc25lcJ/XR0w+smM19sNQ= -github.com/go-zoox/cookie v1.2.0/go.mod h1:+xEawxty0L+z+4EIvTF2AaHUkUM7oIecGZ9XrEaYqsI= -github.com/go-zoox/core-utils v1.0.4/go.mod h1:EknM3KLL6/kagL95wZbWE7mRRcYCG/fHqiJ/EH0ihAs= -github.com/go-zoox/core-utils v1.0.12/go.mod h1:EknM3KLL6/kagL95wZbWE7mRRcYCG/fHqiJ/EH0ihAs= -github.com/go-zoox/core-utils v1.0.13/go.mod h1:EknM3KLL6/kagL95wZbWE7mRRcYCG/fHqiJ/EH0ihAs= github.com/go-zoox/core-utils v1.2.14 h1:Z6x9QTgfBfhbSOOPEDLqLs9UGBWkXgBpVPlJ4pI68yk= github.com/go-zoox/core-utils v1.2.14/go.mod h1:raOOwr2l2sJQyjR0Dg33sg0ry4U1/L2eNTuLFRpUXWs= -github.com/go-zoox/counter v1.0.1/go.mod h1:PICilZTrnO4dFstDPlXpjc6sdWYBG7hm/XDmjAcHaX0= -github.com/go-zoox/counter v1.2.0 h1:a1sMgYmnOza4UgjDD/fLs+HqTPG2Kh54v2IH41uIi7Q= -github.com/go-zoox/counter v1.2.0/go.mod h1:dCAErDaaxnnqQrfPNkJYklqSQrZ9SKzH3iiciJa3BH4= -github.com/go-zoox/cron v1.1.2 h1:4iEIXIYu8MFRWBZccPaQ7wkpmvBs/N6a0FzWYiup9AU= -github.com/go-zoox/cron v1.1.2/go.mod h1:7aOIpwGDyyg+NqX+041NO+9f8FhAngWiLqBPBN6kZ9k= -github.com/go-zoox/crypto v1.0.3/go.mod h1:HaWRg4tHZamqNyOnNoaK+Rw5eto+su66i8bMMP8UCBU= -github.com/go-zoox/crypto v1.1.8 h1:oI2KPLy+SsGeb+h5A99n9MTQVp4jBhwJWkqjStUzz9I= -github.com/go-zoox/crypto v1.1.8/go.mod h1:JqgNr9HcFFGQkMCGLJ9djtfg/RWVLxtunG01HD3lUXM= -github.com/go-zoox/datetime v1.0.4/go.mod h1:os6lYW/GXNpCIseFrBr8DNcOiPuwl5Ttc/kxo4JnMjw= github.com/go-zoox/datetime v1.2.2 h1:JrI4ekdsvpsenGzrNQAOmobBTYyotaXD3YDXngvCbM4= github.com/go-zoox/datetime v1.2.2/go.mod h1:qvaCrzjhq/g/gstx4sx06Nl4ll2pLSrkRa9ueLjrZ9A= -github.com/go-zoox/debug v1.0.1/go.mod h1:7HvnBeV1dVuuGVnXSLdJ5OE6X/wIXAjIEyiaA7NqQPA= -github.com/go-zoox/debug v1.0.2 h1:nnaSGUC1F3218P3BN6ZhRR5GNKtx5DKZ1RtsvAhIjyA= -github.com/go-zoox/debug v1.0.2/go.mod h1:7HvnBeV1dVuuGVnXSLdJ5OE6X/wIXAjIEyiaA7NqQPA= -github.com/go-zoox/dotenv v1.0.7/go.mod h1:N2bXxghq3Zk+lpiOxv+m+0yjnGubVqJGJDR/9jWm3N0= -github.com/go-zoox/dotenv v1.1.0/go.mod h1:elKALomz436YKX4Syo+f02ozIQYq2yFaprj6jL6GnCQ= github.com/go-zoox/dotenv v1.2.3 h1:9wx4sL2u/FrRLkzoOb7ozYii6NoGsl05KoGdZm1ebIE= github.com/go-zoox/dotenv v1.2.3/go.mod h1:hhl5WZUxI+DNJN6Zos1y7Nq0jDCXciphswPSYtInqg0= -github.com/go-zoox/encoding v1.0.5/go.mod h1:WFF+m/IWYHtClMrcKnrdZHHf3cdIF8de2uTOILPM7lw= -github.com/go-zoox/encoding v1.0.7/go.mod h1:h6ZgI27IaUSBq1ntaZjnSruPdRFuBLNUmfp57TaPxs4= github.com/go-zoox/encoding v1.2.1 h1:38rQRsfL1f1YHZaqsPaGcNMkPnzatnPlYiHioUh9F4A= github.com/go-zoox/encoding v1.2.1/go.mod h1:NdcM7Ln73oVW3vJgx3MH4fJknCcdQfq+NgJ0tuCo7tU= -github.com/go-zoox/errors v1.0.2 h1:1NLMoEVlDU1+qrvvPj+rrJXOvQPdeZ3DekVBFrI5PFY= -github.com/go-zoox/errors v1.0.2/go.mod h1:HJ5NKQb9cu3IbI0Jayw7xZiblLBEIglpaIOMxvQnWnk= -github.com/go-zoox/fetch v1.3.5/go.mod h1:AkS6v/DlotjmUs+7qJsoFGFkpROr9LVtiKYb000v3Kw= -github.com/go-zoox/fetch v1.4.4/go.mod h1:WExVnds3HZ1A6jJu9KuqtICfkJpvUdR4uONUnw9TG+0= -github.com/go-zoox/fetch v1.7.16 h1:3bRoF2bG+M5PnWoFXka64PfHRx35Y60Mu70z2F5USDM= -github.com/go-zoox/fetch v1.7.16/go.mod h1:zaDVj8s8gPFzEeFFsD2oWc5D1z8uKKQwwnilmPdSQOk= -github.com/go-zoox/fs v1.2.4/go.mod h1:aywpClMqf6YO8+QnuwC3p3EvFWe88h0tWH65rpxtY00= -github.com/go-zoox/fs v1.2.5/go.mod h1:aywpClMqf6YO8+QnuwC3p3EvFWe88h0tWH65rpxtY00= github.com/go-zoox/fs v1.3.13 h1:fe0uvtXCM+9s51z/CnQ5kxB4hBYaK55tkrE9gq0385U= github.com/go-zoox/fs v1.3.13/go.mod h1:wCM+UQkjFTxNjOOCNlGcN3k9FeXXUwn9bFnpyjOn55c= -github.com/go-zoox/gzip v1.0.0 h1:11ZTgxAPgexmZ/NJaEEuN2FDCJuvg9sips+XDR+48Yw= -github.com/go-zoox/gzip v1.0.0/go.mod h1:7g9vTpKek1dft1Yi1Ryi4A6dq9snMgq94Qq8wSte8L0= -github.com/go-zoox/headers v1.0.8 h1:HZJisMHhKwdySVNbV4Awc5kaMxFfAwBIHpcWOGch+iw= -github.com/go-zoox/headers v1.0.8/go.mod h1:WEgEbewswEw4n4qS1iG68Kn/vOQVCAKGwwuZankc6so= -github.com/go-zoox/i18n v1.0.3 h1:PqeOKyhI9MxbA9TyWDgm7zcCL5WRSlxhANHWou04VHk= -github.com/go-zoox/i18n v1.0.3/go.mod h1:WURpyaWOrVVN4f3mEQtl5A0kie5bK4ExQJ0PnHSOfTI= github.com/go-zoox/ini v1.0.4 h1:N4mUbAO0juYIRrv3ysjKtpEn/+yQv57eQietsgpkAYQ= github.com/go-zoox/ini v1.0.4/go.mod h1:SisQneNLb1EBeZ5bA5GnrJd8FNg372hQrPh+gb3IzV4= -github.com/go-zoox/jobqueue v1.0.0 h1:pVv/eGI0CLLHUP3rDVyn0ALzsobtaxTOnkWw/JhW9Vg= -github.com/go-zoox/jobqueue v1.0.0/go.mod h1:jUCZxrQcM28orhac67eNLU7SBiVNXehxSelj7j4MM88= -github.com/go-zoox/jsonrpc v1.2.2 h1:asaoJgJkfyH5eblLQ1WzrZDe8ERL6v9GT4pKR/LJ3IE= -github.com/go-zoox/jsonrpc v1.2.2/go.mod h1:HdxJW/T0hkVHlfm+ULRnNEqvTtvZ7o4qxdQGQW76khM= -github.com/go-zoox/jwt v1.0.0/go.mod h1:a6ANQHmSs+b9GJv5aad2cQLl8opFmP3hMOxZtgXRmis= -github.com/go-zoox/jwt v1.3.0 h1:beyPOdiiNrNK8dqFijt5kdtaeh1dZKtM7/kaCMGbV0U= -github.com/go-zoox/jwt v1.3.0/go.mod h1:Cfc+t0XhNCgDjXLR5sK6ao7qz1GSIq896gZ1usNb7t8= -github.com/go-zoox/kv v1.4.1/go.mod h1:dc3whoIvGrYmQA2wi6g6ZE0oOtRg+loxaJEj6bLKlJA= -github.com/go-zoox/kv v1.4.3/go.mod h1:hRCBcPBHilKmeSEsn4o67LBaXurX0+m3Tq9Ec4aIRWk= -github.com/go-zoox/kv v1.5.2 h1:LQI3YiC163NTxGzoM+OdZ2ubimyoc7kHSp40FDBSC6k= -github.com/go-zoox/kv v1.5.2/go.mod h1:u/IbVscKbZk4AyDvvnsK9DiaWshH/Nz3twlGDRyC9pA= -github.com/go-zoox/logger v1.2.0/go.mod h1:mBImRV6zpbGtiIjDz/C9vWi80wWc2OTOl9N9P0SAJgk= github.com/go-zoox/logger v1.4.6 h1:zHUaB6KQ9rD/N3hM0JJ3/JCNdgtedf4mVBBNNSyWCOg= github.com/go-zoox/logger v1.4.6/go.mod h1:o7ddvv/gMoMa0TomPhHoIz11ZWRbQ92pF6rwYbOY3iQ= -github.com/go-zoox/proxy v1.2.3/go.mod h1:T+gbngAtIgvambbYibAbzrjwdu8j5pduJdA2j6RYi94= -github.com/go-zoox/proxy v1.5.3 h1:HoWKuWBLHkFlHsI0tOr0t0IkKTpcDeypSjBv5BNHG4Q= -github.com/go-zoox/proxy v1.5.3/go.mod h1:KLWeJqfQk1upCvEdXt3tEuM8xSu0ApbA9FNLOmyHysY= -github.com/go-zoox/pubsub v1.2.2 h1:dpcFlZRSGhX0YqT/WoOJgP5bP2VDqswPqXiiFZCki1w= -github.com/go-zoox/pubsub v1.2.2/go.mod h1:LWX0NAg80hkeGdZf7PJOEGnyN6CXooCxpIlh2MxESDo= -github.com/go-zoox/random v1.0.0/go.mod h1:W+PTQiInxaCngiXpSvycucAKvu1tE/tKlZ9kaMp2/Ys= -github.com/go-zoox/random v1.0.4 h1:icckpkCowQ0eGiiMkHFOJz9Qc9noOcinP+ggqWUIBH4= -github.com/go-zoox/random v1.0.4/go.mod h1:W+PTQiInxaCngiXpSvycucAKvu1tE/tKlZ9kaMp2/Ys= -github.com/go-zoox/ratelimit v1.0.1/go.mod h1:5MtLMrfQRbZHI+tKC4eyHZorrZX005Sy/Dldnk8qYOU= -github.com/go-zoox/ratelimit v1.2.0 h1:BWytTr0HG5xBZvelEDNIqiXT4yavFH+QwpMgSjLt3+M= -github.com/go-zoox/ratelimit v1.2.0/go.mod h1:gbnJYgl6heLTs3aRM5C8FC9ehSIO3cmEFWzbDe/m8yo= -github.com/go-zoox/safe v1.0.1 h1:JwWK7xCyv7eyzBbwzQvhK/Ajm8gG2Q9Cvd/KXpdF2zI= -github.com/go-zoox/safe v1.0.1/go.mod h1:lT0iEBmpoia7xfh2bWzdurzdv++4QRUAfeEzIhCnpoA= -github.com/go-zoox/session v1.2.0 h1:hzjcZYV3+cVmocnC6MazhtELONMtRlIuEezCYvbxY9Q= -github.com/go-zoox/session v1.2.0/go.mod h1:SLHzCK3DDknqot28deZQFBPz5hm9QHcUeRra8y9GT8E= -github.com/go-zoox/tag v1.0.2/go.mod h1:TNFY+IN6FgsD0KGV6mrnuVXONUq7zpH01k53BcNsT8k= -github.com/go-zoox/tag v1.0.6/go.mod h1:jrbJgC1dZAN5+vZlmrUKu1/UpbOo0xVyCC1MfLpGGqk= -github.com/go-zoox/tag v1.0.9/go.mod h1:jrbJgC1dZAN5+vZlmrUKu1/UpbOo0xVyCC1MfLpGGqk= -github.com/go-zoox/tag v1.1.0/go.mod h1:yMB7bMseqbOshUW9O9Dqfq0C7Mmy9OkccV/meEJHICs= github.com/go-zoox/tag v1.2.3 h1:HDQpRu8rA1xSJt6c+v0O7TfzTjPq5aDtyzW/15aTh94= github.com/go-zoox/tag v1.2.3/go.mod h1:z9z4iZb/XPE4HwTXJgPIdwgH90c2NysGxIMq9tW+GuU= github.com/go-zoox/terminal v1.4.7 h1:UUtvdN95wmfdjiIjAwcwJDJsE4BEHH8mQ1bqD83SAU0= @@ -156,37 +62,13 @@ github.com/go-zoox/testify v1.0.2 h1:G5sQ3xm0uwCuytnMhgnqZ5BItCt2DN3n2wLBqlIJEWA github.com/go-zoox/testify v1.0.2/go.mod h1:L35iVL6xDKDL/TQOTRWyNL4H4nm8bzs6nde5XA7PYnY= github.com/go-zoox/uuid v0.0.1 h1:txqmDavRTq68gzzqWfJQLorFyUp9a7M2lmq2KcwPGPA= github.com/go-zoox/uuid v0.0.1/go.mod h1:0/F4LdfLqFdyqOf7aXoiYXRkXHU324JQ5DZEytXYBPM= -github.com/go-zoox/zoox v1.2.19/go.mod h1:xk3S3L58ugJIDyuZMCYrj3qIGLSxddbkARwTRkpxPVE= -github.com/go-zoox/zoox v1.12.8 h1:6Mo507JhfAzfVC7huS/2kr6EAP4PjhflgY8gUjtMrXg= -github.com/go-zoox/zoox v1.12.8/go.mod h1:W31vOF9Wo37KjJNFcD/4An0NU9lXH15vgaV7IDDp2r4= -github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54= github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= @@ -201,43 +83,19 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -245,10 +103,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= -github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -256,29 +110,13 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sevlyar/go-daemon v0.1.6 h1:EUh1MDjEM4BI109Jign0EaknA2izkOyi0LV3ro3QQGs= github.com/sevlyar/go-daemon v0.1.6/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= -github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= @@ -291,77 +129,45 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= @@ -369,34 +175,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/terminal.go b/terminal.go new file mode 100644 index 0000000..6199a5b --- /dev/null +++ b/terminal.go @@ -0,0 +1,7 @@ +package command + +import "github.com/go-zoox/command/terminal" + +func (c *command) Terminal() (terminal.Terminal, error) { + return c.engine.Terminal() +} diff --git a/terminal/terminal.go b/terminal/terminal.go new file mode 100644 index 0000000..3cd2e15 --- /dev/null +++ b/terminal/terminal.go @@ -0,0 +1,15 @@ +package terminal + +import "io" + +type Terminal interface { + io.ReadWriteCloser + + // + Resize(rows, cols int) error + // + Wait() error + + // + ExitCode() int +} From e46c9cc35b45ce3d1d089678543273d6c583d856 Mon Sep 17 00:00:00 2001 From: Zero Date: Sat, 7 Oct 2023 21:26:10 +0800 Subject: [PATCH 03/14] feat: support terminal --- cmd/cmd/commands/exec.go | 15 +++++---------- engine/host/create.go | 6 +++--- engine/host/terminal.go | 4 ---- terminal/terminal.go | 2 -- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/cmd/cmd/commands/exec.go b/cmd/cmd/commands/exec.go index 58c8e16..de59327 100644 --- a/cmd/cmd/commands/exec.go +++ b/cmd/cmd/commands/exec.go @@ -65,16 +65,11 @@ func Exec(app *cli.MultipleProgram) { defer term.Close() go func() { - buf := make([]byte, 1024) - for { - n, err := term.Read(buf) - if err != nil && err != io.EOF { - os.Stderr.Write([]byte(err.Error())) - os.Exit(term.ExitCode()) - return - } - - os.Stdout.Write(buf[:n]) + _, err := io.Copy(os.Stdout, term) + if err != nil && err != io.EOF { + os.Stderr.Write([]byte(err.Error())) + os.Exit(term.ExitCode()) + return } }() diff --git a/engine/host/create.go b/engine/host/create.go index 7c59ceb..301fd80 100644 --- a/engine/host/create.go +++ b/engine/host/create.go @@ -34,9 +34,9 @@ func (h *host) create() error { return err } - // if err := applyUser(h.cmd, h.cfg.User); err != nil { - // return err - // } + if err := applyUser(h.cmd, h.cfg.User); err != nil { + return err + } if err := applyHistory(h.cmd, h.cfg.IsHistoryDisabled); err != nil { return err diff --git a/engine/host/terminal.go b/engine/host/terminal.go index 633d61a..747359b 100644 --- a/engine/host/terminal.go +++ b/engine/host/terminal.go @@ -32,10 +32,6 @@ func (rt *Terminal) Resize(rows, cols int) error { }) } -func (rt *Terminal) Wait() error { - return rt.Cmd.Wait() -} - func (rt *Terminal) ExitCode() int { return rt.Cmd.ProcessState.ExitCode() } diff --git a/terminal/terminal.go b/terminal/terminal.go index 3cd2e15..f023548 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -7,8 +7,6 @@ type Terminal interface { // Resize(rows, cols int) error - // - Wait() error // ExitCode() int From 612aaeea8b49e401f83ea5bc19f612942ed0d40f Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 00:23:25 +0800 Subject: [PATCH 04/14] feat: add engine docker --- cmd/cmd/commands/exec.go | 39 +++++++++++++---- command.go | 21 ++++++++- engine/docker/cancel.go | 11 +++++ engine/docker/config.go | 9 ++-- engine/docker/connect.go | 90 --------------------------------------- engine/docker/create.go | 47 ++++++++++++++++++++ engine/docker/docker.go | 41 +++++++++++++++--- engine/docker/io.go | 18 ++++++++ engine/docker/start.go | 60 ++++++++++++++++++++++++++ engine/docker/terminal.go | 87 +++++++++++++++++++++++++++++++++++++ engine/docker/utils.go | 89 -------------------------------------- engine/docker/wait.go | 24 +++++++++++ engine/host/create.go | 20 --------- engine/host/host.go | 10 ++++- engine/host/start.go | 24 +++++++++++ go.mod | 5 ++- go.sum | 7 ++- 17 files changed, 374 insertions(+), 228 deletions(-) create mode 100644 engine/docker/cancel.go delete mode 100644 engine/docker/connect.go create mode 100644 engine/docker/create.go create mode 100644 engine/docker/io.go create mode 100644 engine/docker/start.go create mode 100644 engine/docker/terminal.go delete mode 100644 engine/docker/utils.go create mode 100644 engine/docker/wait.go diff --git a/cmd/cmd/commands/exec.go b/cmd/cmd/commands/exec.go index de59327..b637d69 100644 --- a/cmd/cmd/commands/exec.go +++ b/cmd/cmd/commands/exec.go @@ -1,6 +1,7 @@ package commands import ( + "context" "fmt" "io" "os" @@ -34,11 +35,29 @@ func Exec(app *cli.MultipleProgram) { Aliases: []string{"c"}, EnvVars: []string{"COMMAND"}, }, + &cli.StringFlag{ + Name: "workdir", + Usage: "the command workdir", + Aliases: []string{"w"}, + EnvVars: []string{"WORKDIR"}, + }, + &cli.StringFlag{ + Name: "user", + Usage: "the command user", + Aliases: []string{"u"}, + // EnvVars: []string{"WORKDIR"}, + }, &cli.StringFlag{ Name: "shell", Usage: "the command shell", Aliases: []string{"s"}, - EnvVars: []string{"SHELL"}, + // EnvVars: []string{"SHELL"}, + }, + &cli.StringFlag{ + Name: "image", + Usage: "docker image", + Aliases: []string{"i"}, + EnvVars: []string{"IMAGE"}, }, &cli.BoolFlag{ Name: "tty", @@ -48,10 +67,13 @@ func Exec(app *cli.MultipleProgram) { }, }, Action: func(ctx *cli.Context) (err error) { - cmd, err := command.New(&command.Config{ + cmd, err := command.New(context.Background(), &command.Config{ Engine: ctx.String("engine"), Command: ctx.String("command"), + WorkDir: ctx.String("workdir"), + User: ctx.String("user"), Shell: ctx.String("shell"), + Image: ctx.String("image"), }) if err != nil { return err @@ -65,12 +87,13 @@ func Exec(app *cli.MultipleProgram) { defer term.Close() go func() { - _, err := io.Copy(os.Stdout, term) - if err != nil && err != io.EOF { - os.Stderr.Write([]byte(err.Error())) - os.Exit(term.ExitCode()) - return - } + io.Copy(os.Stdout, term) + // _, err := io.Copy(os.Stdout, term) + // if err != nil && err != io.EOF { + // os.Stderr.Write([]byte(err.Error())) + // os.Exit(term.ExitCode()) + // return + // } }() if err := connectKeyboard(term); err != nil { diff --git a/command.go b/command.go index f66ec2b..a352f29 100644 --- a/command.go +++ b/command.go @@ -1,9 +1,11 @@ package command import ( + "context" "fmt" "github.com/go-zoox/command/engine" + "github.com/go-zoox/command/engine/docker" "github.com/go-zoox/command/engine/host" "github.com/go-zoox/command/terminal" ) @@ -25,9 +27,12 @@ type Config struct { Environment map[string]string User string Shell string + + // engine = docker + Image string } -func New(cfg *Config) (cmd Command, err error) { +func New(ctx context.Context, cfg *Config) (cmd Command, err error) { if cfg.Engine == "" { cfg.Engine = host.Engine } @@ -39,12 +44,24 @@ func New(cfg *Config) (cmd Command, err error) { var engine engine.Engine switch cfg.Engine { case host.Engine: - engine, err = host.New(&host.Config{ + engine, err = host.New(ctx, &host.Config{ + Command: cfg.Command, + WorkDir: cfg.WorkDir, + Environment: cfg.Environment, + User: cfg.User, + Shell: cfg.Shell, + }) + if err != nil { + return nil, err + } + case docker.Engine: + engine, err = docker.New(ctx, &docker.Config{ Command: cfg.Command, WorkDir: cfg.WorkDir, Environment: cfg.Environment, User: cfg.User, Shell: cfg.Shell, + Image: cfg.Image, }) if err != nil { return nil, err diff --git a/engine/docker/cancel.go b/engine/docker/cancel.go new file mode 100644 index 0000000..b76cd30 --- /dev/null +++ b/engine/docker/cancel.go @@ -0,0 +1,11 @@ +package docker + +import ( + "github.com/docker/docker/api/types" +) + +func (d *docker) Cancel() error { + return d.client.ContainerRemove(d.ctx, d.container.ID, types.ContainerRemoveOptions{ + Force: true, + }) +} diff --git a/engine/docker/config.go b/engine/docker/config.go index fad3765..4164d4c 100644 --- a/engine/docker/config.go +++ b/engine/docker/config.go @@ -1,14 +1,11 @@ package docker type Config struct { - Shell string + Command string Environment map[string]string WorkDir string - - // - User string + User string + Shell string Image string - - InitCommand string } diff --git a/engine/docker/connect.go b/engine/docker/connect.go deleted file mode 100644 index 6c91434..0000000 --- a/engine/docker/connect.go +++ /dev/null @@ -1,90 +0,0 @@ -package docker - -import ( - "context" - "fmt" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - dockerClient "github.com/docker/docker/client" - "github.com/go-zoox/terminal/server/session" - "github.com/go-zoox/uuid" -) - -func (d *docker) Connect(ctx context.Context) (session session.Session, err error) { - args := []string{} - if d.cfg.InitCommand != "" { - args = append(args, "-c", d.cfg.InitCommand) - } - - env := []string{} - for k, v := range d.cfg.Environment { - env = append(env, fmt.Sprintf("%s=%s", k, v)) - } - - c, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv) - if err != nil { - return nil, err - } - - cfg := &container.Config{ - Image: d.cfg.Image, - Cmd: append([]string{d.cfg.Shell}, args...), - User: d.cfg.User, - Tty: true, - OpenStdin: true, - AttachStdin: true, - AttachStdout: true, - AttachStderr: true, - StdinOnce: true, - WorkingDir: d.cfg.WorkDir, - Env: env, - } - - hostCfg := &container.HostConfig{} - - res, err := c.ContainerCreate(ctx, cfg, hostCfg, nil, nil, uuid.V4()) - if err != nil { - return nil, err - } - containerID := res.ID - - stream, err := c.ContainerAttach(ctx, containerID, types.ContainerAttachOptions{ - Stream: true, - Stdin: true, - Stdout: true, - Stderr: true, - // Logs: true, - }) - if err != nil { - return nil, err - } - - rct := &ResizableContainerTerminal{ - Ctx: ctx, - Client: c, - ContainerID: containerID, - ReadCh: make(chan []byte), - Stream: &stream, - } - session = rct - - go func() { - for { - buf := make([]byte, 1024) - n, err := stream.Conn.Read(buf) - if err != nil { - return - } - - rct.ReadCh <- buf[:n] - } - }() - - err = c.ContainerStart(ctx, containerID, types.ContainerStartOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to start container: %v", err) - } - - return -} diff --git a/engine/docker/create.go b/engine/docker/create.go new file mode 100644 index 0000000..faf6017 --- /dev/null +++ b/engine/docker/create.go @@ -0,0 +1,47 @@ +package docker + +import ( + "fmt" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/client" + "github.com/go-zoox/uuid" +) + +func (d *docker) create() (err error) { + if d.cfg.Command != "" { + d.args = append(d.args, "-c", d.cfg.Command) + } + + for k, v := range d.cfg.Environment { + d.env = append(d.env, fmt.Sprintf("%s=%s", k, v)) + } + + d.client, err = client.NewClientWithOpts(client.FromEnv) + if err != nil { + return err + } + + cfg := &container.Config{ + Image: d.cfg.Image, + Cmd: append([]string{d.cfg.Shell}, d.args...), + User: d.cfg.User, + WorkingDir: d.cfg.WorkDir, + Env: d.env, + Tty: true, + OpenStdin: true, + AttachStdin: true, + AttachStdout: true, + AttachStderr: true, + StdinOnce: true, + } + + hostCfg := &container.HostConfig{} + + d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, nil, nil, uuid.V4()) + if err != nil { + return err + } + + return nil +} diff --git a/engine/docker/docker.go b/engine/docker/docker.go index 74fa8ee..ca58f9c 100644 --- a/engine/docker/docker.go +++ b/engine/docker/docker.go @@ -1,18 +1,36 @@ package docker import ( - "github.com/go-zoox/terminal/server/driver" + "context" + "io" + "os" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/client" + "github.com/go-zoox/command/engine" ) -type Docker interface { - driver.Driver -} +const Engine = "docker" type docker struct { cfg *Config + // + args []string + env []string + // + ctx context.Context + // + client *client.Client + // + container container.CreateResponse + + // + stdin io.Reader + stdout io.Writer + stderr io.Writer } -func New(cfg *Config) Docker { +func New(ctx context.Context, cfg *Config) (engine.Engine, error) { if cfg.Image == "" { cfg.Image = "whatwewant/zmicro:v1" } @@ -21,7 +39,18 @@ func New(cfg *Config) Docker { cfg.Shell = "/bin/sh" } - return &docker{ + d := &docker{ + ctx: ctx, cfg: cfg, + // + stdin: os.Stdin, + stdout: os.Stdout, + stderr: os.Stderr, } + + if err := d.create(); err != nil { + return nil, err + } + + return d, nil } diff --git a/engine/docker/io.go b/engine/docker/io.go new file mode 100644 index 0000000..998b677 --- /dev/null +++ b/engine/docker/io.go @@ -0,0 +1,18 @@ +package docker + +import "io" + +func (d *docker) SetStdin(stdin io.Reader) error { + d.stdin = stdin + return nil +} + +func (d *docker) SetStdout(stdout io.Writer) error { + d.stdout = stdout + return nil +} + +func (d *docker) SetStderr(stderr io.Writer) error { + d.stderr = stderr + return nil +} diff --git a/engine/docker/start.go b/engine/docker/start.go new file mode 100644 index 0000000..c2adf39 --- /dev/null +++ b/engine/docker/start.go @@ -0,0 +1,60 @@ +package docker + +import ( + "io" + "net" + + "github.com/docker/docker/api/types" +) + +func (d *docker) Start() error { + stream, err := d.client.ContainerAttach(d.ctx, d.container.ID, types.ContainerAttachOptions{ + Stream: true, + Stdin: true, + Stdout: true, + Stderr: true, + // Logs: true, + }) + if err != nil { + return err + } + + if err := applyStdin(stream.Conn, d.stdin); err != nil { + return nil + } + + if err := applyStdout(stream.Conn, d.stdout); err != nil { + return nil + } + + if err := applyStderr(stream.Conn, d.stderr); err != nil { + return nil + } + + err = d.client.ContainerStart(d.ctx, d.container.ID, types.ContainerStartOptions{}) + if err != nil { + return err + } + + return nil +} + +func applyStdin(conn net.Conn, stdin io.Reader) error { + if stdin != nil { + go io.Copy(conn, stdin) + } + + return nil +} + +func applyStdout(conn net.Conn, stdout io.Writer) error { + if stdout != nil { + go io.Copy(stdout, conn) + } + + return nil +} + +func applyStderr(conn net.Conn, stderr io.Writer) error { + return nil +} diff --git a/engine/docker/terminal.go b/engine/docker/terminal.go new file mode 100644 index 0000000..da04e65 --- /dev/null +++ b/engine/docker/terminal.go @@ -0,0 +1,87 @@ +package docker + +import ( + "context" + "net" + + "github.com/docker/docker/api/types" + dockerClient "github.com/docker/docker/client" + "github.com/go-zoox/command/terminal" +) + +func (d *docker) Terminal() (terminal.Terminal, error) { + stream, err := d.client.ContainerAttach(d.ctx, d.container.ID, types.ContainerAttachOptions{ + Stream: true, + Stdin: true, + Stdout: true, + Stderr: true, + // Logs: true, + }) + if err != nil { + return nil, err + } + + t := &Terminal{ + Ctx: d.ctx, + Client: d.client, + ContainerID: d.container.ID, + Conn: stream.Conn, + } + + err = d.client.ContainerStart(d.ctx, d.container.ID, types.ContainerStartOptions{}) + if err != nil { + return nil, err + } + + return t, nil +} + +type Terminal struct { + Ctx context.Context + Conn net.Conn + // + Client *dockerClient.Client + ContainerID string +} + +func (t *Terminal) Close() error { + t.Conn.Close() + + return t.Client.ContainerRemove(t.Ctx, t.ContainerID, types.ContainerRemoveOptions{ + Force: true, + }) +} + +func (t *Terminal) Read(p []byte) (n int, err error) { + return t.Conn.Read(p) +} + +func (t *Terminal) Write(p []byte) (n int, err error) { + return t.Conn.Write(p) +} + +func (t *Terminal) Resize(rows, cols int) error { + inspect, err := t.Client.ContainerInspect(t.Ctx, t.ContainerID) + if err != nil { + return err + } + + if inspect.State.Status != "running" { + // return fmt.Errorf("container is not running") + return nil + } + + return t.Client.ContainerResize(t.Ctx, t.ContainerID, types.ResizeOptions{ + Height: uint(rows), + Width: uint(cols), + }) +} + +func (t *Terminal) ExitCode() int { + inspect, err := t.Client.ContainerInspect(t.Ctx, t.ContainerID) + if err != nil { + return -1 + } + + return inspect.State.ExitCode +} diff --git a/engine/docker/utils.go b/engine/docker/utils.go deleted file mode 100644 index 9841d41..0000000 --- a/engine/docker/utils.go +++ /dev/null @@ -1,89 +0,0 @@ -package docker - -import ( - "context" - "fmt" - "io" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - dockerClient "github.com/docker/docker/client" - "github.com/go-zoox/logger" -) - -type ResizableContainerTerminal struct { - Ctx context.Context - Client *dockerClient.Client - ContainerID string - ReadCh chan []byte - Stream *types.HijackedResponse - // - exitCode int -} - -func (rct *ResizableContainerTerminal) Close() error { - // if err := rct.Stream.CloseWrite(); err != nil { - // return err - // } - - rct.Stream.Close() - - return rct.Client.ContainerRemove(rct.Ctx, rct.ContainerID, types.ContainerRemoveOptions{ - Force: true, - }) -} - -func (rct *ResizableContainerTerminal) Read(p []byte) (n int, err error) { - return copy(p, <-rct.ReadCh), nil -} - -func (rct *ResizableContainerTerminal) Write(p []byte) (n int, err error) { - n, err = rct.Stream.Conn.Write(p) - if err != nil { - logger.Errorf("Failed to write to pty master: %s", err) - return 0, err - } - - return -} - -func (rct *ResizableContainerTerminal) Resize(rows, cols int) error { - inspect, err := rct.Client.ContainerInspect(rct.Ctx, rct.ContainerID) - if err != nil { - return err - } - - if inspect.State.Status != "running" { - // return fmt.Errorf("container is not running") - return nil - } - - return rct.Client.ContainerResize(rct.Ctx, rct.ContainerID, types.ResizeOptions{ - Height: uint(rows), - Width: uint(cols), - }) -} - -func (rct *ResizableContainerTerminal) Wait() error { - resultC, errC := rct.Client.ContainerWait(rct.Ctx, rct.ContainerID, container.WaitConditionNotRunning) - select { - case err := <-errC: - if err != nil && err != io.EOF { - return fmt.Errorf("container exit error: %#v", err) - } - - logger.Infof("container exited") - - case result := <-resultC: - if result.StatusCode != 0 { - rct.exitCode = int(result.StatusCode) - return fmt.Errorf("container exited with non-zero status: %d", result.StatusCode) - } - } - - return nil -} - -func (rct *ResizableContainerTerminal) ExitCode() int { - return rct.exitCode -} diff --git a/engine/docker/wait.go b/engine/docker/wait.go new file mode 100644 index 0000000..04096ce --- /dev/null +++ b/engine/docker/wait.go @@ -0,0 +1,24 @@ +package docker + +import ( + "fmt" + "io" + + "github.com/docker/docker/api/types/container" +) + +func (d *docker) Wait() error { + result, err := d.client.ContainerWait(d.ctx, d.container.ID, container.WaitConditionNotRunning) + select { + case err := <-err: + if err != nil && err != io.EOF { + return fmt.Errorf("container exit error: %#v", err) + } + case result := <-result: + if result.StatusCode != 0 { + return fmt.Errorf("container exited with non-zero status: %d", result.StatusCode) + } + } + + return nil +} diff --git a/engine/host/create.go b/engine/host/create.go index 301fd80..938a864 100644 --- a/engine/host/create.go +++ b/engine/host/create.go @@ -3,7 +3,6 @@ package host import ( "errors" "fmt" - "io" "os" "os/exec" "os/user" @@ -100,22 +99,3 @@ func applyHistory(cmd *exec.Cmd, disable bool) error { return nil } - -func applyStdin(cmd *exec.Cmd, stdin io.Reader) error { - cmd.Stdin = stdin - return nil -} - -func applyStdout(cmd *exec.Cmd, stdout io.Writer) error { - cmd.Stdout = stdout - if cmd.Stderr == nil { - return applyStderr(cmd, stdout) - } - - return nil -} - -func applyStderr(cmd *exec.Cmd, stderr io.Writer) error { - cmd.Stderr = stderr - return nil -} diff --git a/engine/host/host.go b/engine/host/host.go index 115f4c7..acb768a 100644 --- a/engine/host/host.go +++ b/engine/host/host.go @@ -1,6 +1,7 @@ package host import ( + "context" "io" "os" "os/exec" @@ -11,6 +12,8 @@ import ( const Engine = "host" type host struct { + ctx context.Context + // cfg *Config // cmd *exec.Cmd @@ -22,8 +25,13 @@ type host struct { stderr io.Writer } -func New(cfg *Config) (engine.Engine, error) { +func New(ctx context.Context, cfg *Config) (engine.Engine, error) { + if cfg.Shell == "" { + cfg.Shell = "/bin/sh" + } + h := &host{ + ctx: ctx, cfg: cfg, // stdin: os.Stdin, diff --git a/engine/host/start.go b/engine/host/start.go index 4ae2097..cc94544 100644 --- a/engine/host/start.go +++ b/engine/host/start.go @@ -1,5 +1,10 @@ package host +import ( + "io" + "os/exec" +) + func (h *host) Start() error { if err := applyStdin(h.cmd, h.stdin); err != nil { return nil @@ -15,3 +20,22 @@ func (h *host) Start() error { return h.cmd.Start() } + +func applyStdin(cmd *exec.Cmd, stdin io.Reader) error { + cmd.Stdin = stdin + return nil +} + +func applyStdout(cmd *exec.Cmd, stdout io.Writer) error { + cmd.Stdout = stdout + if cmd.Stderr == nil { + return applyStderr(cmd, stdout) + } + + return nil +} + +func applyStderr(cmd *exec.Cmd, stderr io.Writer) error { + cmd.Stderr = stderr + return nil +} diff --git a/go.mod b/go.mod index 2a76a55..74d9373 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 github.com/go-zoox/cli v1.3.6 github.com/go-zoox/logger v1.4.6 - github.com/go-zoox/terminal v1.4.7 github.com/go-zoox/testify v1.0.2 github.com/go-zoox/uuid v0.0.1 github.com/spf13/cast v1.5.1 @@ -16,7 +15,6 @@ require ( ) require ( - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/distribution/reference v0.5.0 // indirect @@ -42,6 +40,8 @@ require ( github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -55,6 +55,7 @@ require ( golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.15.0 // indirect golang.org/x/sys v0.12.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gotest.tools/v3 v3.5.1 // indirect diff --git a/go.sum b/go.sum index a5ffeb3..df6dc56 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= @@ -56,8 +55,6 @@ github.com/go-zoox/logger v1.4.6 h1:zHUaB6KQ9rD/N3hM0JJ3/JCNdgtedf4mVBBNNSyWCOg= github.com/go-zoox/logger v1.4.6/go.mod h1:o7ddvv/gMoMa0TomPhHoIz11ZWRbQ92pF6rwYbOY3iQ= github.com/go-zoox/tag v1.2.3 h1:HDQpRu8rA1xSJt6c+v0O7TfzTjPq5aDtyzW/15aTh94= github.com/go-zoox/tag v1.2.3/go.mod h1:z9z4iZb/XPE4HwTXJgPIdwgH90c2NysGxIMq9tW+GuU= -github.com/go-zoox/terminal v1.4.7 h1:UUtvdN95wmfdjiIjAwcwJDJsE4BEHH8mQ1bqD83SAU0= -github.com/go-zoox/terminal v1.4.7/go.mod h1:VEk5VxyHAtkMzV4Qg9iFowUcZuYyO6ECcNLh67jMq58= github.com/go-zoox/testify v1.0.2 h1:G5sQ3xm0uwCuytnMhgnqZ5BItCt2DN3n2wLBqlIJEWA= github.com/go-zoox/testify v1.0.2/go.mod h1:L35iVL6xDKDL/TQOTRWyNL4H4nm8bzs6nde5XA7PYnY= github.com/go-zoox/uuid v0.0.1 h1:txqmDavRTq68gzzqWfJQLorFyUp9a7M2lmq2KcwPGPA= @@ -91,7 +88,9 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= @@ -150,7 +149,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -165,6 +163,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= From 26169e5851b83e155d006a9d72c99bab382ba8ff Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 18:05:19 +0800 Subject: [PATCH 05/14] fix: add terminal.Wait for run online command --- engine/docker/terminal.go | 21 +++++++++++++++++++++ engine/host/terminal.go | 16 ++++++++++++++++ terminal/terminal.go | 3 +++ 3 files changed, 40 insertions(+) diff --git a/engine/docker/terminal.go b/engine/docker/terminal.go index da04e65..5634658 100644 --- a/engine/docker/terminal.go +++ b/engine/docker/terminal.go @@ -2,9 +2,12 @@ package docker import ( "context" + "fmt" + "io" "net" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" dockerClient "github.com/docker/docker/client" "github.com/go-zoox/command/terminal" ) @@ -85,3 +88,21 @@ func (t *Terminal) ExitCode() int { return inspect.State.ExitCode } + +func (rt *Terminal) Wait() error { + resultC, errC := rt.Client.ContainerWait(rt.Ctx, rt.ContainerID, container.WaitConditionNotRunning) + select { + case err := <-errC: + if err != nil && err != io.EOF { + return fmt.Errorf("container exit error: %#v", err) + } + + case result := <-resultC: + if result.StatusCode != 0 { + // rt.exitCode = int(result.StatusCode) + return fmt.Errorf("container exited with non-zero status: %d", result.StatusCode) + } + } + + return nil +} diff --git a/engine/host/terminal.go b/engine/host/terminal.go index 747359b..9bbe811 100644 --- a/engine/host/terminal.go +++ b/engine/host/terminal.go @@ -25,6 +25,18 @@ type Terminal struct { Cmd *exec.Cmd } +func (t *Terminal) Close() error { + return t.File.Close() +} + +func (t *Terminal) Read(p []byte) (n int, err error) { + return t.File.Read(p) +} + +func (t *Terminal) Write(p []byte) (n int, err error) { + return t.File.Write(p) +} + func (rt *Terminal) Resize(rows, cols int) error { return pty.Setsize(rt.File, &pty.Winsize{ Rows: uint16(rows), @@ -35,3 +47,7 @@ func (rt *Terminal) Resize(rows, cols int) error { func (rt *Terminal) ExitCode() int { return rt.Cmd.ProcessState.ExitCode() } + +func (rt *Terminal) Wait() error { + return rt.Cmd.Wait() +} diff --git a/terminal/terminal.go b/terminal/terminal.go index f023548..472f6a6 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -10,4 +10,7 @@ type Terminal interface { // ExitCode() int + + // + Wait() error } From 06a63eb11f086e59c4d435efa393cff81f4aaa3a Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 19:34:13 +0800 Subject: [PATCH 06/14] fix: ci --- .github/workflows/ci.yml | 8 +++++--- .github/workflows/release.yml | 28 ++++++++++++++++++++++++++++ .goreleaser.yaml | 23 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .goreleaser.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 536df1f..dc54f11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,9 +21,9 @@ jobs: redis-version: 6 - name: Set up Go - uses: actions/setup-go@v2 + uses: zmicro-design/action-setup-go@v1 with: - go-version: 1.18 + go-version: v1.20 - name: install deps run: | @@ -31,12 +31,14 @@ jobs: go install golang.org/x/tools/cmd/goimports@latest go install golang.org/x/lint/golint@latest go install github.com/mattn/goveralls@latest + - name: static analysis run: | golint -set_exit_status go vet test -z "$(goimports -l .)" + - name: Test run: goveralls -service=github env: - COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ef60782 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: release + +on: + push: + tags: + - 'v*' + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Go + uses: zmicro-design/action-setup-go@v1 + with: + go-version: v1.20 + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v4 + with: + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..368f2a0 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,23 @@ +env: + - GO111MODULE=on + +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + # - windows + goarch: + - amd64 + - arm64 + # - arm + # - "386" + goarm: + - "7" + mod_timestamp: "{{ .CommitTimestamp }}" + flags: + - -trimpath + ldflags: + - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X main.builtBy=go-zoox + main: ./cmd/command-runner From 154e8d2b7fc3ad7f70240b727f43a73b4aabfe04 Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 19:34:25 +0800 Subject: [PATCH 07/14] chore: rename cmd --- cmd/{cmd => command-runner}/commands/exec.go | 0 cmd/{cmd => command-runner}/main.go | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename cmd/{cmd => command-runner}/commands/exec.go (100%) rename cmd/{cmd => command-runner}/main.go (74%) diff --git a/cmd/cmd/commands/exec.go b/cmd/command-runner/commands/exec.go similarity index 100% rename from cmd/cmd/commands/exec.go rename to cmd/command-runner/commands/exec.go diff --git a/cmd/cmd/main.go b/cmd/command-runner/main.go similarity index 74% rename from cmd/cmd/main.go rename to cmd/command-runner/main.go index 7006ece..7d1ad3b 100644 --- a/cmd/cmd/main.go +++ b/cmd/command-runner/main.go @@ -3,12 +3,12 @@ package main import ( "github.com/go-zoox/cli" "github.com/go-zoox/command" - "github.com/go-zoox/command/cmd/cmd/commands" + "github.com/go-zoox/command/cmd/command-runner/commands" ) func main() { app := cli.NewMultipleProgram(&cli.MultipleProgramConfig{ - Name: "cmd", + Name: "command-runner", Usage: "Powerful command runner", Version: command.Version, }) From 7065ede928229da74a3c0b4888e6ced1b90d3eb7 Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 19:46:15 +0800 Subject: [PATCH 08/14] doc: add comment and fix lint --- cancel.go | 1 + cmd/command-runner/commands/exec.go | 1 + command.go | 9 ++++++--- engine/docker/cancel.go | 1 + engine/docker/config.go | 1 + engine/docker/create.go | 1 + engine/docker/docker.go | 4 +++- engine/docker/io.go | 3 +++ engine/docker/start.go | 1 + engine/docker/terminal.go | 12 ++++++++++-- engine/docker/wait.go | 1 + engine/engine.go | 8 +------- engine/host/cancel.go | 1 + engine/host/config.go | 1 + engine/host/create.go | 1 + engine/host/host.go | 4 +++- engine/host/io.go | 3 +++ engine/host/start.go | 1 + engine/host/terminal.go | 20 ++++++++++++++------ engine/host/wait.go | 1 + io.go | 3 +++ run.go | 1 + start.go | 1 + terminal.go | 1 + terminal/terminal.go | 1 + wait.go | 1 + 26 files changed, 63 insertions(+), 20 deletions(-) diff --git a/cancel.go b/cancel.go index 87cf2d3..f1b166d 100644 --- a/cancel.go +++ b/cancel.go @@ -1,5 +1,6 @@ package command +// Cancel cancels the command. func (c *command) Cancel() error { return c.engine.Cancel() } diff --git a/cmd/command-runner/commands/exec.go b/cmd/command-runner/commands/exec.go index b637d69..efe76fe 100644 --- a/cmd/command-runner/commands/exec.go +++ b/cmd/command-runner/commands/exec.go @@ -17,6 +17,7 @@ import ( "golang.org/x/term" ) +// Exec is the exec command func Exec(app *cli.MultipleProgram) { app.Register("exec", &cli.Command{ Name: "exec", diff --git a/command.go b/command.go index a352f29..1aa5f11 100644 --- a/command.go +++ b/command.go @@ -10,6 +10,7 @@ import ( "github.com/go-zoox/command/terminal" ) +// Command is the command runner interface type Command interface { Start() error Wait() error @@ -20,6 +21,7 @@ type Command interface { Terminal() (terminal.Terminal, error) } +// Config is the command config type Config struct { Engine string Command string @@ -32,9 +34,10 @@ type Config struct { Image string } +// New creates a new command runner. func New(ctx context.Context, cfg *Config) (cmd Command, err error) { if cfg.Engine == "" { - cfg.Engine = host.Engine + cfg.Engine = host.Name } if cfg.Shell == "" { @@ -43,7 +46,7 @@ func New(ctx context.Context, cfg *Config) (cmd Command, err error) { var engine engine.Engine switch cfg.Engine { - case host.Engine: + case host.Name: engine, err = host.New(ctx, &host.Config{ Command: cfg.Command, WorkDir: cfg.WorkDir, @@ -54,7 +57,7 @@ func New(ctx context.Context, cfg *Config) (cmd Command, err error) { if err != nil { return nil, err } - case docker.Engine: + case docker.Name: engine, err = docker.New(ctx, &docker.Config{ Command: cfg.Command, WorkDir: cfg.WorkDir, diff --git a/engine/docker/cancel.go b/engine/docker/cancel.go index b76cd30..8a264f3 100644 --- a/engine/docker/cancel.go +++ b/engine/docker/cancel.go @@ -4,6 +4,7 @@ import ( "github.com/docker/docker/api/types" ) +// Cancel cancels the command. func (d *docker) Cancel() error { return d.client.ContainerRemove(d.ctx, d.container.ID, types.ContainerRemoveOptions{ Force: true, diff --git a/engine/docker/config.go b/engine/docker/config.go index 4164d4c..24aa9bf 100644 --- a/engine/docker/config.go +++ b/engine/docker/config.go @@ -1,5 +1,6 @@ package docker +// Config is the configuration for a Docker engine. type Config struct { Command string Environment map[string]string diff --git a/engine/docker/create.go b/engine/docker/create.go index faf6017..4771b73 100644 --- a/engine/docker/create.go +++ b/engine/docker/create.go @@ -8,6 +8,7 @@ import ( "github.com/go-zoox/uuid" ) +// create creates a container. func (d *docker) create() (err error) { if d.cfg.Command != "" { d.args = append(d.args, "-c", d.cfg.Command) diff --git a/engine/docker/docker.go b/engine/docker/docker.go index ca58f9c..29e9504 100644 --- a/engine/docker/docker.go +++ b/engine/docker/docker.go @@ -10,7 +10,8 @@ import ( "github.com/go-zoox/command/engine" ) -const Engine = "docker" +// Name is the name of the engine. +const Name = "docker" type docker struct { cfg *Config @@ -30,6 +31,7 @@ type docker struct { stderr io.Writer } +// New creates a new docker engine. func New(ctx context.Context, cfg *Config) (engine.Engine, error) { if cfg.Image == "" { cfg.Image = "whatwewant/zmicro:v1" diff --git a/engine/docker/io.go b/engine/docker/io.go index 998b677..cd94e4d 100644 --- a/engine/docker/io.go +++ b/engine/docker/io.go @@ -2,16 +2,19 @@ package docker import "io" +// SetStdin sets the stdin for the Docker engine. func (d *docker) SetStdin(stdin io.Reader) error { d.stdin = stdin return nil } +// SetStdout sets the stdout for the Docker engine. func (d *docker) SetStdout(stdout io.Writer) error { d.stdout = stdout return nil } +// SetStderr sets the stderr for the Docker engine. func (d *docker) SetStderr(stderr io.Writer) error { d.stderr = stderr return nil diff --git a/engine/docker/start.go b/engine/docker/start.go index c2adf39..0e2aec9 100644 --- a/engine/docker/start.go +++ b/engine/docker/start.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/api/types" ) +// Start starts the command. func (d *docker) Start() error { stream, err := d.client.ContainerAttach(d.ctx, d.container.ID, types.ContainerAttachOptions{ Stream: true, diff --git a/engine/docker/terminal.go b/engine/docker/terminal.go index 5634658..d1e8bb2 100644 --- a/engine/docker/terminal.go +++ b/engine/docker/terminal.go @@ -12,6 +12,7 @@ import ( "github.com/go-zoox/command/terminal" ) +// Terminal returns a terminal. func (d *docker) Terminal() (terminal.Terminal, error) { stream, err := d.client.ContainerAttach(d.ctx, d.container.ID, types.ContainerAttachOptions{ Stream: true, @@ -39,6 +40,7 @@ func (d *docker) Terminal() (terminal.Terminal, error) { return t, nil } +// Terminal is a terminal. type Terminal struct { Ctx context.Context Conn net.Conn @@ -47,6 +49,7 @@ type Terminal struct { ContainerID string } +// Close closes the terminal. func (t *Terminal) Close() error { t.Conn.Close() @@ -55,14 +58,17 @@ func (t *Terminal) Close() error { }) } +// Read reads from the terminal. func (t *Terminal) Read(p []byte) (n int, err error) { return t.Conn.Read(p) } +// Write writes to the terminal. func (t *Terminal) Write(p []byte) (n int, err error) { return t.Conn.Write(p) } +// Resize resizes the terminal. func (t *Terminal) Resize(rows, cols int) error { inspect, err := t.Client.ContainerInspect(t.Ctx, t.ContainerID) if err != nil { @@ -80,6 +86,7 @@ func (t *Terminal) Resize(rows, cols int) error { }) } +// ExitCode returns the exit code. func (t *Terminal) ExitCode() int { inspect, err := t.Client.ContainerInspect(t.Ctx, t.ContainerID) if err != nil { @@ -89,8 +96,9 @@ func (t *Terminal) ExitCode() int { return inspect.State.ExitCode } -func (rt *Terminal) Wait() error { - resultC, errC := rt.Client.ContainerWait(rt.Ctx, rt.ContainerID, container.WaitConditionNotRunning) +// Wait waits for the terminal to exit. +func (t *Terminal) Wait() error { + resultC, errC := t.Client.ContainerWait(t.Ctx, t.ContainerID, container.WaitConditionNotRunning) select { case err := <-errC: if err != nil && err != io.EOF { diff --git a/engine/docker/wait.go b/engine/docker/wait.go index 04096ce..46050b6 100644 --- a/engine/docker/wait.go +++ b/engine/docker/wait.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/api/types/container" ) +// Wait waits for the command to finish. func (d *docker) Wait() error { result, err := d.client.ContainerWait(d.ctx, d.container.ID, container.WaitConditionNotRunning) select { diff --git a/engine/engine.go b/engine/engine.go index f377f11..159df66 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -6,6 +6,7 @@ import ( "github.com/go-zoox/command/terminal" ) +// Engine is the interface that an command engine must implement. type Engine interface { Start() error Wait() error @@ -17,10 +18,3 @@ type Engine interface { // Terminal() (terminal.Terminal, error) } - -type Config struct { - Shell string - Command string - Environment map[string]string - WorkDir string -} diff --git a/engine/host/cancel.go b/engine/host/cancel.go index 1c5d1ae..7f0af3f 100644 --- a/engine/host/cancel.go +++ b/engine/host/cancel.go @@ -1,5 +1,6 @@ package host +// Cancel cancels the command. func (h *host) Cancel() error { if err := h.cmd.Process.Kill(); err != nil { return err diff --git a/engine/host/config.go b/engine/host/config.go index 0957bf8..553bb8f 100644 --- a/engine/host/config.go +++ b/engine/host/config.go @@ -1,5 +1,6 @@ package host +// Config is the configuration for a host engine. type Config struct { Command string Environment map[string]string diff --git a/engine/host/create.go b/engine/host/create.go index 938a864..ba7eca1 100644 --- a/engine/host/create.go +++ b/engine/host/create.go @@ -12,6 +12,7 @@ import ( "github.com/spf13/cast" ) +// Create creates the command. func (h *host) create() error { if h.cmd != nil { return errors.New("command: already created") diff --git a/engine/host/host.go b/engine/host/host.go index acb768a..b8fadfc 100644 --- a/engine/host/host.go +++ b/engine/host/host.go @@ -9,7 +9,8 @@ import ( "github.com/go-zoox/command/engine" ) -const Engine = "host" +// Name is the name of the engine. +const Name = "host" type host struct { ctx context.Context @@ -25,6 +26,7 @@ type host struct { stderr io.Writer } +// New creates a new host engine. func New(ctx context.Context, cfg *Config) (engine.Engine, error) { if cfg.Shell == "" { cfg.Shell = "/bin/sh" diff --git a/engine/host/io.go b/engine/host/io.go index 1b283d3..f9debed 100644 --- a/engine/host/io.go +++ b/engine/host/io.go @@ -2,16 +2,19 @@ package host import "io" +// SetStdin sets the stdin for the command. func (h *host) SetStdin(stdin io.Reader) error { h.stdin = stdin return nil } +// SetStdout sets the stdout for the command. func (h *host) SetStdout(stdout io.Writer) error { h.stdout = stdout return nil } +// SetStderr sets the stderr for the command. func (h *host) SetStderr(stderr io.Writer) error { h.stderr = stderr return nil diff --git a/engine/host/start.go b/engine/host/start.go index cc94544..57ee0d8 100644 --- a/engine/host/start.go +++ b/engine/host/start.go @@ -5,6 +5,7 @@ import ( "os/exec" ) +// Start starts the command. func (h *host) Start() error { if err := applyStdin(h.cmd, h.stdin); err != nil { return nil diff --git a/engine/host/terminal.go b/engine/host/terminal.go index 9bbe811..9bc34c4 100644 --- a/engine/host/terminal.go +++ b/engine/host/terminal.go @@ -8,6 +8,7 @@ import ( "github.com/go-zoox/command/terminal" ) +// Name is the name of the engine. func (h *host) Terminal() (terminal.Terminal, error) { terminal, err := pty.Start(h.cmd) if err != nil { @@ -20,34 +21,41 @@ func (h *host) Terminal() (terminal.Terminal, error) { }, nil } +// Terminal is the terminal implementation. type Terminal struct { *os.File Cmd *exec.Cmd } +// Close closes the terminal. func (t *Terminal) Close() error { return t.File.Close() } +// Read reads from the terminal. func (t *Terminal) Read(p []byte) (n int, err error) { return t.File.Read(p) } +// Write writes to the terminal. func (t *Terminal) Write(p []byte) (n int, err error) { return t.File.Write(p) } -func (rt *Terminal) Resize(rows, cols int) error { - return pty.Setsize(rt.File, &pty.Winsize{ +// Resize resizes the terminal. +func (t *Terminal) Resize(rows, cols int) error { + return pty.Setsize(t.File, &pty.Winsize{ Rows: uint16(rows), Cols: uint16(cols), }) } -func (rt *Terminal) ExitCode() int { - return rt.Cmd.ProcessState.ExitCode() +// ExitCode returns the exit code. +func (t *Terminal) ExitCode() int { + return t.Cmd.ProcessState.ExitCode() } -func (rt *Terminal) Wait() error { - return rt.Cmd.Wait() +// Wait waits for the terminal to exit. +func (t *Terminal) Wait() error { + return t.Cmd.Wait() } diff --git a/engine/host/wait.go b/engine/host/wait.go index 64f419e..ad269d4 100644 --- a/engine/host/wait.go +++ b/engine/host/wait.go @@ -1,5 +1,6 @@ package host +// Wait waits for the command to finish. func (h *host) Wait() error { return h.cmd.Wait() } diff --git a/io.go b/io.go index d3c3f6f..4617bab 100644 --- a/io.go +++ b/io.go @@ -2,14 +2,17 @@ package command import "io" +// SetStdin sets the stdin for the command. func (c *command) SetStdin(stdin io.Reader) error { return c.engine.SetStdin(stdin) } +// SetStdout sets the stdout for the command. func (c *command) SetStdout(stdout io.Writer) error { return c.engine.SetStdout(stdout) } +// SetStderr sets the stderr for the command. func (c *command) SetStderr(stderr io.Writer) error { return c.engine.SetStderr(stderr) } diff --git a/run.go b/run.go index 11b5526..304e324 100644 --- a/run.go +++ b/run.go @@ -1,5 +1,6 @@ package command +// Run runs the command. func (c *command) Run() error { if err := c.Start(); err != nil { return err diff --git a/start.go b/start.go index 14598a0..1d4d745 100644 --- a/start.go +++ b/start.go @@ -2,6 +2,7 @@ package command import "errors" +// Start starts to run the command. func (c *command) Start() error { if c.engine == nil { return errors.New("engine not set") diff --git a/terminal.go b/terminal.go index 6199a5b..9391b27 100644 --- a/terminal.go +++ b/terminal.go @@ -2,6 +2,7 @@ package command import "github.com/go-zoox/command/terminal" +// Terminal returns a terminal for the command. func (c *command) Terminal() (terminal.Terminal, error) { return c.engine.Terminal() } diff --git a/terminal/terminal.go b/terminal/terminal.go index 472f6a6..b129f8d 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -2,6 +2,7 @@ package terminal import "io" +// Terminal is the interface that a terminal must implement. type Terminal interface { io.ReadWriteCloser diff --git a/wait.go b/wait.go index 6ffd5f2..b8a270f 100644 --- a/wait.go +++ b/wait.go @@ -1,5 +1,6 @@ package command +// Wait waits for the command to exit. func (c *command) Wait() error { return c.engine.Wait() } From 29ffab7d48e881507812aa2d0bbad951c486fe1d Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 20:00:45 +0800 Subject: [PATCH 09/14] chore: fire tmp --- tmp/command_old.go | 86 ------------------------------ tmp/command_test.go | 125 -------------------------------------------- 2 files changed, 211 deletions(-) delete mode 100644 tmp/command_old.go delete mode 100644 tmp/command_test.go diff --git a/tmp/command_old.go b/tmp/command_old.go deleted file mode 100644 index 82e342b..0000000 --- a/tmp/command_old.go +++ /dev/null @@ -1,86 +0,0 @@ -package command - -import ( - "encoding/json" - "fmt" - "io" - "os" - "os/exec" -) - -// command is better os/exec command -type command struct { - Script string `json:"content"` - Context string `json:"context"` - Environment map[string]string `json:"environment"` - Shell string `json:"shell"` - // - Stdout io.Writer - Stderr io.Writer - // - cmd *exec.Cmd -} - -// Run runs the command -func (c *command) Run() error { - environment := os.Environ() - - for k, v := range c.Environment { - environment = append(environment, fmt.Sprintf("%s=%s", k, v)) - } - - shell := c.Shell - if shell == "" { - shell = os.Getenv("SHELL") - if shell == "" { - shell = "sh" - } - } - - cmd := exec.Command(shell, "-c", c.Script) - cmd.Dir = c.Context - cmd.Env = environment - - cmd.Stdout = c.Stdout - if cmd.Stdout == nil { - cmd.Stdout = os.Stdout - } - - cmd.Stderr = c.Stderr - if cmd.Stderr == nil { - cmd.Stderr = os.Stderr - } - - c.cmd = cmd - - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -// Config gets the config of command -func (c *command) Config() (string, error) { - cfg, err := json.MarshalIndent(c, "", " ") - if err != nil { - return "", err - } - - return string(cfg), nil -} - -// MustConfig gets the config of command -func (c *command) MustConfig() string { - cfg, err := c.Config() - if err != nil { - return "" - } - - return cfg -} - -// ExitCode gets the exit code of process -func (c *command) ExitCode() int { - return c.cmd.ProcessState.ExitCode() -} diff --git a/tmp/command_test.go b/tmp/command_test.go deleted file mode 100644 index 65fb758..0000000 --- a/tmp/command_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package command - -import ( - "io" - "testing" - - "github.com/go-zoox/testify" -) - -func TestCommand(t *testing.T) { - cmd := &command{ - Script: `echo "hello world"`, - } - - cfg := `{ - "content": "echo \"hello world\"", - "context": "", - "environment": null, - "shell": "" -}` - - testify.Equal(t, cfg, cmd.MustConfig()) - - // cmd.Run() -} - -func TestCommandWithContext(t *testing.T) { - cmd := &command{ - Script: `echo "PWD: $PWD"`, - Context: `/tmp`, - } - - cfg := `{ - "content": "echo \"PWD: $PWD\"", - "context": "/tmp", - "environment": null, - "shell": "" -}` - - testify.Equal(t, cfg, cmd.MustConfig()) - - // cmd.Run() -} - -func TestCommandWithEnvironment(t *testing.T) { - cmd := &command{ - Script: `echo "PWD: $PWD"`, - Context: `/tmp`, - Environment: map[string]string{ - "FOO": "BAR", - "FOO1": "NAR1", - }, - } - - cfg := `{ - "content": "echo \"PWD: $PWD\"", - "context": "/tmp", - "environment": { - "FOO": "BAR", - "FOO1": "NAR1" - }, - "shell": "" -}` - - testify.Equal(t, cfg, cmd.MustConfig()) - - // cmd.Run() -} - -func TestCommandWithShell(t *testing.T) { - cmd := &command{ - Script: `echo "PWD: $PWD"`, - Context: `/tmp`, - Environment: map[string]string{ - "FOO": "BAR", - "FOO1": "NAR1", - }, - Shell: "/bin/bash", - } - - cfg := `{ - "content": "echo \"PWD: $PWD\"", - "context": "/tmp", - "environment": { - "FOO": "BAR", - "FOO1": "NAR1" - }, - "shell": "/bin/bash" -}` - - testify.Equal(t, cfg, cmd.MustConfig()) - - // cmd.Run() -} - -func TestCommandWithMultilines(t *testing.T) { - output := &Output{} - cmd := &command{ - Script: ` -echo 1 -echo 2 -echo 3 -`, - Stdout: output, - Stderr: output, - } - - testify.Assert(t, cmd.Run() == nil) - testify.Equal(t, output.String(), "1\n2\n3\n") -} - -type Output struct { - io.Writer - - data []byte -} - -func (o *Output) Write(b []byte) (n int, err error) { - o.data = append(o.data, b...) - return len(b), nil -} - -func (o *Output) String() string { - return string(o.data) -} From e89e8142b2a2ee2902a4c2a8396f26228b3c72e2 Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 20:01:02 +0800 Subject: [PATCH 10/14] test: add command test --- command.go | 5 +++++ command_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 command_test.go diff --git a/command.go b/command.go index 1aa5f11..7038b04 100644 --- a/command.go +++ b/command.go @@ -3,6 +3,7 @@ package command import ( "context" "fmt" + "io" "github.com/go-zoox/command/engine" "github.com/go-zoox/command/engine/docker" @@ -18,6 +19,10 @@ type Command interface { // Run() error // + SetStdin(stdin io.Reader) error + SetStdout(stdout io.Writer) error + SetStderr(stderr io.Writer) error + // Terminal() (terminal.Terminal, error) } diff --git a/command_test.go b/command_test.go new file mode 100644 index 0000000..7e2794a --- /dev/null +++ b/command_test.go @@ -0,0 +1,29 @@ +package command + +import ( + "context" + "strings" + "testing" +) + +func TestNew(t *testing.T) { + cfg := &Config{ + Command: "echo hello world", + } + + cmd, err := New(context.Background(), cfg) + if err != nil { + t.Fatalf("failed to create command: %v", err) + } + + buf := &strings.Builder{} + cmd.SetStdout(buf) + + if err := cmd.Run(); err != nil { + t.Fatalf("failed to start command: %v", err) + } + + if v := buf.String(); v != "hello world\n" { + t.Fatalf("expected %q, got %q", "hello world\n", v) + } +} From 88938e817759651cc16538af34ba874943602909 Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 21:12:47 +0800 Subject: [PATCH 11/14] feat: support memory/cpu/platform for engine docker --- cmd/command-runner/commands/exec.go | 34 ++++++++++++++---- command.go | 9 +++++ engine/docker/config.go | 7 ++++ engine/docker/create.go | 55 +++++++++++++++++++++++++++-- 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/cmd/command-runner/commands/exec.go b/cmd/command-runner/commands/exec.go index efe76fe..5615bc8 100644 --- a/cmd/command-runner/commands/exec.go +++ b/cmd/command-runner/commands/exec.go @@ -13,6 +13,7 @@ import ( "github.com/go-zoox/cli" "github.com/go-zoox/command" "github.com/go-zoox/command/terminal" + "github.com/go-zoox/fs" "golang.org/x/term" ) @@ -41,6 +42,7 @@ func Exec(app *cli.MultipleProgram) { Usage: "the command workdir", Aliases: []string{"w"}, EnvVars: []string{"WORKDIR"}, + Value: fs.CurrentDir(), }, &cli.StringFlag{ Name: "user", @@ -66,15 +68,35 @@ func Exec(app *cli.MultipleProgram) { Aliases: []string{"t"}, EnvVars: []string{"TTY"}, }, + &cli.Int64Flag{ + Name: "memory", + Usage: `Memory limit, unit: MB`, + Aliases: []string{"m"}, + EnvVars: []string{"MEMORY"}, + }, + &cli.Float64Flag{ + Name: "cpu", + Usage: `CPU limit, unit: core`, + EnvVars: []string{"CPU"}, + }, + &cli.StringFlag{ + Name: "platform", + Usage: `Command platform, available: linux/amd64, linux/arm64`, + Aliases: []string{"p"}, + EnvVars: []string{"PLATFORM"}, + }, }, Action: func(ctx *cli.Context) (err error) { cmd, err := command.New(context.Background(), &command.Config{ - Engine: ctx.String("engine"), - Command: ctx.String("command"), - WorkDir: ctx.String("workdir"), - User: ctx.String("user"), - Shell: ctx.String("shell"), - Image: ctx.String("image"), + Engine: ctx.String("engine"), + Command: ctx.String("command"), + WorkDir: ctx.String("workdir"), + User: ctx.String("user"), + Shell: ctx.String("shell"), + Image: ctx.String("image"), + Memory: ctx.Int64("memory"), + CPU: ctx.Float64("cpu"), + Platform: ctx.String("platform"), }) if err != nil { return err diff --git a/command.go b/command.go index 7038b04..42cf651 100644 --- a/command.go +++ b/command.go @@ -37,6 +37,12 @@ type Config struct { // engine = docker Image string + // Memory is the memory limit, unit: MB + Memory int64 + // CPU is the CPU limit, unit: core + CPU float64 + // Platform is the command platform, available: linux/amd64, linux/arm64 + Platform string } // New creates a new command runner. @@ -70,6 +76,9 @@ func New(ctx context.Context, cfg *Config) (cmd Command, err error) { User: cfg.User, Shell: cfg.Shell, Image: cfg.Image, + Memory: cfg.Memory, + CPU: cfg.CPU, + Platform: cfg.Platform, }) if err != nil { return nil, err diff --git a/engine/docker/config.go b/engine/docker/config.go index 24aa9bf..b251db7 100644 --- a/engine/docker/config.go +++ b/engine/docker/config.go @@ -8,5 +8,12 @@ type Config struct { User string Shell string + // engine = docker Image string + // Memory is the memory limit, unit: MB + Memory int64 + // CPU is the CPU limit, unit: core + CPU float64 + // Platform is the command platform, available: linux/amd64, linux/arm64 + Platform string } diff --git a/engine/docker/create.go b/engine/docker/create.go index 4771b73..8396735 100644 --- a/engine/docker/create.go +++ b/engine/docker/create.go @@ -4,8 +4,12 @@ import ( "fmt" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" "github.com/docker/docker/client" + "github.com/go-zoox/core-utils/cast" + "github.com/go-zoox/core-utils/strings" "github.com/go-zoox/uuid" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // create creates a container. @@ -24,6 +28,7 @@ func (d *docker) create() (err error) { } cfg := &container.Config{ + Hostname: "go-zoox", Image: d.cfg.Image, Cmd: append([]string{d.cfg.Shell}, d.args...), User: d.cfg.User, @@ -37,9 +42,55 @@ func (d *docker) create() (err error) { StdinOnce: true, } - hostCfg := &container.HostConfig{} + hostCfg := &container.HostConfig{ + Resources: container.Resources{ + // Memory: d.cfg.Memory, + // CPUPeriod: 100000, + // CPUQuota: cast.ToInt64(100000 * d.cfg.CPU), + }, + Mounts: []mount.Mount{ + // { + // Type: mount.TypeBind, + // Source: d.cfg.WorkDir, + // Target: d.cfg.WorkDir, + // ReadOnly: false, + // }, + }, + } + if d.cfg.Memory != 0 { + hostCfg.Resources.Memory = d.cfg.Memory * 1024 * 1024 + } + + if d.cfg.CPU != 0 { + hostCfg.Resources.CPUPeriod = 100000 + hostCfg.Resources.CPUQuota = cast.ToInt64(float64(hostCfg.Resources.CPUPeriod) * d.cfg.CPU) + } + if d.cfg.WorkDir != "" { + hostCfg.Mounts = append(hostCfg.Mounts, mount.Mount{ + Type: mount.TypeBind, + Source: d.cfg.WorkDir, + Target: d.cfg.WorkDir, + ReadOnly: false, + }) + } + + platformCfg := &ocispec.Platform{ + OS: "linux", + Architecture: "amd64", + } + if d.cfg.Platform != "" { + switch d.cfg.Platform { + case "linux/amd64", "linux/arm64": + default: + return fmt.Errorf("invalid platform: %s, available: linux/amd64, linux/arm64", d.cfg.Platform) + } + + osArch := strings.Split(d.cfg.Platform, "/") + platformCfg.OS = osArch[0] + platformCfg.Architecture = osArch[1] + } - d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, nil, nil, uuid.V4()) + d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, nil, platformCfg, uuid.V4()) if err != nil { return err } From cfd9299fad05c37061e1f74a3cedb1b24cc8b730 Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 21:39:35 +0800 Subject: [PATCH 12/14] feat: support network and disable-network for engine docker --- cmd/command-runner/commands/exec.go | 31 ++++++++++++++++++++--------- command.go | 24 +++++++++++++--------- engine/docker/config.go | 4 ++++ engine/docker/create.go | 22 +++++++++++++++++++- 4 files changed, 62 insertions(+), 19 deletions(-) diff --git a/cmd/command-runner/commands/exec.go b/cmd/command-runner/commands/exec.go index 5615bc8..dfaff7d 100644 --- a/cmd/command-runner/commands/exec.go +++ b/cmd/command-runner/commands/exec.go @@ -85,18 +85,31 @@ func Exec(app *cli.MultipleProgram) { Aliases: []string{"p"}, EnvVars: []string{"PLATFORM"}, }, + &cli.StringFlag{ + Name: "network", + Usage: `Network name`, + Aliases: []string{"n"}, + EnvVars: []string{"NETWORK"}, + }, + &cli.BoolFlag{ + Name: "disable-network", + Usage: "Disable network visit", + EnvVars: []string{"DISABLE_NETWORK"}, + }, }, Action: func(ctx *cli.Context) (err error) { cmd, err := command.New(context.Background(), &command.Config{ - Engine: ctx.String("engine"), - Command: ctx.String("command"), - WorkDir: ctx.String("workdir"), - User: ctx.String("user"), - Shell: ctx.String("shell"), - Image: ctx.String("image"), - Memory: ctx.Int64("memory"), - CPU: ctx.Float64("cpu"), - Platform: ctx.String("platform"), + Engine: ctx.String("engine"), + Command: ctx.String("command"), + WorkDir: ctx.String("workdir"), + User: ctx.String("user"), + Shell: ctx.String("shell"), + Image: ctx.String("image"), + Memory: ctx.Int64("memory"), + CPU: ctx.Float64("cpu"), + Platform: ctx.String("platform"), + Network: ctx.String("network"), + DisableNetwork: ctx.Bool("disable-network"), }) if err != nil { return err diff --git a/command.go b/command.go index 42cf651..04d752f 100644 --- a/command.go +++ b/command.go @@ -43,6 +43,10 @@ type Config struct { CPU float64 // Platform is the command platform, available: linux/amd64, linux/arm64 Platform string + // Network is the network name + Network string + // DisableNetwork disables network + DisableNetwork bool } // New creates a new command runner. @@ -70,15 +74,17 @@ func New(ctx context.Context, cfg *Config) (cmd Command, err error) { } case docker.Name: engine, err = docker.New(ctx, &docker.Config{ - Command: cfg.Command, - WorkDir: cfg.WorkDir, - Environment: cfg.Environment, - User: cfg.User, - Shell: cfg.Shell, - Image: cfg.Image, - Memory: cfg.Memory, - CPU: cfg.CPU, - Platform: cfg.Platform, + Command: cfg.Command, + WorkDir: cfg.WorkDir, + Environment: cfg.Environment, + User: cfg.User, + Shell: cfg.Shell, + Image: cfg.Image, + Memory: cfg.Memory, + CPU: cfg.CPU, + Platform: cfg.Platform, + Network: cfg.Network, + DisableNetwork: cfg.DisableNetwork, }) if err != nil { return nil, err diff --git a/engine/docker/config.go b/engine/docker/config.go index b251db7..58a5352 100644 --- a/engine/docker/config.go +++ b/engine/docker/config.go @@ -16,4 +16,8 @@ type Config struct { CPU float64 // Platform is the command platform, available: linux/amd64, linux/arm64 Platform string + // Network is the network name + Network string + // DisableNetwork disables network + DisableNetwork bool } diff --git a/engine/docker/create.go b/engine/docker/create.go index 8396735..4bcd951 100644 --- a/engine/docker/create.go +++ b/engine/docker/create.go @@ -3,8 +3,10 @@ package docker import ( "fmt" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" "github.com/go-zoox/core-utils/cast" "github.com/go-zoox/core-utils/strings" @@ -56,10 +58,14 @@ func (d *docker) create() (err error) { // ReadOnly: false, // }, }, + // NetworkMode: "none", } if d.cfg.Memory != 0 { hostCfg.Resources.Memory = d.cfg.Memory * 1024 * 1024 } + if d.cfg.DisableNetwork { + hostCfg.NetworkMode = "none" + } if d.cfg.CPU != 0 { hostCfg.Resources.CPUPeriod = 100000 @@ -74,6 +80,20 @@ func (d *docker) create() (err error) { }) } + networkCfg := &network.NetworkingConfig{ + EndpointsConfig: map[string]*network.EndpointSettings{}, + } + if d.cfg.Network != "" { + networkIns, err := d.client.NetworkInspect(d.ctx, d.cfg.Network, types.NetworkInspectOptions{}) + if err != nil { + return err + } + + networkCfg.EndpointsConfig[d.cfg.Network] = &network.EndpointSettings{ + NetworkID: networkIns.ID, + } + } + platformCfg := &ocispec.Platform{ OS: "linux", Architecture: "amd64", @@ -90,7 +110,7 @@ func (d *docker) create() (err error) { platformCfg.Architecture = osArch[1] } - d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, nil, platformCfg, uuid.V4()) + d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, networkCfg, platformCfg, uuid.V4()) if err != nil { return err } From 3a205ea8f7465429f442511630dacac8ad9ca9a9 Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 21:43:08 +0800 Subject: [PATCH 13/14] chore: update container name --- engine/docker/create.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engine/docker/create.go b/engine/docker/create.go index 4bcd951..1108f18 100644 --- a/engine/docker/create.go +++ b/engine/docker/create.go @@ -110,7 +110,8 @@ func (d *docker) create() (err error) { platformCfg.Architecture = osArch[1] } - d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, networkCfg, platformCfg, uuid.V4()) + containerName := fmt.Sprintf("go-zoox_command_%s", uuid.V4()) + d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, networkCfg, platformCfg, containerName) if err != nil { return err } From 918a09e6289c7b3866ac38cce3a3ca6fa7f1639a Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 8 Oct 2023 21:52:52 +0800 Subject: [PATCH 14/14] feat: support custom runner id --- command.go | 34 ++++++++++++++++++++++++++++++++-- engine/docker/config.go | 3 +++ engine/docker/create.go | 4 +--- engine/docker/docker.go | 6 ++++++ engine/host/config.go | 3 +++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/command.go b/command.go index 04d752f..96a91d7 100644 --- a/command.go +++ b/command.go @@ -9,6 +9,7 @@ import ( "github.com/go-zoox/command/engine/docker" "github.com/go-zoox/command/engine/host" "github.com/go-zoox/command/terminal" + "github.com/go-zoox/uuid" ) // Command is the command runner interface @@ -47,6 +48,9 @@ type Config struct { Network string // DisableNetwork disables network DisableNetwork bool + + // Custom Command Runner ID + ID string } // New creates a new command runner. @@ -59,13 +63,37 @@ func New(ctx context.Context, cfg *Config) (cmd Command, err error) { cfg.Shell = "/bin/sh" } + if cfg.ID == "" { + cfg.ID = fmt.Sprintf("go-zoox_command_%s", uuid.V4()) + } + + environment := map[string]string{ + "GO_ZOOX_COMMAND_ENGINE": cfg.Engine, + "GO_ZOOX_COMMAND_ID": cfg.ID, + "GO_ZOOX_COMMAND_SHELL": cfg.Shell, + "GO_ZOOX_COMMAND_USER": cfg.User, + "GO_ZOOX_COMMAND_WORKDIR": cfg.WorkDir, + "GO_ZOOX_COMMAND_COMMAND": cfg.Command, + "GO_ZOOX_COMMAND_IMAGE": cfg.Image, + "GO_ZOOX_COMMAND_MEMORY": fmt.Sprintf("%d", cfg.Memory), + "GO_ZOOX_COMMAND_CPU": fmt.Sprintf("%f", cfg.CPU), + "GO_ZOOX_COMMAND_PLATFORM": cfg.Platform, + "GO_ZOOX_COMMAND_NETWORK": cfg.Network, + "GO_ZOOX_COMMAND_DISABLE_NETWORK": fmt.Sprintf("%t", cfg.DisableNetwork), + } + for k, v := range cfg.Environment { + environment[k] = v + } + var engine engine.Engine switch cfg.Engine { case host.Name: engine, err = host.New(ctx, &host.Config{ + ID: cfg.ID, + // Command: cfg.Command, WorkDir: cfg.WorkDir, - Environment: cfg.Environment, + Environment: environment, User: cfg.User, Shell: cfg.Shell, }) @@ -74,9 +102,11 @@ func New(ctx context.Context, cfg *Config) (cmd Command, err error) { } case docker.Name: engine, err = docker.New(ctx, &docker.Config{ + ID: cfg.ID, + // Command: cfg.Command, WorkDir: cfg.WorkDir, - Environment: cfg.Environment, + Environment: environment, User: cfg.User, Shell: cfg.Shell, Image: cfg.Image, diff --git a/engine/docker/config.go b/engine/docker/config.go index 58a5352..311555b 100644 --- a/engine/docker/config.go +++ b/engine/docker/config.go @@ -20,4 +20,7 @@ type Config struct { Network string // DisableNetwork disables network DisableNetwork bool + + // Custom Command Runner ID + ID string } diff --git a/engine/docker/create.go b/engine/docker/create.go index 1108f18..ab7b26e 100644 --- a/engine/docker/create.go +++ b/engine/docker/create.go @@ -10,7 +10,6 @@ import ( "github.com/docker/docker/client" "github.com/go-zoox/core-utils/cast" "github.com/go-zoox/core-utils/strings" - "github.com/go-zoox/uuid" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -110,8 +109,7 @@ func (d *docker) create() (err error) { platformCfg.Architecture = osArch[1] } - containerName := fmt.Sprintf("go-zoox_command_%s", uuid.V4()) - d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, networkCfg, platformCfg, containerName) + d.container, err = d.client.ContainerCreate(d.ctx, cfg, hostCfg, networkCfg, platformCfg, d.cfg.ID) if err != nil { return err } diff --git a/engine/docker/docker.go b/engine/docker/docker.go index 29e9504..5c626c0 100644 --- a/engine/docker/docker.go +++ b/engine/docker/docker.go @@ -2,12 +2,14 @@ package docker import ( "context" + "fmt" "io" "os" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" "github.com/go-zoox/command/engine" + "github.com/go-zoox/uuid" ) // Name is the name of the engine. @@ -41,6 +43,10 @@ func New(ctx context.Context, cfg *Config) (engine.Engine, error) { cfg.Shell = "/bin/sh" } + if cfg.ID == "" { + cfg.ID = fmt.Sprintf("go-zoox_command_%s", uuid.V4()) + } + d := &docker{ ctx: ctx, cfg: cfg, diff --git a/engine/host/config.go b/engine/host/config.go index 553bb8f..33bfacf 100644 --- a/engine/host/config.go +++ b/engine/host/config.go @@ -10,4 +10,7 @@ type Config struct { // IsHistoryDisabled bool + + // Custom Command Runner ID + ID string }