shell/run.go

252 lines
5.6 KiB
Go

package shell
import (
"errors"
"os"
"os/exec"
"strings"
"syscall"
"go.wit.com/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)
// run command and return it's output
/*
func RunCapture(cmdline string) string {
test := New()
test.Exec(cmdline)
return Chomp(test.Buffer)
}
func RunWait(args []string) *OldShell {
test := New()
cmdline := strings.Join(args, " ")
test.Exec(cmdline)
return test
}
*/
// var newfile *shell.File
func RunString(args string) bool {
// return false
parts := strings.Split(args, " ")
return Run(parts)
}
func Run(args []string) bool {
dir, err := os.Getwd()
if err != nil {
return false
}
r := RunPath(dir, args)
if r.Ok {
return true
}
return false
}
var ErrorArgvEmpty error = errors.New("command was empty")
type RunResult struct {
Ok bool
Argv []string
Path string
Output []byte
Err error
Outerr error
}
// run, but set the working path
func RunPath(path string, args []string) *RunResult {
r := new(RunResult)
r.Path = path
r.Argv = args
if len(args) == 0 {
r.Ok = true
r.Err = ErrorArgvEmpty
return r
}
if args[0] == "" {
r.Ok = false
r.Err = ErrorArgvEmpty
return r
}
thing := args[0]
parts := args[1:]
cmd := exec.Command(thing, parts...)
cmd.Dir = path
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Info("path =", path, "cmd =", strings.Join(args, " "))
if err := cmd.Run(); err != nil {
// Handle error if the command execution fails
// log.Info("RunPath() failed")
// log.Info("cmd.Enviorn =", cmd.Environ())
out, outerr := cmd.Output()
// log.Info("cmd.output =", out)
// log.Info("cmd.output err=", outerr)
// log.Info("path =", path)
// log.Info("args =", args)
// log.Info("err =", err.Error())
r.Ok = false
r.Err = err
r.Output = out
r.Outerr = outerr
return r
}
out, outerr := cmd.Output()
r.Output = out
r.Outerr = outerr
r.Ok = true
return r
}
// send the path and the command
func RunCmd(workingpath string, parts []string) (error, bool, string) {
if len(parts) == 0 {
log.Warn("command line was empty")
return errors.New("empty"), false, ""
}
if parts[0] == "" {
log.Warn("command line was empty")
return errors.New("empty"), false, ""
}
thing := parts[0]
parts = parts[1:]
log.Log(INFO, "working path =", workingpath, "thing =", thing, "cmdline =", parts)
// Create the command
cmd := exec.Command(thing, parts...)
// Set the working directory
cmd.Dir = workingpath
// Execute the command
output, err := cmd.CombinedOutput()
if err != nil {
if thing == "git" {
log.Log(INFO, "git ERROR. maybe okay", workingpath, "thing =", thing, "cmdline =", parts)
log.Log(INFO, "git ERROR. maybe okay err =", err)
if err.Error() == "exit status 1" {
log.Log(INFO, "git ERROR. normal exit status 1")
if parts[0] == "diff-index" {
log.Log(INFO, "git normal diff-index when repo dirty")
return nil, false, "git diff-index exit status 1"
}
}
}
log.Warn("ERROR working path =", workingpath, "thing =", thing, "cmdline =", parts)
log.Warn("ERROR working path =", workingpath, "thing =", thing, "cmdline =", parts)
log.Warn("ERROR working path =", workingpath, "thing =", thing, "cmdline =", parts)
log.Error(err)
log.Warn("output was", string(output))
log.Warn("cmd exited with error", err)
// panic("fucknuts")
// The command failed (non-zero exit status)
if exitErr, ok := err.(*exec.ExitError); ok {
// Assert that it is an exec.ExitError and get the exit code
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
log.Warn("Exit Status: %d\n", status.ExitStatus())
}
} else {
log.Warn("cmd.Run() failed with %s\n", err)
}
return err, false, string(output)
}
tmp := string(output)
tmp = strings.TrimSpace(tmp)
// Print the output
return nil, true, tmp
}
// send the path and the command
func RunCmdRun(workingpath string, parts []string) error {
if len(parts) == 0 {
log.Warn("command line was empty")
return errors.New("empty")
}
if parts[0] == "" {
log.Warn("command line was empty")
return errors.New("empty")
}
thing := parts[0]
parts = parts[1:]
log.Log(INFO, "working path =", workingpath, "thing =", thing, "cmdline =", parts)
// Create the command
cmd := exec.Command(thing, parts...)
// Set the working directory
cmd.Dir = workingpath
// Execute the command
err := cmd.Run()
if err != nil {
log.Warn("ERROR working path =", workingpath, "thing =", thing, "cmdline =", parts)
log.Error(err)
log.Warn("cmd exited with error", err)
// panic("fucknuts")
// The command failed (non-zero exit status)
if exitErr, ok := err.(*exec.ExitError); ok {
// Assert that it is an exec.ExitError and get the exit code
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
log.Warn("Exit Status: %d\n", status.ExitStatus())
}
} else {
log.Warn("cmd.Run() failed with %s\n", err)
}
return err
}
return nil
}
func (r *RunResult) Stdout() string {
return string(r.Output)
}
// run, but set the working path
func Output(path string, args []string) *RunResult {
r := new(RunResult)
r.Path = path
r.Argv = args
if len(args) == 0 {
r.Ok = true
r.Err = ErrorArgvEmpty
return r
}
if args[0] == "" {
r.Ok = false
r.Err = ErrorArgvEmpty
return r
}
thing := args[0]
parts := args[1:]
cmd := exec.Command(thing, parts...)
cmd.Dir = path
output, err := cmd.CombinedOutput()
if err := cmd.Run(); err != nil {
r.Ok = false
r.Err = err
r.Output = output
return r
}
r.Output = output
r.Err = err
r.Ok = true
return r
}