2019-04-07 23:15:01 -05:00
|
|
|
package shell
|
|
|
|
|
2024-01-05 20:01:07 -06:00
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"io/ioutil"
|
2024-01-25 00:39:14 -06:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
"time"
|
2019-06-04 22:20:15 -05:00
|
|
|
|
2024-01-05 20:01:07 -06:00
|
|
|
"github.com/svent/go-nbreader"
|
2024-01-25 00:39:14 -06:00
|
|
|
"go.wit.com/log"
|
2024-01-05 20:01:07 -06:00
|
|
|
)
|
2019-04-07 23:15:01 -05:00
|
|
|
|
2019-06-09 16:29:50 -05:00
|
|
|
// TODO: look at https://github.com/go-cmd/cmd/issues/20
|
|
|
|
// use go-cmd instead here?
|
|
|
|
|
2019-06-06 11:34:47 -05:00
|
|
|
var callback func(interface{}, int)
|
|
|
|
|
2019-05-09 17:20:26 -05:00
|
|
|
var shellStdout *os.File
|
|
|
|
var shellStderr *os.File
|
|
|
|
|
2024-01-25 00:39:14 -06:00
|
|
|
var spewOn bool = false
|
|
|
|
var quiet bool = false
|
|
|
|
|
2019-06-16 12:49:01 -05:00
|
|
|
// var msecDelay int = 20 // number of milliseconds to delay between reads with no data
|
2019-05-09 19:24:25 -05:00
|
|
|
|
2019-06-16 12:49:01 -05:00
|
|
|
// var bytesBuffer bytes.Buffer
|
|
|
|
// var bytesSplice []byte
|
2019-06-04 22:20:15 -05:00
|
|
|
|
2019-06-06 18:12:59 -05:00
|
|
|
func handleError(c interface{}, ret int) {
|
2024-01-05 20:01:07 -06:00
|
|
|
log.Log(INFO, "shell.Run() Returned", ret)
|
2024-01-25 00:39:14 -06:00
|
|
|
if callback != nil {
|
2019-06-06 18:15:31 -05:00
|
|
|
callback(c, ret)
|
|
|
|
}
|
2019-06-06 11:34:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2024-01-25 00:39:14 -06:00
|
|
|
callback = nil
|
2019-06-06 11:34:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func InitCallback(f func(interface{}, int)) {
|
|
|
|
callback = f
|
|
|
|
}
|
|
|
|
|
2019-06-07 02:36:46 -05:00
|
|
|
// this means it won't copy all the output to STDOUT
|
2019-06-07 03:15:37 -05:00
|
|
|
func Quiet(q bool) {
|
|
|
|
quiet = q
|
2019-06-07 02:36:46 -05:00
|
|
|
}
|
|
|
|
|
2019-04-07 23:15:01 -05:00
|
|
|
func Script(cmds string) int {
|
|
|
|
// 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")
|
|
|
|
|
|
|
|
for _, line := range lines {
|
2019-06-06 17:59:49 -05:00
|
|
|
line = Chomp(line) // this is like 'chomp' in perl
|
2024-01-05 20:01:07 -06:00
|
|
|
log.Log(INFO, "LINE:", line)
|
2019-04-07 23:15:01 -05:00
|
|
|
time.Sleep(1)
|
2024-02-10 16:31:19 -06:00
|
|
|
RunString(line)
|
2019-04-07 23:15:01 -05:00
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2019-05-09 19:24:25 -05:00
|
|
|
func SpewOn() {
|
|
|
|
spewOn = true
|
|
|
|
}
|
|
|
|
|
2019-05-09 20:54:36 -05:00
|
|
|
func SetDelayInMsec(msecs int) {
|
|
|
|
msecDelay = msecs
|
|
|
|
}
|
|
|
|
|
2019-05-09 17:20:26 -05:00
|
|
|
func SetStdout(newout *os.File) {
|
|
|
|
shellStdout = newout
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetStderr(newerr *os.File) {
|
|
|
|
shellStderr = newerr
|
|
|
|
}
|
|
|
|
|
2019-06-16 15:35:32 -05:00
|
|
|
func Unlink(filename string) {
|
|
|
|
os.Remove(Path(filename))
|
|
|
|
}
|
|
|
|
|
|
|
|
func RM(filename string) {
|
|
|
|
os.Remove(Path(filename))
|
|
|
|
}
|
|
|
|
|
2019-06-16 12:49:01 -05:00
|
|
|
/*
|
2019-04-07 23:15:01 -05:00
|
|
|
err := process.Wait()
|
|
|
|
|
|
|
|
if err != nil {
|
2019-05-09 19:24:25 -05:00
|
|
|
if (spewOn) {
|
2019-06-05 03:28:15 -05:00
|
|
|
// this panics: spew.Dump(err.(*exec.ExitError))
|
2019-05-09 19:24:25 -05:00
|
|
|
spew.Dump(process.ProcessState)
|
|
|
|
}
|
2019-06-05 03:28:15 -05:00
|
|
|
// stuff := err.(*exec.ExitError)
|
2024-01-05 20:01:07 -06:00
|
|
|
log.Log(INFO, "ERROR ", err.Error())
|
|
|
|
log.Log(INFO, "END ", cmdline)
|
2019-06-06 18:12:59 -05:00
|
|
|
handleError(err, -1)
|
2019-06-06 15:02:16 -05:00
|
|
|
return ""
|
2019-06-16 12:49:01 -05:00
|
|
|
*/
|
2019-04-08 18:43:49 -05:00
|
|
|
|
|
|
|
func Daemon(cmdline string, timeout time.Duration) int {
|
|
|
|
for {
|
2024-02-10 16:31:19 -06:00
|
|
|
RunString(cmdline)
|
2019-04-08 18:43:49 -05:00
|
|
|
time.Sleep(timeout)
|
|
|
|
}
|
|
|
|
}
|
2019-05-09 20:54:36 -05:00
|
|
|
|
|
|
|
// pass in two file handles (1 read, 1 write)
|
2019-06-07 11:14:21 -05:00
|
|
|
func nonBlockingReader(buffReader *bufio.Reader, writeFileHandle *os.File, stdout *bufio.Writer) {
|
2019-05-09 20:54:36 -05:00
|
|
|
// newreader := bufio.NewReader(readFileHandle)
|
|
|
|
|
|
|
|
// create a nonblocking GO reader
|
2024-01-25 00:39:14 -06:00
|
|
|
nbr := nbreader.NewNBReader(buffReader, 1024)
|
2019-05-09 20:54:36 -05:00
|
|
|
|
|
|
|
for {
|
|
|
|
// defer buffReader.Close()
|
|
|
|
// defer writeFileHandle.Flush()
|
|
|
|
defer writeFileHandle.Close()
|
|
|
|
totalCount := 0
|
|
|
|
for {
|
|
|
|
oneByte := make([]byte, 1024)
|
|
|
|
count, err := nbr.Read(oneByte)
|
2024-01-25 00:39:14 -06:00
|
|
|
if err != nil {
|
2024-01-05 20:01:07 -06:00
|
|
|
log.Log(INFO, "count, err =", count, err)
|
2019-06-06 18:12:59 -05:00
|
|
|
handleError(err, -1)
|
2019-05-09 20:54:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
totalCount += count
|
2024-01-25 00:39:14 -06:00
|
|
|
if count == 0 {
|
|
|
|
time.Sleep(time.Duration(msecDelay) * time.Millisecond) // without this delay this will peg the CPU
|
|
|
|
if totalCount != 0 {
|
2024-01-05 20:01:07 -06:00
|
|
|
log.Log(INFO, "STDERR: totalCount = ", totalCount)
|
2019-05-09 20:54:36 -05:00
|
|
|
totalCount = 0
|
|
|
|
}
|
2019-05-09 21:46:27 -05:00
|
|
|
} else {
|
2024-01-05 20:01:07 -06:00
|
|
|
log.Log(INFO, "STDERR: count = ", count)
|
2019-05-09 21:46:27 -05:00
|
|
|
writeFileHandle.Write(oneByte[0:count])
|
2024-01-25 00:39:14 -06:00
|
|
|
if quiet == false {
|
2019-06-07 11:14:21 -05:00
|
|
|
stdout.Write(oneByte[0:count])
|
|
|
|
stdout.Flush()
|
|
|
|
}
|
2019-05-09 20:54:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-09 16:29:50 -05:00
|
|
|
|
|
|
|
// run something and never return from it
|
|
|
|
// TODO: pass STDOUT, STDERR, STDIN correctly
|
|
|
|
// TODO: figure out how to nohup the process and exit
|
|
|
|
func Exec(cmdline string) {
|
2024-01-25 00:39:14 -06:00
|
|
|
log.Log(INFO, "shell.Run() START "+cmdline)
|
2019-06-09 16:29:50 -05:00
|
|
|
|
2024-01-25 00:39:14 -06:00
|
|
|
cmd := Chomp(cmdline) // this is like 'chomp' in perl
|
|
|
|
cmdArgs := strings.Fields(cmd)
|
2019-06-09 16:29:50 -05:00
|
|
|
|
2024-01-25 00:39:14 -06:00
|
|
|
process := exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
|
|
|
|
process.Stderr = os.Stderr
|
|
|
|
process.Stdin = os.Stdin
|
|
|
|
process.Stdout = os.Stdout
|
2019-06-09 16:29:50 -05:00
|
|
|
process.Start()
|
|
|
|
err := process.Wait()
|
2024-01-05 20:01:07 -06:00
|
|
|
log.Log(INFO, "shell.Exec() err =", err)
|
2019-06-09 16:29:50 -05:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
2019-06-13 22:26:04 -05:00
|
|
|
|
2019-06-14 21:05:17 -05:00
|
|
|
// return true if the filename exists (cross-platform)
|
2019-06-13 22:26:04 -05:00
|
|
|
func Exists(filename string) bool {
|
2019-06-14 21:05:17 -05:00
|
|
|
_, err := os.Stat(Path(filename))
|
2019-06-13 22:26:04 -05:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-02-10 16:31:19 -06:00
|
|
|
// makes the directory
|
|
|
|
func Mkdir(dir string) bool {
|
|
|
|
if Dir(dir) {
|
|
|
|
// already a dir
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if Exists(dir) {
|
|
|
|
// something else is there
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
Run([]string{"mkdir", "-p", dir})
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2024-02-22 15:29:58 -06:00
|
|
|
func IsDir(dirname string) bool {
|
|
|
|
return Dir(dirname)
|
|
|
|
}
|
|
|
|
|
2019-06-14 21:05:17 -05:00
|
|
|
// return true if the filename exists (cross-platform)
|
2019-06-13 22:26:04 -05:00
|
|
|
func Dir(dirname string) bool {
|
2019-06-14 21:05:17 -05:00
|
|
|
info, err := os.Stat(Path(dirname))
|
2019-06-13 22:26:04 -05:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return info.IsDir()
|
|
|
|
}
|
2019-06-14 21:05:17 -05:00
|
|
|
|
|
|
|
// Cat a file into a string
|
|
|
|
func Cat(filename string) string {
|
|
|
|
buffer, err := ioutil.ReadFile(Path(filename))
|
2024-01-05 20:01:07 -06:00
|
|
|
// log.Log(INFO, "buffer =", string(buffer))
|
2019-06-14 21:05:17 -05:00
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return Chomp(buffer)
|
|
|
|
}
|