Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,24 @@ 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: |
go mod tidy
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 }}
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -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}}
23 changes: 23 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions cancel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package command

// Cancel cancels the command.
func (c *command) Cancel() error {
return c.engine.Cancel()
}
262 changes: 262 additions & 0 deletions cmd/command-runner/commands/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
package commands

import (
"context"
"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"
"github.com/go-zoox/fs"

"golang.org/x/term"
)

// Exec is the exec command
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: "workdir",
Usage: "the command workdir",
Aliases: []string{"w"},
EnvVars: []string{"WORKDIR"},
Value: fs.CurrentDir(),
},
&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"},
},
&cli.StringFlag{
Name: "image",
Usage: "docker image",
Aliases: []string{"i"},
EnvVars: []string{"IMAGE"},
},
&cli.BoolFlag{
Name: "tty",
Usage: "Allocate a pseudo-TTY. The default is false, which disables TTY allocation.",
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"},
},
&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"),
Network: ctx.String("network"),
DisableNetwork: ctx.Bool("disable-network"),
})
if err != nil {
return err
}

if ctx.Bool("tty") {
term, err := cmd.Terminal()
if err != nil {
return err
}
defer term.Close()

go func() {
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 {
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)
}
19 changes: 19 additions & 0 deletions cmd/command-runner/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"github.com/go-zoox/cli"
"github.com/go-zoox/command"
"github.com/go-zoox/command/cmd/command-runner/commands"
)

func main() {
app := cli.NewMultipleProgram(&cli.MultipleProgramConfig{
Name: "command-runner",
Usage: "Powerful command runner",
Version: command.Version,
})

commands.Exec(app)

app.Run()
}
Loading