diff --git a/example1/Makefile b/example1/Makefile new file mode 100644 index 0000000..9fc318d --- /dev/null +++ b/example1/Makefile @@ -0,0 +1,3 @@ +all: + go build + ./example1 diff --git a/example1/example1 b/example1/example1 new file mode 100755 index 0000000..625385e Binary files /dev/null and b/example1/example1 differ diff --git a/example1/main.go b/example1/main.go new file mode 100644 index 0000000..4a36503 --- /dev/null +++ b/example1/main.go @@ -0,0 +1,27 @@ +package main + +/* +import "log" +import "reflect" +import "os" +*/ + +// import "github.com/davecgh/go-spew/spew" + +import "git.wit.com/jcarr/shell" + +func main() { + shell.SpewOn() + + shell.Run("ls /tmp") + + shell.Run("ping -c 4 localhost") + + // slow down the polling to every 2 seconds + shell.SetDelayInMsec(2000) + shell.Run("ping -c 4 localhost") + + // TODO: this might not be working + // check error handling + shell.Run("ls /tmpthisisnothere") +} diff --git a/shell.go b/shell.go index d9ee33f..bfdac21 100644 --- a/shell.go +++ b/shell.go @@ -16,6 +16,7 @@ var shellStdout *os.File var shellStderr *os.File var spewOn bool = false +var msecDelay int = 20 // number of milliseconds to delay between reads with no data func Script(cmds string) int { // split on new lines (while we are at it, handle stupid windows text files @@ -40,6 +41,10 @@ func SpewOn() { spewOn = true } +func SetDelayInMsec(msecs int) { + msecDelay = msecs +} + func SetStdout(newout *os.File) { shellStdout = newout } @@ -85,74 +90,45 @@ func Run(cmdline string) int { newreader := bufio.NewReader(pstdout) nbr := nbreader.NewNBReader(newreader, 1024) - newerrreader := bufio.NewReader(pstderr) - nbrerr := nbreader.NewNBReader(newerrreader, 1024) + // nbrerr := nbreader.NewNBReader(newerrreader, 1024) + + tmp := bufio.NewReader(pstderr) + go NonBlockingReader(tmp, shellStderr) totalCount := 0 - for { - time.Sleep(2 * time.Millisecond) // only check the buffer 500 times a second + var dead bool = false + for (dead == false) { + time.Sleep(time.Duration(msecDelay) * time.Millisecond) // only check the buffer 500 times a second // log.Println("sleep done") + var empty bool = false // tight loop that reads 1K at a time until buffer is empty - for { + for (empty == false) { oneByte := make([]byte, 1024) count, err := nbr.Read(oneByte) totalCount += count if (err != nil) { - // log.Println("Read() count = ", count, "err = ", err) + log.Println("Read() count = ", count, "err = ", err) oneByte = make([]byte, 1024) count, err = nbr.Read(oneByte) f.Write([]byte(string(oneByte))) f.Flush() + empty = true + dead = true } f.Write([]byte(string(oneByte))) f.Flush() if (count == 0) { - break + empty = true } } if (totalCount != 0) { - log.Println("totalCount = ", totalCount) + log.Println("STDOUT: totalCount = ", totalCount) + totalCount = 0 } - - // - // HANDLE STDERR - // HANDLE STDERR - // - oneByte := make([]byte, 1024) - count, err := nbrerr.Read(oneByte) - - if (err != nil) { - oneByte = make([]byte, 1024) - count, err = nbrerr.Read(oneByte) - f.Write([]byte(string(oneByte))) - f.Flush() - - log.Println("Read() count = ", count, "err = ", err) - // spew.Dump(process.Process) - // spew.Dump(process.ProcessState) - err := process.Wait() - if err != nil { - if (spewOn) { - spew.Dump(err.(*exec.ExitError)) - spew.Dump(process.ProcessState) - } - stuff := err.(*exec.ExitError) - log.Println("ERROR ", stuff) - log.Println("END ", cmdline) - return -1 - } - log.Println("END ", cmdline) - return 0 - } else { - f.Write([]byte(string(oneByte))) - f.Flush() - } - - // spew.Dump(reflect.ValueOf(cmd.Process).Elem()) } err := process.Wait() @@ -177,3 +153,35 @@ func Daemon(cmdline string, timeout time.Duration) int { time.Sleep(timeout) } } + +// pass in two file handles (1 read, 1 write) +func NonBlockingReader(buffReader *bufio.Reader, writeFileHandle *os.File) { + // newreader := bufio.NewReader(readFileHandle) + + // create a nonblocking GO reader + nbr := nbreader.NewNBReader(buffReader, 1024) + + for { + // defer buffReader.Close() + // defer writeFileHandle.Flush() + defer writeFileHandle.Close() + totalCount := 0 + for { + oneByte := make([]byte, 1024) + count, err := nbr.Read(oneByte) + if (err != nil) { + log.Println("count, err =", count, err) + return + } + totalCount += count + if (count == 0) { + time.Sleep(time.Duration(msecDelay) * time.Millisecond) // without this delay this will peg the CPU + if (totalCount != 0) { + log.Println("STDERR: totalCount = ", totalCount) + totalCount = 0 + } + } + writeFileHandle.Write([]byte(string(oneByte))) + } + } +}