1 Star 0 Fork 0

h79/goutils

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
cmd.go 4.78 KB
一键复制 编辑 原始数据 按行查看 历史
package system
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"runtime"
"strings"
"time"
)
type Config struct {
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
EnableStd bool `json:"enableStd" yaml:"enableStd" xml:"enableStd"`
EnableEnv bool `json:"enableEnv" yaml:"enableEnv" xml:"enableEnv"`
}
type CmdResult struct {
stdout bytes.Buffer
stderr bytes.Buffer
Command string
Err error
StartTime time.Time
EndTime time.Time
}
func (r CmdResult) Result() string {
if r.Err != nil {
return r.stderr.String()
}
return r.stdout.String()
}
func (r CmdResult) Error() string {
if r.Err != nil {
return fmt.Sprintf("CmdResult: %s, err: %v", r.Command, r.Err)
}
return fmt.Sprintf("CmdResult: %s, Result: %s, StartTime:%v, EndTime: %v", r.Command, r.Result(), r.StartTime, r.EndTime)
}
func StripArgs(args []string, arg string) []string {
ll := len(args)
for i := 0; i < ll; {
if args[i] == arg {
next := 1
if i+1 < ll && args[i+1][0] != '-' {
next = 2
}
args = append(args[:i], args[i+next:]...)
break
}
i++
}
return args
}
func (*Shell) init(args string) *exec.Cmd {
var args_ []string
var cmd *exec.Cmd
switch runtime.GOOS {
case "darwin":
fallthrough
case "linux":
args_ = append(args_, "-c")
args_ = append(args_, args)
cmd = exec.Command(os.Getenv("SHELL"), args_...)
break
case "windows":
args_ = append(args_, "/C")
args_ = append(args_, args)
cmd = exec.Command("cmd", args_...)
break
default:
os.Exit(1)
}
return cmd
}
func (c *Cmd) init(conf *Config, env ...string) *exec.Cmd {
if conf == nil {
return c.Cmd
}
if conf.EnableEnv {
c.Cmd.Env = os.Environ()
c.Cmd.Env = append(c.Cmd.Env, env...)
}
if conf.EnableStd {
c.Cmd.Stdin = os.Stdin
c.Cmd.Stdout = os.Stdout
c.Cmd.Stderr = os.Stderr
} else {
c.Cmd.Stdin = conf.Stdin
c.Cmd.Stdout = conf.Stdout
c.Cmd.Stderr = conf.Stderr
}
sysProcAttr(c.Cmd)
return c.Cmd
}
type Shell struct {
}
func (s *Shell) Start(args []string, config Config, env ...string) (*exec.Cmd, error) {
var c = NewCmd(s.init(strings.Join(args, " ")), &config, env...)
return c.Start()
}
// Run 阻塞式同步执行
func (s *Shell) Run(cmd string) CmdResult {
res := CmdResult{Command: cmd, StartTime: time.Now()}
conf := Config{
Stdout: &res.stdout,
Stderr: &res.stderr,
}
var c = NewCmd(s.init(cmd), &conf)
res.Err = c.Cmd.Run()
res.EndTime = time.Now()
return res
}
type Cmd struct {
Cmd *exec.Cmd
Err error
Data interface{}
}
func NewCmd(cmd *exec.Cmd, conf *Config, env ...string) *Cmd {
var c = &Cmd{Cmd: cmd}
c.init(conf, env...)
return c
}
func (c *Cmd) WithErr(err error) *Cmd {
c.Err = err
return c
}
func (c *Cmd) WithData(da interface{}) *Cmd {
c.Data = da
return c
}
func (c *Cmd) Start() (*exec.Cmd, error) {
err := c.Cmd.Start()
if err != nil {
return nil, err
}
return c.Cmd, nil
}
// Run 超时同步执行, 等待结果返回
// Deprecated: this function simply calls SyncExec.
func (*Cmd) Run(cmd string, timeout time.Duration) CmdResult {
return SyncExec(cmd, timeout)
}
// SyncExec 超时同步执行
// timeout = 0, default 30 seconds
func SyncExec(cmd string, timeout time.Duration) CmdResult {
var res = CmdResult{Command: cmd, StartTime: time.Now()}
var conf = Config{Stdout: &res.stdout, Stderr: &res.stderr}
var tt = timeout * time.Second
var s = Shell{}
var c = NewCmd(s.init(cmd), &conf)
if tt <= 0 {
tt = 30 * time.Second
}
t := time.After(tt)
stop := make(chan struct{}, 1)
ChildRunning(func() {
res.Err = c.Cmd.Run()
res.EndTime = time.Now()
stop <- struct{}{}
})
select {
case <-stop:
break
case <-t:
if c.Cmd.Process != nil {
err := c.Cmd.Process.Kill()
return CmdResult{Command: cmd, Err: fmt.Errorf("cmd time out, kill the process id= %d,%v", c.Cmd.Process.Pid, err)}
}
return CmdResult{Command: cmd, Err: fmt.Errorf("cmd time out")}
case <-Closed():
break
}
return res
}
// AsyExec 异步执行,返回chan
func AsyExec(cmd string) <-chan CmdResult {
resCh := make(chan CmdResult, 1)
ChildRunning(func() {
var s = Shell{}
res := s.Run(cmd)
resCh <- res
})
return resCh
}
// CreateTmpShellFile 创建临时的 shell 脚本文件
// content 创建的脚本内容
func CreateTmpShellFile(pattern, content string) (tmpFile string, err error) {
file, err := os.CreateTemp("", pattern)
if err != nil {
return
}
defer func() {
file.Close()
if runtime.GOOS == "windows" {
tmpFile = file.Name() + ".cmd"
} else {
tmpFile = file.Name() + ".sh"
}
err = os.Rename(file.Name(), tmpFile)
}()
err = file.Chmod(0777)
if err != nil {
return "", err
}
if runtime.GOOS != "windows" {
_, err = file.WriteString("#!/bin/bash\n")
if err != nil {
return
}
_, err = file.WriteString("set -e\n")
if err != nil {
return
}
}
_, err = file.WriteString(content)
return
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/h79/goutils.git
git@gitee.com:h79/goutils.git
h79
goutils
goutils
v1.8.35

搜索帮助

344bd9b3 5694891 D2dac590 5694891