|
|
|
@ -9,6 +9,7 @@ import (
|
|
|
|
|
"os/exec"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync"
|
|
|
|
|
"sync/atomic"
|
|
|
|
|
"syscall"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
@ -20,8 +21,7 @@ type StarCmd struct {
|
|
|
|
|
outfile io.ReadCloser
|
|
|
|
|
infile io.WriteCloser
|
|
|
|
|
errfile io.ReadCloser
|
|
|
|
|
running bool
|
|
|
|
|
runningChan chan int
|
|
|
|
|
running int32
|
|
|
|
|
//Store AlL of the Standed Outputs
|
|
|
|
|
stdout []byte
|
|
|
|
|
//Store All of the Standed Errors
|
|
|
|
@ -42,11 +42,10 @@ type StarCmd struct {
|
|
|
|
|
func Command(command string, args ...string) (*StarCmd, error) {
|
|
|
|
|
var err error
|
|
|
|
|
shell := new(StarCmd)
|
|
|
|
|
shell.running = false
|
|
|
|
|
shell.running = 0
|
|
|
|
|
shell.prewritetime = time.Millisecond * 200
|
|
|
|
|
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
|
|
|
|
|
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
|
|
|
|
|
shell.runningChan = make(chan int, 3)
|
|
|
|
|
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
|
|
|
|
|
cmd := exec.Command(command, args...)
|
|
|
|
|
shell.CMD = cmd
|
|
|
|
@ -69,10 +68,9 @@ func Command(command string, args ...string) (*StarCmd, error) {
|
|
|
|
|
func CommandContext(ctx context.Context, command string, args ...string) (*StarCmd, error) {
|
|
|
|
|
var err error
|
|
|
|
|
shell := new(StarCmd)
|
|
|
|
|
shell.running = false
|
|
|
|
|
shell.running = 0
|
|
|
|
|
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
|
|
|
|
|
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
|
|
|
|
|
shell.runningChan = make(chan int, 3)
|
|
|
|
|
shell.prewritetime = time.Millisecond * 200
|
|
|
|
|
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
|
|
|
|
|
cmd := exec.CommandContext(ctx, command, args...)
|
|
|
|
@ -95,7 +93,7 @@ func CommandContext(ctx context.Context, command string, args ...string) (*StarC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (starcli *StarCmd) queryStdout(ctx context.Context) {
|
|
|
|
|
for starcli.running && starcli.CMD != nil {
|
|
|
|
|
for starcli.IsRunning() && starcli.CMD != nil {
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return
|
|
|
|
@ -115,7 +113,7 @@ func (starcli *StarCmd) queryStdout(ctx context.Context) {
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
} else {
|
|
|
|
|
if !strings.Contains(err.Error(),"file already closed") {
|
|
|
|
|
if !strings.Contains(err.Error(), "file already closed") {
|
|
|
|
|
starcli.runerr = err
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@ -125,7 +123,7 @@ func (starcli *StarCmd) queryStdout(ctx context.Context) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (starcli *StarCmd) queryStderr(ctx context.Context) {
|
|
|
|
|
for starcli.running && starcli.CMD != nil {
|
|
|
|
|
for starcli.IsRunning() && starcli.CMD != nil {
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return
|
|
|
|
@ -145,7 +143,7 @@ func (starcli *StarCmd) queryStderr(ctx context.Context) {
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
} else {
|
|
|
|
|
if !strings.Contains(err.Error(),"file already closed") {
|
|
|
|
|
if !strings.Contains(err.Error(), "file already closed") {
|
|
|
|
|
starcli.runerr = err
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
@ -247,20 +245,38 @@ func (starcli *StarCmd) AllStdErr() error {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (starcli *StarCmd) setRunning(alive bool) {
|
|
|
|
|
if alive {
|
|
|
|
|
val := atomic.LoadInt32(&starcli.running)
|
|
|
|
|
if val == 0 {
|
|
|
|
|
atomic.AddInt32(&starcli.running, 1)
|
|
|
|
|
} else {
|
|
|
|
|
atomic.AddInt32(&starcli.running, 1-val)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
val := atomic.LoadInt32(&starcli.running)
|
|
|
|
|
if val == 1 {
|
|
|
|
|
atomic.AddInt32(&starcli.running, -1)
|
|
|
|
|
} else {
|
|
|
|
|
atomic.AddInt32(&starcli.running, -val)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
func (starcli *StarCmd) Start() error {
|
|
|
|
|
if err := starcli.CMD.Start(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
starcli.running = true
|
|
|
|
|
starcli.setRunning(true)
|
|
|
|
|
go func() {
|
|
|
|
|
err := starcli.CMD.Wait()
|
|
|
|
|
if err != nil {
|
|
|
|
|
starcli.runerr = err
|
|
|
|
|
}
|
|
|
|
|
starcli.stopctxfunc()
|
|
|
|
|
starcli.running = false
|
|
|
|
|
starcli.setRunning(false)
|
|
|
|
|
if starcli.CMD.ProcessState != nil {
|
|
|
|
|
starcli.exitcode = starcli.CMD.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
|
|
|
|
starcli.runningChan <- 1
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
go starcli.queryStdout(starcli.stopctx)
|
|
|
|
|
go starcli.queryStderr(starcli.stopctx)
|
|
|
|
@ -282,11 +298,11 @@ func (starcli *StarCmd) Start() error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (starcli *StarCmd) IsRunning() bool {
|
|
|
|
|
return starcli.running
|
|
|
|
|
return 0 != atomic.LoadInt32(&starcli.running)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (starcli *StarCmd) Stoped() <-chan int {
|
|
|
|
|
return starcli.runningChan
|
|
|
|
|
func (starcli *StarCmd) Stoped() <-chan struct{} {
|
|
|
|
|
return starcli.stopctx.Done()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (starcli *StarCmd) Exec(cmd string, wait int) (string, error) {
|
|
|
|
@ -313,12 +329,12 @@ func (starcli *StarCmd) ExitCode() int {
|
|
|
|
|
return starcli.exitcode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (starcli *StarCmd) Kill() error{
|
|
|
|
|
err:=starcli.CMD.Process.Kill()
|
|
|
|
|
if err!=nil{
|
|
|
|
|
func (starcli *StarCmd) Kill() error {
|
|
|
|
|
err := starcli.CMD.Process.Kill()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
starcli.running = false
|
|
|
|
|
starcli.setRunning(false)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|