Compare commits
7 Commits
7048640de6
...
7e68be7419
Author | SHA1 | Date |
---|---|---|
Jeff Carr | 7e68be7419 | |
Jeff Carr | 78c7f261f4 | |
Jeff Carr | 59c9bf88ca | |
Jeff Carr | 954470c34c | |
Jeff Carr | 8a5c9922e4 | |
Jeff Carr | f1d7a816be | |
Jeff Carr | 026c59bc5c |
|
@ -0,0 +1 @@
|
||||||
|
example1/example1
|
|
@ -0,0 +1,3 @@
|
||||||
|
all:
|
||||||
|
go build
|
||||||
|
./example1
|
|
@ -0,0 +1,44 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
import "log"
|
||||||
|
import "reflect"
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
// import "github.com/davecgh/go-spew/spew"
|
||||||
|
|
||||||
|
import "git.wit.com/wit/shell"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
shell.Run("ls /tmp")
|
||||||
|
|
||||||
|
shell.Run("ping -c 3 localhost")
|
||||||
|
|
||||||
|
// slow down the polling to every 2 seconds
|
||||||
|
shell.SetDelayInMsec(2000)
|
||||||
|
|
||||||
|
shell.Run("ping -c 4 localhost")
|
||||||
|
|
||||||
|
// capture ping output into a file
|
||||||
|
fout, _ := os.Create("/tmp/example1.ping.stdout")
|
||||||
|
ferr, _ := os.Create("/tmp/example1.ping.stderr")
|
||||||
|
shell.SetStdout(fout)
|
||||||
|
shell.SetStderr(ferr)
|
||||||
|
|
||||||
|
shell.Run("ping -c 5 localhost")
|
||||||
|
|
||||||
|
// turn out process exit debugging
|
||||||
|
shell.SpewOn()
|
||||||
|
|
||||||
|
fout, _ = os.Create("/tmp/example1.fail.stdout")
|
||||||
|
ferr, _ = os.Create("/tmp/example1.fail.stderr")
|
||||||
|
shell.SetStdout(fout)
|
||||||
|
shell.SetStderr(ferr)
|
||||||
|
|
||||||
|
// TODO: this might not be working
|
||||||
|
// check error handling
|
||||||
|
shell.Run("ls /tmpthisisnothere")
|
||||||
|
}
|
149
shell.go
149
shell.go
|
@ -1,7 +1,6 @@
|
||||||
package shell
|
package shell
|
||||||
|
|
||||||
import "fmt"
|
// import "log"
|
||||||
import "log"
|
|
||||||
import "strings"
|
import "strings"
|
||||||
import "time"
|
import "time"
|
||||||
import "os"
|
import "os"
|
||||||
|
@ -10,19 +9,50 @@ import "bufio"
|
||||||
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 "github.com/sirupsen/logrus"
|
||||||
|
// import "github.com/wercker/journalhook"
|
||||||
|
|
||||||
|
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 {
|
func Script(cmds string) int {
|
||||||
// split on new lines (while we are at it, handle stupid windows text files
|
// split on new lines (while we are at it, handle stupid windows text files
|
||||||
lines := strings.Split(strings.Replace(cmds, "\r\n", "\n", -1), "\n")
|
lines := strings.Split(strings.Replace(cmds, "\r\n", "\n", -1), "\n")
|
||||||
|
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
line = strings.TrimSpace(line) // this is like 'chomp' in perl
|
line = strings.TrimSpace(line) // this is like 'chomp' in perl
|
||||||
fmt.Println("LINE:", line)
|
log.Println("LINE:", line)
|
||||||
time.Sleep(1)
|
time.Sleep(1)
|
||||||
Run(line)
|
Run(line)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func UseJournalctl() {
|
||||||
|
journalhook.Enable()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func SpewOn() {
|
||||||
|
spewOn = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDelayInMsec(msecs int) {
|
||||||
|
msecDelay = msecs
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetStdout(newout *os.File) {
|
||||||
|
shellStdout = newout
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetStderr(newerr *os.File) {
|
||||||
|
shellStderr = newerr
|
||||||
|
}
|
||||||
|
|
||||||
func Run(cmdline string) int {
|
func Run(cmdline string) int {
|
||||||
log.Println("START " + cmdline)
|
log.Println("START " + cmdline)
|
||||||
|
|
||||||
|
@ -42,71 +72,74 @@ func Run(cmdline string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
process := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
|
process := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
|
||||||
stdout, _ := process.StdoutPipe()
|
pstdout, _ := process.StdoutPipe()
|
||||||
stderr, _ := process.StderrPipe()
|
pstderr, _ := process.StderrPipe()
|
||||||
|
|
||||||
|
if (spewOn) {
|
||||||
|
spew.Dump(pstdout)
|
||||||
|
}
|
||||||
|
|
||||||
process.Start()
|
process.Start()
|
||||||
|
|
||||||
f := bufio.NewWriter(os.Stdout)
|
if (shellStdout == nil) {
|
||||||
|
shellStdout = os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
newreader := bufio.NewReader(stdout)
|
f := bufio.NewWriter(shellStdout)
|
||||||
|
|
||||||
|
newreader := bufio.NewReader(pstdout)
|
||||||
nbr := nbreader.NewNBReader(newreader, 1024)
|
nbr := nbreader.NewNBReader(newreader, 1024)
|
||||||
|
|
||||||
newerrreader := bufio.NewReader(stderr)
|
tmp := bufio.NewReader(pstderr)
|
||||||
nbrerr := nbreader.NewNBReader(newerrreader, 1024)
|
go NonBlockingReader(tmp, shellStderr)
|
||||||
|
|
||||||
for {
|
totalCount := 0
|
||||||
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")
|
// log.Println("sleep done")
|
||||||
|
|
||||||
|
var empty bool = false
|
||||||
|
// tight loop that reads 1K at a time until buffer is empty
|
||||||
|
for (empty == false) {
|
||||||
oneByte := make([]byte, 1024)
|
oneByte := make([]byte, 1024)
|
||||||
count, err := nbr.Read(oneByte)
|
count, err := nbr.Read(oneByte)
|
||||||
|
totalCount += count
|
||||||
|
|
||||||
if (err != nil) {
|
if (err != nil) {
|
||||||
// log.Println("Read() count = ", count, "err = ", err)
|
log.Println("Read() count = ", count, "err = ", err)
|
||||||
oneByte = make([]byte, 1024)
|
oneByte = make([]byte, 1024)
|
||||||
count, err = nbr.Read(oneByte)
|
count, err = nbr.Read(oneByte)
|
||||||
f.Write([]byte(string(oneByte)))
|
log.Println("STDOUT: count = ", count)
|
||||||
|
f.Write(oneByte[0:count])
|
||||||
f.Flush()
|
f.Flush()
|
||||||
|
empty = true
|
||||||
|
dead = true
|
||||||
}
|
}
|
||||||
f.Write([]byte(string(oneByte)))
|
// f.Write([]byte(string(oneByte)))
|
||||||
f.Flush()
|
if (count == 0) {
|
||||||
|
empty = true
|
||||||
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 {
|
|
||||||
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 {
|
} else {
|
||||||
f.Write([]byte(string(oneByte)))
|
log.Println("STDOUT: count = ", count)
|
||||||
|
f.Write(oneByte[0:count])
|
||||||
f.Flush()
|
f.Flush()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// spew.Dump(reflect.ValueOf(cmd.Process).Elem())
|
if (totalCount != 0) {
|
||||||
|
log.Println("STDOUT: totalCount = ", totalCount)
|
||||||
|
totalCount = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := process.Wait()
|
err := process.Wait()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if (spewOn) {
|
||||||
spew.Dump(err.(*exec.ExitError))
|
spew.Dump(err.(*exec.ExitError))
|
||||||
spew.Dump(process.ProcessState)
|
spew.Dump(process.ProcessState)
|
||||||
|
}
|
||||||
stuff := err.(*exec.ExitError)
|
stuff := err.(*exec.ExitError)
|
||||||
log.Println("ERROR ", stuff)
|
log.Println("ERROR ", stuff)
|
||||||
log.Println("END ", cmdline)
|
log.Println("END ", cmdline)
|
||||||
|
@ -122,3 +155,37 @@ func Daemon(cmdline string, timeout time.Duration) int {
|
||||||
time.Sleep(timeout)
|
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
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("STDERR: count = ", count)
|
||||||
|
writeFileHandle.Write(oneByte[0:count])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue