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 // captures the output so you can not see the command run in real time 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 // also does not seem to show the output in realtime 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 }