diff options
Diffstat (limited to 'run.go')
| -rw-r--r-- | run.go | 101 |
1 files changed, 101 insertions, 0 deletions
@@ -0,0 +1,101 @@ +package fhelp + +import ( + "errors" + "time" + + "github.com/go-cmd/cmd" + "go.wit.com/log" +) + +func RunRealtime(args []string) cmd.Status { + return PathRunRealtime("", args) +} + +// this is stuff from a long time ago that there must be a replacement for +func RemoveFirstElement(slice []string) (string, []string) { + if len(slice) == 0 { + return "", slice // Return the original slice if it's empty + } + return slice[0], slice[1:] // Return the slice without the first element +} + +// echos twice a second if anything sends to STDOUT or STDERR +// not great, but it's really just for watching things run in real time anyway +// TODO: fix \r handling for things like git-clone so the terminal doesn't +// have to do a \n newline each time. +// TODO: add timeouts and status of things hanging around forever +func PathRunRealtime(pwd string, args []string) cmd.Status { + // Check if the slice has at least one element (the command name) + if len(args) == 0 { + var s cmd.Status + s.Error = errors.New("Error: Command slice is empty.") + return s + } + + // Start a long-running process, capture stdout and stderr + a, b := RemoveFirstElement(args) + findCmd := cmd.NewCmd(a, b...) + if pwd != "" { + findCmd.Dir = pwd + } + statusChan := findCmd.Start() // non-blocking + + ticker := time.NewTicker(100 * time.Microsecond) + + // this is interesting, maybe useful, but wierd, but neat. interesting even + // Print last line of stdout every 2s + go func() { + // loop very quickly, but only print the line if it changes + var lastout string + var lasterr string + for range ticker.C { + status := findCmd.Status() + n := len(status.Stdout) + if n != 0 { + newline := status.Stdout[n-1] + if lastout != newline { + lastout = newline + log.Info(lastout) + } + } + n = len(status.Stderr) + if n != 0 { + newline := status.Stderr[n-1] + if lasterr != newline { + lasterr = newline + log.Info(lasterr) + } + } + if status.Complete { + return + } + } + }() + + // Stop command after 1 hour + go func() { + <-time.After(1 * time.Hour) + findCmd.Stop() + }() + + // Check if command is done + select { + case finalStatus := <-statusChan: + log.Info("finalStatus =", finalStatus.Exit, finalStatus.Error) + return finalStatus + // done + default: + // no, still running + } + + // Block waiting for command to exit, be stopped, or be killed + // there are things being left around here. debug this + finalStatus := <-statusChan + if len(finalStatus.Cmd) != 0 { + if string(finalStatus.Cmd) != "go" { + log.Info("shell.Run() ok goroutine end?", finalStatus.Cmd, finalStatus.Exit) + } + } + return findCmd.Status() +} |
