summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2019-06-16 10:49:01 -0700
committerJeff Carr <[email protected]>2019-06-16 10:49:01 -0700
commit30d3fe09b5e7d117a3db260a6700d95d19a48367 (patch)
tree61114829d1c81acb03c7001a1029cf7f2d4a8593
parent3fadcf18a67fe6bc8e5037be4702a0781c5cad47 (diff)
smarter go syntax for Run()
Signed-off-by: Jeff Carr <[email protected]>
-rw-r--r--run.go179
-rw-r--r--shell.go17
-rw-r--r--structs.go41
3 files changed, 228 insertions, 9 deletions
diff --git a/run.go b/run.go
new file mode 100644
index 0000000..9b74bd3
--- /dev/null
+++ b/run.go
@@ -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
+}
diff --git a/shell.go b/shell.go
index 51f6378..2714e76 100644
--- a/shell.go
+++ b/shell.go
@@ -1,16 +1,13 @@
package shell
-import "fmt"
import "strings"
import "time"
import "os"
import "os/exec"
import "bufio"
-import "bytes"
-import "io"
import "io/ioutil"
-import "github.com/davecgh/go-spew/spew"
+// import "github.com/davecgh/go-spew/spew"
import "github.com/svent/go-nbreader"
// import "log"
@@ -26,10 +23,10 @@ var shellStderr *os.File
var spewOn 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 bytesSplice []byte
+// var bytesBuffer bytes.Buffer
+// var bytesSplice []byte
func handleError(c interface{}, ret int) {
log.Debug("shell.Run() Returned", ret)
@@ -39,7 +36,7 @@ func handleError(c interface{}, ret int) {
}
func init() {
- callback = nil
+ callback = nil
}
func InitCallback(f func(interface{}, int)) {
@@ -80,9 +77,10 @@ func SetStderr(newerr *os.File) {
shellStderr = newerr
}
+/*
// NOTE: this might cause problems:
// always remove the newlines at the end ?
-func Run(cmdline string) string {
+func OldRun(cmdline string) string {
log.Println("shell.Run() START " + cmdline)
cmd := Chomp(cmdline) // this is like 'chomp' in perl
@@ -202,6 +200,7 @@ func Run(cmdline string) string {
log.Println("shell.Run() END ", cmdline)
return Chomp(b)
}
+*/
func Daemon(cmdline string, timeout time.Duration) int {
for {
diff --git a/structs.go b/structs.go
index b5726e8..5f3df65 100644
--- a/structs.go
+++ b/structs.go
@@ -1,6 +1,7 @@
package shell
import "io"
+import "os/exec"
import "bufio"
import "bytes"
import "github.com/svent/go-nbreader"
@@ -9,6 +10,7 @@ var FileMap map[string]*File
var readBufferSize int
+/*
type File struct {
Name string
BufferSize int
@@ -22,7 +24,45 @@ type File struct {
Fbufio *bufio.Reader // := bufio.NewReader(pOUT)
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 {
var newfile File
@@ -32,3 +72,4 @@ func FileCreate(f io.ReadCloser) *File {
return &newfile
}
+*/