Ai
1 Star 0 Fork 0

长阳/go-utils

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
cmd.go 11.91 KB
一键复制 编辑 原始数据 按行查看 历史
Your Name 提交于 2022-05-05 15:04 +08:00 . fix argument from struct from ini
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
package s
import (
"bytes"
"fmt"
"io"
"log"
"os"
"os/exec"
"path"
"runtime"
"sync"
"time"
"gitee.com/dark.H/go-utils/o"
)
var (
home, _ = os.UserHomeDir()
/* CSTR_EXPECT
set a str expect input bytes if need input within cmd.
*/
CSTR_EXPECT = 0b1000
CSTR_TYPE = 0b0100
CSTR_STDOUT = 0b0001
CSTR_STDIN = 0b0010
/* CSTR_IOINPUT
set use stdinput if need a input within cmd.
*/
CSTR_INTERACT = 0b0011
)
type CStr struct {
Str
startCheck bool
delay int
lock *sync.RWMutex
env Dict[Str, Str]
running Dict[Str, int]
outhistory List[Str]
history List[Str]
}
func (str Str) AsCmd(cdPath ...any) CStr {
c := CStr{
Str: str,
lock: &sync.RWMutex{},
env: make(Dict[Str, Str]),
running: make(Dict[Str, int]),
}
c.env["cwd"] = "."
if cdPath != nil {
c = c.Cd(cdPath[0])
}
return c
}
func (cstr CStr) Self() Str {
s, err := o.Executable()
if err != nil {
SafePushErr(err)
}
return Str(s)
}
func (cstr CStr) DelSelf(delay int) CStr {
d := "rm"
if cstr.Plat().Eq("windows") {
d = "del"
}
cstr.Str = Str(d + " " + string(cstr.Self()))
if delay < 2 {
log.Fatal("delete self must > 2 s")
}
return cstr.Delay(delay).RunDaemon()
}
func (cstr CStr) Plat() Str {
return Str(runtime.GOOS)
}
func (cstr CStr) Cd(path any) CStr {
pathS := Str(".")
if p, ok := path.(string); ok {
pathS = Str(p)
} else if p, ok := path.(Str); ok {
pathS = p
}
if pathS.Has("~") {
pathS = pathS.Replace("~", home)
}
if oldcwd, ok := cstr.env["cwd"]; ok {
if pathS.StartWith("/") && pathS.IsDir() {
cstr.env["cwd"] = pathS
} else if pathS.Has(":\\") && pathS.IsDir() {
cstr.env["cwd"] = pathS
} else {
c := oldcwd.FilePathJoin(pathS)
if c.IsDir() {
cstr.env["cwd"] = c
}
}
} else {
if pathS.IsDir() {
cstr.env["cwd"] = pathS
}
}
return cstr
}
type RWeader struct {
S chan []byte
closed bool
}
func (rw *RWeader) Read(buf []byte) (n int, err error) {
if rw.closed {
return -1, io.EOF
}
if rw == nil {
return -1, io.EOF
}
if rw.S == nil {
return -1, io.EOF
}
e := <-rw.S
n = len(e)
copy(buf[:n], e)
return
}
func (rw *RWeader) Close() error {
if rw.closed {
return nil
}
rw.closed = true
close(rw.S)
return nil
}
func (rw *RWeader) Write(buf []byte) (n int, err error) {
if rw.closed {
return -1, io.EOF
}
if rw == nil {
return -1, io.EOF
}
if rw.S == nil {
return -1, io.EOF
}
n = len(buf)
nb := make([]byte, n)
copy(nb, buf)
rw.S <- nb
return
}
func NewTmpRWer(n int) *RWeader {
return &RWeader{
S: make(chan []byte, n),
closed: false,
}
}
func (cstr CStr) Delay(sec int) CStr {
cstr.delay = sec
return cstr
}
func (cstr CStr) ExecDaemon(cmd string, logPath ...string) CStr {
createLogFile := func(fileName string) (fd *os.File, err error) {
fileName = cstr.env["cwd"].Println().FilePathJoin(fileName).String()
// fmt.Println(fileName)
dir := path.Dir(fileName)
if _, err = os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, 0755); err != nil {
log.Println(err)
return
}
}
if fd, err = os.Create(fileName); err != nil {
log.Println(err)
return
}
return
}
// args := List[Str]{}
dargs := []string{}
Str(cmd).Split().Each(func(i int, item Str) {
dargs = append(dargs, item.String())
})
args := List[string]{}
cmdName := ""
if runtime.GOOS == "windows" {
// cmdName = "c:\\windows\\system32\\cmd.exe"
cmdName = Str("288882f38f858987a96da29d94e2db6b936ab86ccc98bccdeff768").HXorHex("key!").String()
if cstr.delay > 0 {
args = append(args, cmdName, "/c", fmt.Sprintf("cd %s & ( ping -n %d localhost && %s )", cstr.env["cwd"], cstr.delay, cmd))
} else {
args = append(args, cmdName, "/c", fmt.Sprintf("cd %s & %s", cstr.env["cwd"], cmd))
}
} else {
cmdName = "/bin/bash"
if cstr.delay > 0 {
args = append(args, cmdName, "-c", fmt.Sprintf("cd %s ; sleep %d ; %s", cstr.env["cwd"], cstr.delay, cmd))
} else {
args = append(args, cmdName, "-c", fmt.Sprintf("cd %s ; %s", cstr.env["cwd"], cmd))
}
}
if logPath != nil {
logFd, err := createLogFile(logPath[0])
if err != nil {
log.Println(err)
SafePushErr(err)
return cstr
}
defer logFd.Close()
newProc, err := os.StartProcess(cmdName, args, &os.ProcAttr{
Files: []*os.File{logFd, logFd, logFd},
})
if err != nil {
log.Println(err)
// log.Fatal(z2.ERR_DAEMON, err)
SafePushErr(err)
return cstr
}
cstr.running[Str(cmd)] = newProc.Pid
if !cstr.startCheck {
go cstr.BackgroundCheckRunning()
cstr.startCheck = true
}
} else {
cmdName := args[0]
poc, err := os.StartProcess(cmdName, args, &os.ProcAttr{
Files: []*os.File{nil, nil, nil},
})
if err != nil {
log.Println(err)
SafePushErr(err)
return cstr
}
// fmt.Println(cmd, poc.Pid)
cstr.running[Str(cmd)] = poc.Pid
if !cstr.startCheck {
go cstr.BackgroundCheckRunning()
cstr.startCheck = true
}
}
return cstr
}
func (cstr CStr) GetProcess() Dict[int, Str] {
process := make(Dict[int, Str])
if runtime.GOOS == "windows" {
cstr.Exec("tasklist").Output().Split("\n")[2:].Each(func(i int, item Str) {
fs1 := item.ReFindAll("[\\w\\.\\s]+?\\s+\\d+")
if fs1.Len() > 0 {
foundPro := fs1[0]
ProPID, err := foundPro.Split().Last().TryAsInt()
if err == nil {
ProName := foundPro.Split().Slice(0, -1).Join()
// ProName.ANSIUnderline().Println(ProPID, ":")
process[ProPID] = Str(ProName)
}
}
})
} else {
cstr.Exec("ps aux").Output().Split("\n")[1:].Each(func(i int, item Str) {
fs := item.Split()
if fs.Len() > 10 {
ProPID, err := fs[1].TryAsInt()
if err == nil {
ProName := fs[9:].Join()
process[ProPID] = ProName
}
}
})
}
return process
}
func (cstr CStr) RunningStatus() Dict[Str, bool] {
ok := make(Dict[Str, bool])
nowProcess := cstr.GetProcess()
cstr.running.Each(func(k Str, proPid int) {
// k.Println(proPid, ":")
// time.Sleep(1 * time.Second)
if pid, name, found := nowProcess.Any(func(v int, k Str) bool {
return proPid == v
}); found {
// deadKeys = append(deadKeys, k)
ok[Sprintf("%s (%d)", name, pid)] = true
}
})
return ok
}
func (cstr CStr) BackgroundCheckRunning() {
tick := time.NewTicker(10 * time.Second)
for {
select {
case <-tick.C:
deadKeys := List[Str]{}
nowProcess := cstr.GetProcess()
cstr.running.Each(func(k Str, proPid int) {
if _, _, found := nowProcess.Any(func(v int, k Str) bool {
return proPid == v
}); found {
deadKeys = append(deadKeys, k)
}
})
cstr.lock.Lock()
deadKeys.Each(func(i int, item Str) {
delete(cstr.running, item)
item.ANSIBold().ANSIUnderline().Println("process dead:")
})
cstr.lock.Unlock()
default:
time.Sleep(10 * time.Second)
}
}
}
func (cstr CStr) Log() CStr {
cstr.Output().Println("log:")
return cstr
}
func (cstr CStr) RunDaemon(logPath ...string) CStr {
return cstr.ExecDaemon(cstr.Str.String(), logPath...)
}
func (cstr CStr) Run(opts ...any) CStr {
return cstr.Exec(string(cstr.Str), opts...)
}
func (cstr CStr) Exec(cmd string, opts ...any) CStr {
// var cmd exec.Cmd
e := List[string]{}
if runtime.GOOS == "windows" {
e = append(e, "c:\\windows\\system32\\cmd.exe", "/c")
if cstr.delay > 0 {
e = append(e, fmt.Sprintf(`cd %s & ( ping -n %d localhost && %s )`, cstr.env["cwd"], cstr.delay, cmd))
// opts = append(opts, CSTR_INTERACT)
} else {
e = append(e, fmt.Sprintf("cd %s & %s", cstr.env["cwd"], cmd))
}
} else {
e = append(e, "bash", "-c")
if cstr.delay > 0 {
e = append(e, fmt.Sprintf("cd %s ; sleep %d ; %s", cstr.env["cwd"], cstr.delay, cmd))
} else {
e = append(e, fmt.Sprintf("cd %s ; %s", cstr.env["cwd"], cmd))
}
}
fmt.Println(e[0], e[1], e[2])
c := exec.Command(e[0], e[1:]...)
bufout := bytes.NewBuffer([]byte{})
errout := bytes.NewBuffer([]byte{})
stdInput := NewTmpRWer(100)
defer stdInput.Close()
Closed := false
mode := 0
expects := make(Dict[Str, Str])
expectStr := ""
var err error
if opts != nil {
setOut := false
for _, opt := range opts {
if optI, ok := opt.(int); ok {
mode |= optI
// fmt.Println("mode:", optI)
if optI&CSTR_INTERACT == CSTR_INTERACT {
c.Stdin = os.Stdin
// bytes.NewReader()
tee := io.MultiWriter(os.Stdout, bufout)
teeerr := io.MultiWriter(os.Stderr, errout)
c.Stdout = tee
c.Stderr = teeerr
setOut = true
break
} else if optI&CSTR_STDOUT == CSTR_STDOUT {
tee := io.MultiWriter(os.Stdout, bufout)
teeerr := io.MultiWriter(os.Stderr, errout)
c.Stdout = tee
c.Stderr = teeerr
setOut = true
}
} else if optS, ok := opt.(string); ok {
// Str(optS).Println("mode:")
if mode&CSTR_EXPECT == CSTR_EXPECT {
expectStr = optS
mode = mode ^ CSTR_EXPECT
} else if mode&CSTR_TYPE == CSTR_TYPE {
if expectStr != "" {
expects[Str(expectStr)] = Str(optS)
expectStr = ""
} else {
fmt.Println("simple")
c.Stdin = bytes.NewBuffer([]byte(optS))
}
mode = mode ^ CSTR_EXPECT
}
}
}
if !setOut {
tee := io.MultiWriter(bufout)
teeerr := io.MultiWriter(errout)
c.Stdout = tee
c.Stderr = teeerr
}
if len(expects) > 0 {
// tmpout := bytes.NewBuffer([]byte{})
// var tee io.Writer
// if mode&CSTR_STDOUT == CSTR_STDOUT {
tee := io.MultiWriter(os.Stdout, bufout)
// } else {
// tee = io.MultiWriter(tmpout, bufout)
// }
// c.Stdout = tee
c.Stdin = stdInput
tmpout, err := c.StdoutPipe()
if err != nil {
log.Fatal(err)
}
// lock.Add(1)
go func(expects Dict[Str, Str], closed *bool) {
// hit := 0
// tmpreader := bufio.NewReader(tmpout)
LOOP:
for {
// if tmpout.Len() > 0 {
linebuf := make([]byte, 1024)
// if tmpout.Len() > 0 {
n, err := tmpout.Read(linebuf)
if err != nil {
break LOOP
}
c := Str(linebuf[:n])
tee.Write(linebuf[:n])
// Str(c).Println("one:", expStr)
for _, line := range c.Split("\n") {
expects.Each(func(k, v Str) {
if line.ReMatch(k.String()) {
// k.ANSIUnderline().ANSIGreen().Println(line, " test ok type:", []byte(v))
stdInput.Write([]byte(v))
tee.Write([]byte(v))
// hit += 1
}
// } else {
// k.ANSISelected().ANSIUnderline().Println(line, "test failed:")
// }
})
}
}
stdInput.Close()
// fmt.Println("finished")
}(expects, &Closed)
}
// Str(input[0]).Print()
} else {
c.Stdout = bufout
c.Stderr = errout
// err = c.Run()
// var proc *os.Process
// proc, err = os.StartProcess(e[0], e[1:], &os.ProcAttr{
// Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
// })
// fmt.Println(proc.Pid)
}
// Str("wait ?").Println()
err = c.Run()
// tmpout.Close()
// lock.Wait()
Closed = true
// tmpout.Close()
if err != nil {
// log.Fatal("err cmd:", err)
cstr.history = cstr.history.Push(Str(cmd))
mmm, err := AutoEncodeToUTF8(errout.Bytes())
if err != nil {
fmt.Println("err:", err)
SafePush(&ErrStack, err)
}
cstr.outhistory = cstr.outhistory.Push(Str(mmm))
} else {
cstr.history = cstr.history.Push(Str(cmd))
mmm, err := AutoEncodeToUTF8(bufout.Bytes())
if err != nil {
log.Fatal(err, mmm)
SafePush(&ErrStack, err)
}
if errout.Len() > 0 {
mmm, err := AutoEncodeToUTF8(errout.Bytes())
if err != nil {
fmt.Println("err:", err)
SafePush(&ErrStack, err)
}
cstr.outhistory = cstr.outhistory.Push(Str(mmm))
}
cstr.outhistory = cstr.outhistory.Push(Str(mmm))
}
// Str("wait ok").Println()
return cstr
}
func (cstr CStr) Outputs() List[Str] {
return cstr.outhistory
}
func (cstr CStr) Histories() List[Str] {
return cstr.history
}
func (cstr CStr) Output(ix ...int) Str {
i := cstr.outhistory.Len() - 1
if ix != nil {
i = ix[0]
}
if i < 0 {
i = i + cstr.outhistory.Len()
}
return cstr.outhistory[i]
}
func (cstr CStr) History(ix ...int) Str {
i := cstr.history.Len() - 1
if ix != nil {
i = ix[0]
}
if i < 0 {
i = i + cstr.history.Len()
}
return cstr.history[i]
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/dark.H/go-utils.git
git@gitee.com:dark.H/go-utils.git
dark.H
go-utils
go-utils
v1.3.4

搜索帮助