diff options
| -rw-r--r-- | buildPlugin.go | 3 | ||||
| -rw-r--r-- | install_linux.go | 6 | ||||
| -rw-r--r-- | run.go | 101 | ||||
| -rw-r--r-- | sudo.go | 7 | ||||
| -rw-r--r-- | sudo_darwin.go | 12 | ||||
| -rw-r--r-- | sudo_linux.go | 62 | ||||
| -rw-r--r-- | sudo_windows.go | 12 |
7 files changed, 198 insertions, 5 deletions
diff --git a/buildPlugin.go b/buildPlugin.go index 6dbe187..c0c100e 100644 --- a/buildPlugin.go +++ b/buildPlugin.go @@ -1,7 +1,6 @@ package fhelp import ( - "go.wit.com/lib/gui/shell" "go.wit.com/log" ) @@ -28,7 +27,7 @@ func BuildPlugin(pname string) bool { if !QuestionUser("Would you like to run that now?") { return false } - r := shell.RunRealtime(cmd) + r := RunRealtime(cmd) if r.Error == nil { log.Info("build worked") log.Info("You must copy that file to ~/go/lib/go-gui/") diff --git a/install_linux.go b/install_linux.go index 0ed600b..f86946a 100644 --- a/install_linux.go +++ b/install_linux.go @@ -8,7 +8,6 @@ import ( "os" "strings" - "go.wit.com/lib/gui/shell" "go.wit.com/log" ) @@ -27,8 +26,9 @@ func osInstall(pkg string) error { line = strings.ToLower(line) switch line { case "y": - shell.Sudo(cmd) - return nil + log.Info("todo: fix this") + Sudo(cmd) + return log.Errorf("user didn't install package %s", pkg) default: } } @@ -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() +} @@ -0,0 +1,7 @@ +package fhelp + +// auto run protoc with the correct args + +func Sudo(cmd []string) error { + return osSudo(cmd) +} diff --git a/sudo_darwin.go b/sudo_darwin.go new file mode 100644 index 0000000..4e082ec --- /dev/null +++ b/sudo_darwin.go @@ -0,0 +1,12 @@ +package fhelp + +// auto run protoc with the correct args + +import ( + "go.wit.com/log" +) + +func osSudo(cmd []string) error { + log.Info("todo: add instructions on macos to sudo") + return log.Errorf("no sudo") +} diff --git a/sudo_linux.go b/sudo_linux.go new file mode 100644 index 0000000..0ef3995 --- /dev/null +++ b/sudo_linux.go @@ -0,0 +1,62 @@ +package fhelp + +import ( + "fmt" + "os" + "os/exec" + "syscall" +) + +func osSudoRaw(c []string) { + args := []string{"-S"} + args = append(args, c...) + cmd := exec.Command("sudo", args...) + + // Assign the current process's standard input, output, and error + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Stdin = os.Stdin + + // Ensure the process has a terminal session + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setsid: true, // Start a new session + } + + err := cmd.Run() + if err != nil { + fmt.Println("Command execution failed:", err) + } +} + +func osSudo(c []string) error { + args := []string{"-S"} + // args := []string{} + args = append(args, c...) + cmd := exec.Command("sudo", args...) + + // Open the terminal device directly to preserve input/output control + tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) + if err != nil { + fmt.Println("Failed to open /dev/tty:", err) + return err + } + defer tty.Close() + + // Assign the TTY explicitly + cmd.Stdin = tty + cmd.Stdout = tty + cmd.Stderr = tty + + // Ensure the new process gets its own session + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setsid: true, // Start a new session + } + + // Run the command + if err := cmd.Run(); err != nil { + fmt.Println("Command execution failed:", err) + } + + fmt.Println("\nProcess finished. TTY restored.") + return nil +} diff --git a/sudo_windows.go b/sudo_windows.go new file mode 100644 index 0000000..cad5936 --- /dev/null +++ b/sudo_windows.go @@ -0,0 +1,12 @@ +package fhelp + +// auto run protoc with the correct args + +import ( + "go.wit.com/log" +) + +func osSudo(cmd []string) error { + log.Info("todo: add instructions on windows to sudo") + return log.Errorf("user needs root") +} |
