feat: initial commit of vps-commander release v1.0.0
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
package executor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
ExitCode int
|
||||
Stdout string
|
||||
Stderr string
|
||||
DurationMS int64
|
||||
}
|
||||
|
||||
type Local struct{ MaxOutput int }
|
||||
|
||||
type cappedBuffer struct {
|
||||
buf bytes.Buffer
|
||||
max int
|
||||
}
|
||||
|
||||
func (b *cappedBuffer) Write(p []byte) (int, error) {
|
||||
if b.max <= 0 {
|
||||
return len(p), nil
|
||||
}
|
||||
if b.buf.Len() < b.max {
|
||||
n := b.max - b.buf.Len()
|
||||
if n > len(p) {
|
||||
n = len(p)
|
||||
}
|
||||
_, _ = b.buf.Write(p[:n])
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (e Local) Run(ctx context.Context, command, workdir string) Result {
|
||||
start := time.Now()
|
||||
if e.MaxOutput <= 0 {
|
||||
e.MaxOutput = 1024 * 1024
|
||||
}
|
||||
cmd := exec.Command("/bin/sh", "-c", command)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
if workdir != "" {
|
||||
cmd.Dir = workdir
|
||||
}
|
||||
var stdout, stderr cappedBuffer
|
||||
stdout.max, stderr.max = e.MaxOutput, e.MaxOutput
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
return Result{ExitCode: 1, Stderr: err.Error(), DurationMS: time.Since(start).Milliseconds()}
|
||||
}
|
||||
waitCh := make(chan error, 1)
|
||||
go func() { waitCh <- cmd.Wait() }()
|
||||
timedOut := false
|
||||
var err error
|
||||
select {
|
||||
case err = <-waitCh:
|
||||
case <-ctx.Done():
|
||||
timedOut = true
|
||||
_ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
|
||||
err = <-waitCh
|
||||
}
|
||||
code := 0
|
||||
if err != nil {
|
||||
code = 1
|
||||
if ee, ok := err.(*exec.ExitError); ok {
|
||||
code = ee.ExitCode()
|
||||
}
|
||||
}
|
||||
if timedOut || ctx.Err() != nil {
|
||||
code = 124
|
||||
}
|
||||
return Result{code, stdout.buf.String(), strings.TrimSpace(stderr.buf.String()), time.Since(start).Milliseconds()}
|
||||
}
|
||||
Reference in New Issue
Block a user