smarter go syntax for Run()
Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
parent
3fadcf18a6
commit
30d3fe09b5
|
@ -0,0 +1,179 @@
|
||||||
|
package shell
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
import "time"
|
||||||
|
import "os/exec"
|
||||||
|
import "bytes"
|
||||||
|
import "io"
|
||||||
|
import "fmt"
|
||||||
|
import "os"
|
||||||
|
import "bufio"
|
||||||
|
import "github.com/svent/go-nbreader"
|
||||||
|
|
||||||
|
import "git.wit.com/wit/log"
|
||||||
|
|
||||||
|
var msecDelay int = 20 // check every 20 milliseconds
|
||||||
|
|
||||||
|
// TODO: look at https://github.com/go-cmd/cmd/issues/20
|
||||||
|
// use go-cmd instead here?
|
||||||
|
// exiterr.Sys().(syscall.WaitStatus)
|
||||||
|
|
||||||
|
// var newfile *shell.File
|
||||||
|
|
||||||
|
func Run(cmdline string) string {
|
||||||
|
test := New()
|
||||||
|
test.Exec(cmdline)
|
||||||
|
return Chomp(test.Buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *Shell) Run(cmdline string) string {
|
||||||
|
cmd.InitProcess(cmdline)
|
||||||
|
if (cmd.Error != nil) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
cmd.Exec(cmdline)
|
||||||
|
return Chomp(cmd.Buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *Shell) InitProcess(cmdline string) {
|
||||||
|
log.Println("shell.InitProcess() START " + cmdline)
|
||||||
|
|
||||||
|
cmd.Cmdline = Chomp(cmdline) // this is like 'chomp' in perl
|
||||||
|
cmdArgs := strings.Fields(cmd.Cmdline)
|
||||||
|
if (len(cmdArgs) == 0) {
|
||||||
|
cmd.Error = fmt.Errorf("cmdline == ''")
|
||||||
|
cmd.Done = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (cmdArgs[0] == "cd") {
|
||||||
|
if (len(cmdArgs) > 1) {
|
||||||
|
log.Println("os.Chdir()", cmd)
|
||||||
|
os.Chdir(cmdArgs[1])
|
||||||
|
}
|
||||||
|
handleError(nil, 0)
|
||||||
|
cmd.Done = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Process = exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *Shell) FileCreate(out string) {
|
||||||
|
var newfile File
|
||||||
|
|
||||||
|
var iof io.ReadCloser
|
||||||
|
if (out == "STDOUT") {
|
||||||
|
iof, _ = cmd.Process.StdoutPipe()
|
||||||
|
} else {
|
||||||
|
iof, _ = cmd.Process.StderrPipe()
|
||||||
|
}
|
||||||
|
|
||||||
|
newfile.Fio = iof
|
||||||
|
newfile.Fbufio = bufio.NewReader(iof)
|
||||||
|
newfile.Fnbreader = nbreader.NewNBReader(newfile.Fbufio, 1024)
|
||||||
|
|
||||||
|
if (out == "STDOUT") {
|
||||||
|
cmd.STDOUT = &newfile
|
||||||
|
} else {
|
||||||
|
cmd.STDERR = &newfile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: this might cause problems:
|
||||||
|
// always remove the newlines at the end ?
|
||||||
|
func (cmd *Shell) Exec(cmdline string) {
|
||||||
|
log.Println("shell.Run() START " + cmdline)
|
||||||
|
|
||||||
|
cmd.InitProcess(cmdline)
|
||||||
|
if (cmd.Error != nil) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.FileCreate("STDOUT")
|
||||||
|
cmd.FileCreate("STDERR")
|
||||||
|
|
||||||
|
cmd.Process.Start()
|
||||||
|
|
||||||
|
// TODO; 'goroutine' both of these
|
||||||
|
// and make your own wait that will make sure
|
||||||
|
// the process is then done and run process.Wait()
|
||||||
|
go cmd.Capture(cmd.STDERR)
|
||||||
|
cmd.Capture(cmd.STDOUT)
|
||||||
|
|
||||||
|
// wait until the process exists
|
||||||
|
// https://golang.org/pkg/os/exec/#Cmd.Wait
|
||||||
|
// What should happen here, before calling Wait()
|
||||||
|
// is checks to make sure the READERS() on STDOUT and STDERR are done
|
||||||
|
err := cmd.Process.Wait()
|
||||||
|
|
||||||
|
// time.Sleep(2 * time.Second) // putting this here doesn't help STDOUT flush()
|
||||||
|
|
||||||
|
if (err != nil) {
|
||||||
|
cmd.Error = err
|
||||||
|
log.Println("process.Wait() END err =", err.Error())
|
||||||
|
} else {
|
||||||
|
log.Println("process.Wait() END")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *Shell) Capture(f *File) {
|
||||||
|
log.Debugln("nbrREADER() START")
|
||||||
|
|
||||||
|
if (cmd.Buffer == nil) {
|
||||||
|
cmd.Buffer = new(bytes.Buffer)
|
||||||
|
}
|
||||||
|
if (cmd.Buffer == nil) {
|
||||||
|
log.Debugln("f.Buffer == nil")
|
||||||
|
log.Debugln("SHOULD DIE HERE")
|
||||||
|
f.Dead = false
|
||||||
|
cmd.Error = fmt.Errorf("could not make buffer")
|
||||||
|
cmd.Done = true
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Dead = false
|
||||||
|
|
||||||
|
// loop that keeps trying to read from f
|
||||||
|
for (f.Dead == false) {
|
||||||
|
time.Sleep(time.Duration(msecDelay) * time.Millisecond) // only check the buffer 500 times a second
|
||||||
|
|
||||||
|
// set to false so it keeps retrying reads
|
||||||
|
f.Empty = false
|
||||||
|
|
||||||
|
// tight loop that reads 1024 bytes at a time until buffer is empty
|
||||||
|
// 1024 is set in f.BufferSize
|
||||||
|
for (f.Empty == false) {
|
||||||
|
f.Empty = cmd.ReadToBuffer(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if filehandle buffer is empty
|
||||||
|
func (cmd *Shell) ReadToBuffer(f *File) bool {
|
||||||
|
// log.Debugln("ReadToBuffer() START")
|
||||||
|
nbr := f.Fnbreader
|
||||||
|
oneByte := make([]byte, 1024)
|
||||||
|
if (nbr == nil) {
|
||||||
|
// log.Debugln("ReadToBuffer() ERROR nbr is nil")
|
||||||
|
f.Dead = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
count, err := nbr.Read(oneByte)
|
||||||
|
f.TotalCount += count
|
||||||
|
|
||||||
|
if (err != nil) {
|
||||||
|
// log.Debugln("ReadToBuffer() file has closed with", err)
|
||||||
|
// log.Debugln("ReadToBuffer() count = ", count, "err = ", err)
|
||||||
|
f.Dead = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
// log.Debugln("ReadToBuffer() START count == 0 return true")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// log.Debugln("ReadToBuffer() count = ", count)
|
||||||
|
// tmp := Chomp(oneByte)
|
||||||
|
// log.Debugln("ReadToBuffer() tmp = ", tmp)
|
||||||
|
io.WriteString(cmd.Buffer, string(oneByte))
|
||||||
|
return false
|
||||||
|
}
|
17
shell.go
17
shell.go
|
@ -1,16 +1,13 @@
|
||||||
package shell
|
package shell
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
import "strings"
|
import "strings"
|
||||||
import "time"
|
import "time"
|
||||||
import "os"
|
import "os"
|
||||||
import "os/exec"
|
import "os/exec"
|
||||||
import "bufio"
|
import "bufio"
|
||||||
import "bytes"
|
|
||||||
import "io"
|
|
||||||
import "io/ioutil"
|
import "io/ioutil"
|
||||||
|
|
||||||
import "github.com/davecgh/go-spew/spew"
|
// import "github.com/davecgh/go-spew/spew"
|
||||||
import "github.com/svent/go-nbreader"
|
import "github.com/svent/go-nbreader"
|
||||||
|
|
||||||
// import "log"
|
// import "log"
|
||||||
|
@ -26,10 +23,10 @@ var shellStderr *os.File
|
||||||
|
|
||||||
var spewOn bool = false
|
var spewOn bool = false
|
||||||
var quiet bool = false
|
var quiet bool = false
|
||||||
var msecDelay int = 20 // number of milliseconds to delay between reads with no data
|
// var msecDelay int = 20 // number of milliseconds to delay between reads with no data
|
||||||
|
|
||||||
var bytesBuffer bytes.Buffer
|
// var bytesBuffer bytes.Buffer
|
||||||
var bytesSplice []byte
|
// var bytesSplice []byte
|
||||||
|
|
||||||
func handleError(c interface{}, ret int) {
|
func handleError(c interface{}, ret int) {
|
||||||
log.Debug("shell.Run() Returned", ret)
|
log.Debug("shell.Run() Returned", ret)
|
||||||
|
@ -39,7 +36,7 @@ func handleError(c interface{}, ret int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
callback = nil
|
callback = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitCallback(f func(interface{}, int)) {
|
func InitCallback(f func(interface{}, int)) {
|
||||||
|
@ -80,9 +77,10 @@ func SetStderr(newerr *os.File) {
|
||||||
shellStderr = newerr
|
shellStderr = newerr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// NOTE: this might cause problems:
|
// NOTE: this might cause problems:
|
||||||
// always remove the newlines at the end ?
|
// always remove the newlines at the end ?
|
||||||
func Run(cmdline string) string {
|
func OldRun(cmdline string) string {
|
||||||
log.Println("shell.Run() START " + cmdline)
|
log.Println("shell.Run() START " + cmdline)
|
||||||
|
|
||||||
cmd := Chomp(cmdline) // this is like 'chomp' in perl
|
cmd := Chomp(cmdline) // this is like 'chomp' in perl
|
||||||
|
@ -202,6 +200,7 @@ func Run(cmdline string) string {
|
||||||
log.Println("shell.Run() END ", cmdline)
|
log.Println("shell.Run() END ", cmdline)
|
||||||
return Chomp(b)
|
return Chomp(b)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func Daemon(cmdline string, timeout time.Duration) int {
|
func Daemon(cmdline string, timeout time.Duration) int {
|
||||||
for {
|
for {
|
||||||
|
|
41
structs.go
41
structs.go
|
@ -1,6 +1,7 @@
|
||||||
package shell
|
package shell
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
import "os/exec"
|
||||||
import "bufio"
|
import "bufio"
|
||||||
import "bytes"
|
import "bytes"
|
||||||
import "github.com/svent/go-nbreader"
|
import "github.com/svent/go-nbreader"
|
||||||
|
@ -9,6 +10,7 @@ var FileMap map[string]*File
|
||||||
|
|
||||||
var readBufferSize int
|
var readBufferSize int
|
||||||
|
|
||||||
|
/*
|
||||||
type File struct {
|
type File struct {
|
||||||
Name string
|
Name string
|
||||||
BufferSize int
|
BufferSize int
|
||||||
|
@ -22,7 +24,45 @@ type File struct {
|
||||||
Fbufio *bufio.Reader // := bufio.NewReader(pOUT)
|
Fbufio *bufio.Reader // := bufio.NewReader(pOUT)
|
||||||
Fnbreader *nbreader.NBReader // := nbreader.NewNBReader(readOUT, 1024)
|
Fnbreader *nbreader.NBReader // := nbreader.NewNBReader(readOUT, 1024)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
Name string
|
||||||
|
// BufferSize int
|
||||||
|
// Buffer *bytes.Buffer
|
||||||
|
// Fbytes []byte
|
||||||
|
TotalCount int
|
||||||
|
Empty bool
|
||||||
|
Dead bool
|
||||||
|
|
||||||
|
Fio io.ReadCloser // := process.StdoutPipe()
|
||||||
|
Fbufio *bufio.Reader // := bufio.NewReader(pOUT)
|
||||||
|
Fnbreader *nbreader.NBReader // := nbreader.NewNBReader(readOUT, 1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Shell struct {
|
||||||
|
Cmdline string
|
||||||
|
Process *exec.Cmd
|
||||||
|
Done bool
|
||||||
|
Quiet bool
|
||||||
|
Error error
|
||||||
|
Buffer *bytes.Buffer
|
||||||
|
|
||||||
|
// which names are really better here?
|
||||||
|
// for now I init them both to test out
|
||||||
|
// how the code looks and feels
|
||||||
|
STDOUT *File
|
||||||
|
STDERR *File
|
||||||
|
Stdout *File
|
||||||
|
Stderr *File
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Shell {
|
||||||
|
var tmp Shell
|
||||||
|
return &tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func FileCreate(f io.ReadCloser) *File {
|
func FileCreate(f io.ReadCloser) *File {
|
||||||
var newfile File
|
var newfile File
|
||||||
|
|
||||||
|
@ -32,3 +72,4 @@ func FileCreate(f io.ReadCloser) *File {
|
||||||
|
|
||||||
return &newfile
|
return &newfile
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
Loading…
Reference in New Issue