Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
|
4efd88947c | |
|
e621f228ba | |
|
590ce71782 | |
|
2b1f7f54d5 | |
|
d70cf82ecc | |
|
364d666eb6 | |
|
0146183226 | |
|
098c7d3771 | |
|
1534b9fbbc | |
|
d5f45aef13 | |
|
3408d9434b | |
|
d564d4f2d7 | |
|
2b1b847143 | |
|
f39c2a86a6 | |
|
8d692299b0 | |
|
99eded5398 | |
|
62e2d64ff9 |
8
Makefile
8
Makefile
|
@ -1,5 +1,9 @@
|
|||
all:
|
||||
GO111MODULE=off go build
|
||||
all: goimports vet
|
||||
|
||||
vet:
|
||||
@GO111MODULE=off go vet
|
||||
@echo this go library package builds okay
|
||||
|
||||
|
||||
goimports:
|
||||
goimports -w *.go
|
||||
|
|
95
cmd.go
95
cmd.go
|
@ -3,6 +3,7 @@ package shell
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-cmd/cmd"
|
||||
|
@ -43,7 +44,7 @@ func Run(argv []string) cmd.Status {
|
|||
// where the have rocked out a proper smart read on both filehandles
|
||||
// https://dave.cheney.net/2013/04/30/curious-channels
|
||||
func PathRun(path string, argv []string) cmd.Status {
|
||||
return PathRunLog(path, argv, NOW)
|
||||
return PathRunLog(path, argv, INFO)
|
||||
}
|
||||
|
||||
// the actual wrapper around go-cmd/cmd
|
||||
|
@ -139,6 +140,21 @@ func RunRealtime(args []string) cmd.Status {
|
|||
return PathRunRealtime("", args)
|
||||
}
|
||||
|
||||
func RunEcho(cmd []string) cmd.Status {
|
||||
result := RunQuiet(cmd)
|
||||
pwd, _ := os.Getwd()
|
||||
log.Warn("shell.RunEcho() cmd:", cmd, pwd)
|
||||
log.Warn("shell.RunEcho() Exit:", result.Exit)
|
||||
log.Warn("shell.RunEcho() Error:", result.Error)
|
||||
for _, line := range result.Stdout {
|
||||
log.Warn("STDOUT:", line)
|
||||
}
|
||||
for _, line := range result.Stderr {
|
||||
log.Warn("STDERR:", line)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -160,7 +176,7 @@ func PathRunRealtime(pwd string, args []string) cmd.Status {
|
|||
}
|
||||
statusChan := findCmd.Start() // non-blocking
|
||||
|
||||
ticker := time.NewTicker(5 * time.Millisecond)
|
||||
ticker := time.NewTicker(100 * time.Microsecond)
|
||||
|
||||
// this is interesting, maybe useful, but wierd, but neat. interesting even
|
||||
// Print last line of stdout every 2s
|
||||
|
@ -209,29 +225,14 @@ func PathRunRealtime(pwd string, args []string) cmd.Status {
|
|||
}
|
||||
|
||||
// Block waiting for command to exit, be stopped, or be killed
|
||||
// there are things being left around here. debug this
|
||||
finalStatus := <-statusChan
|
||||
return finalStatus
|
||||
}
|
||||
|
||||
func blah(cmd []string) {
|
||||
r := Run(cmd)
|
||||
log.Info("cmd =", r.Cmd)
|
||||
log.Info("complete =", r.Complete)
|
||||
log.Info("exit =", r.Exit)
|
||||
log.Info("err =", r.Error)
|
||||
log.Info("len(stdout+stderr) =", len(r.Stdout))
|
||||
}
|
||||
|
||||
// run these to see confirm the sytem behaves as expected
|
||||
func RunTest() {
|
||||
blah([]string{"ping", "-c", "3", "localhost"})
|
||||
blah([]string{"exit", "0"})
|
||||
blah([]string{"exit", "-1"})
|
||||
blah([]string{"true"})
|
||||
blah([]string{"false"})
|
||||
blah([]string{"grep", "root", "/etc/", "/proc/cmdline", "/usr/bin/chmod"})
|
||||
blah([]string{"grep", "root", "/proc/cmdline"})
|
||||
fmt.Sprint("blahdone")
|
||||
if len(finalStatus.Cmd) != 0 {
|
||||
if string(finalStatus.Cmd) != "go" {
|
||||
log.Info("shell.Run() ok goroutine end?", finalStatus.Cmd, finalStatus.Exit)
|
||||
}
|
||||
}
|
||||
return findCmd.Status()
|
||||
}
|
||||
|
||||
// this is stuff from a long time ago that there must be a replacement for
|
||||
|
@ -241,3 +242,49 @@ func RemoveFirstElement(slice []string) (string, []string) {
|
|||
}
|
||||
return slice[0], slice[1:] // Return the slice without the first element
|
||||
}
|
||||
|
||||
func RunVerbose(cmd []string) (*cmd.Status, error) {
|
||||
pwd, _ := os.Getwd()
|
||||
log.Info("Running:", pwd, cmd)
|
||||
r, err := RunStrict(cmd)
|
||||
if err != nil {
|
||||
log.Info("Error", cmd, err)
|
||||
}
|
||||
for _, line := range r.Stdout {
|
||||
log.Info(line)
|
||||
}
|
||||
for _, line := range r.Stderr {
|
||||
log.Info(line)
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
func RunVerboseOnError(cmd []string) (*cmd.Status, error) {
|
||||
r, err := RunStrict(cmd)
|
||||
if err == nil {
|
||||
return r, err
|
||||
}
|
||||
pwd, _ := os.Getwd()
|
||||
log.Info("Run Error:", pwd, cmd, err)
|
||||
for _, line := range r.Stdout {
|
||||
log.Info(line)
|
||||
}
|
||||
for _, line := range r.Stderr {
|
||||
log.Info(line)
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
func RunStrict(cmd []string) (*cmd.Status, error) {
|
||||
pwd, _ := os.Getwd()
|
||||
result := PathRunQuiet(pwd, cmd)
|
||||
if result.Error != nil {
|
||||
log.Warn(pwd, cmd, "wow. golang is cool. an os.Error:", result.Error)
|
||||
return &result, result.Error
|
||||
}
|
||||
if result.Exit != 0 {
|
||||
// log.Warn(cmd, "failed with", result.Exit, repo.GetGoPath())
|
||||
return &result, errors.New(fmt.Sprint(cmd, "failed with", result.Exit))
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package shell
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func Exec(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("Error: Command slice is empty.")
|
||||
}
|
||||
|
||||
// Start a long-running process, capture stdout and stderr
|
||||
a, b := RemoveFirstElement(args)
|
||||
|
||||
process := exec.Command(a, b...)
|
||||
process.Stderr = os.Stderr
|
||||
process.Stdin = os.Stdin
|
||||
process.Stdout = os.Stdout
|
||||
process.Start()
|
||||
err := process.Wait()
|
||||
log.Log(INFO, "shell.Exec() err =", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExecCheck(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("Error: Command slice is empty.")
|
||||
}
|
||||
|
||||
// Start a long-running process, capture stdout and stderr
|
||||
a, b := RemoveFirstElement(args)
|
||||
|
||||
process := exec.Command(a, b...)
|
||||
process.Stderr = os.Stderr
|
||||
process.Stdin = os.Stdin
|
||||
process.Stdout = os.Stdout
|
||||
err := process.Run()
|
||||
if err != nil {
|
||||
log.Info("ExecCheck() err", err)
|
||||
return err
|
||||
}
|
||||
// log.Info("ExecCheck() nil")
|
||||
return nil
|
||||
}
|
||||
|
||||
func PathExecVerbose(path string, args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("Error: Command slice is empty.")
|
||||
}
|
||||
|
||||
// Start a long-running process, capture stdout and stderr
|
||||
a, b := RemoveFirstElement(args)
|
||||
|
||||
process := exec.Command(a, b...)
|
||||
process.Dir = path
|
||||
process.Stderr = os.Stderr
|
||||
process.Stdin = os.Stdin
|
||||
process.Stdout = os.Stdout
|
||||
err := process.Run()
|
||||
log.Info("Exec() cmd:", args)
|
||||
if err != nil {
|
||||
log.Info("ExecCheck() err", err)
|
||||
return err
|
||||
}
|
||||
// log.Info("ExecCheck() nil")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SudoRaw(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 Sudo(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
|
||||
}
|
|
@ -3,8 +3,6 @@ package shell
|
|||
// old code and probably junk
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
|
@ -16,11 +14,11 @@ import (
|
|||
|
||||
var callback func(interface{}, int)
|
||||
|
||||
var shellStdout *os.File
|
||||
var shellStderr *os.File
|
||||
// var shellStdout *os.File
|
||||
// var shellStderr *os.File
|
||||
|
||||
var spewOn bool = false
|
||||
var quiet bool = false
|
||||
// var spewOn bool = false
|
||||
// var quiet bool = false
|
||||
|
||||
// var msecDelay int = 20 // number of milliseconds to delay between reads with no data
|
||||
|
||||
|
@ -42,26 +40,6 @@ func InitCallback(f func(interface{}, int)) {
|
|||
callback = f
|
||||
}
|
||||
|
||||
// this means it won't copy all the output to STDOUT
|
||||
func Quiet(q bool) {
|
||||
quiet = q
|
||||
}
|
||||
|
||||
/*
|
||||
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 {
|
||||
line = Chomp(line) // this is like 'chomp' in perl
|
||||
log.Log(INFO, "LINE:", line)
|
||||
time.Sleep(1)
|
||||
RunString(line)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
*/
|
||||
|
||||
func Unlink(filename string) bool {
|
||||
if err := os.Remove(filename); err != nil {
|
||||
return Exists(filename)
|
||||
|
@ -107,66 +85,11 @@ func Exists(filename string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func IsDir(dirname string) bool {
|
||||
return Dir(dirname)
|
||||
}
|
||||
|
||||
// return true if the filename exists (cross-platform)
|
||||
func Dir(dirname string) bool {
|
||||
func IsDir(dirname string) bool {
|
||||
info, err := os.Stat(Path(dirname))
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return info.IsDir()
|
||||
}
|
||||
|
||||
// Cat a file into a string
|
||||
func Cat(filename string) string {
|
||||
buffer, err := ioutil.ReadFile(Path(filename))
|
||||
// log.Log(INFO, "buffer =", string(buffer))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(buffer)
|
||||
}
|
||||
|
||||
func RunPathHttpOut(path string, cmd []string, w http.ResponseWriter, r *http.Request) error {
|
||||
log.Warn("Run(): ", cmd)
|
||||
|
||||
process := exec.Command(cmd[0], cmd[1:len(cmd)]...)
|
||||
process.Dir = path
|
||||
process.Stderr = os.Stderr
|
||||
process.Stdin = r.Body
|
||||
process.Stdout = w
|
||||
process.Start()
|
||||
err := process.Wait()
|
||||
log.Warn("shell.Exec() err =", err)
|
||||
return err
|
||||
}
|
||||
|
||||
func RunHttpOut(cmd []string, w http.ResponseWriter, r *http.Request) error {
|
||||
log.Warn("NewRun() ", cmd)
|
||||
|
||||
process := exec.Command(cmd[0], cmd[1:len(cmd)]...)
|
||||
process.Stderr = os.Stderr
|
||||
process.Stdin = r.Body
|
||||
process.Stdout = w
|
||||
process.Start()
|
||||
err := process.Wait()
|
||||
log.Warn("shell.Exec() err =", err)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package shell
|
||||
|
||||
import "regexp"
|
||||
|
||||
// splits strings. should work all the time
|
||||
// A string with mixed line endings, including old Mac style (\r)
|
||||
func SplitNewLines(input string) []string {
|
||||
// This regex matches a carriage return and optional newline, OR just a newline.
|
||||
// This covers \r\n, \n, and \r.
|
||||
re := regexp.MustCompile(`\r\n?|\n|\r`)
|
||||
|
||||
// The -1 means there is no limit to the number of splits.
|
||||
lines := re.Split(input, -1)
|
||||
|
||||
// Output: ["line one" "line two" "line three" "line four"]
|
||||
return lines
|
||||
}
|
|
@ -1,12 +1,6 @@
|
|||
package shell
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
/*
|
||||
var FileMap map[string]*File
|
||||
|
||||
var readBufferSize int
|
||||
|
@ -54,3 +48,4 @@ func New() *OldShell {
|
|||
|
||||
return &tmp
|
||||
}
|
||||
*/
|
||||
|
|
23
time.go
23
time.go
|
@ -51,6 +51,14 @@ func GetDurationStamp(t time.Time) string {
|
|||
return FormatDuration(duration)
|
||||
}
|
||||
|
||||
// allows nil
|
||||
func HumanDuration(d *time.Duration) string {
|
||||
if d == nil {
|
||||
return ""
|
||||
}
|
||||
return FormatDuration(*d)
|
||||
}
|
||||
|
||||
func FormatDuration(d time.Duration) string {
|
||||
result := ""
|
||||
|
||||
|
@ -94,6 +102,19 @@ func FormatDuration(d time.Duration) string {
|
|||
if ms > 100 {
|
||||
// todo: print .3s, etc ?
|
||||
}
|
||||
result += fmt.Sprintf("%dms", ms)
|
||||
if ms > 0 {
|
||||
result += fmt.Sprintf("%dms", ms)
|
||||
return result
|
||||
}
|
||||
|
||||
// report in milliseconds
|
||||
mc := int(d.Microseconds())
|
||||
if mc > 0 {
|
||||
result += fmt.Sprintf("%dmc", mc)
|
||||
return result
|
||||
}
|
||||
|
||||
ns := int(d.Nanoseconds())
|
||||
result += fmt.Sprintf("%dns", ns)
|
||||
return result
|
||||
}
|
||||
|
|
2
wget.go
2
wget.go
|
@ -34,7 +34,7 @@ func Wget(url string) *bytes.Buffer {
|
|||
|
||||
log.Log(INFO, "res.StatusCode: %d\n", resp.StatusCode)
|
||||
if resp.StatusCode != 200 {
|
||||
handleError(fmt.Errorf(fmt.Sprint("%d", resp.StatusCode)), -1)
|
||||
handleError(fmt.Errorf("%d", resp.StatusCode), -1)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
28
xterm.go
28
xterm.go
|
@ -3,11 +3,25 @@ package shell
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
// not sure why I wrote this or what it is for
|
||||
// this is because I'm crazy. how crazy you ask? fucking crazy!
|
||||
// hehe. If you haven't ever written code that you look back
|
||||
// at like this and go 'what the fuck is this shit', then
|
||||
// realize that you wrote it, then go 'what the fuck is this shit'
|
||||
// and then still look at it and wonder, "how early was this. how much did I not know when I wrote this"
|
||||
// then, if you haven't done those kinds of things, then don't
|
||||
// ever fucking come up to me and tell me that I'm nuts
|
||||
// because, you are not as good as me then. It's very complicated
|
||||
// to work on very complicated things. I don't care how smart you are,
|
||||
// you can totally forget about shit you wrote and then have to come back to it later
|
||||
|
||||
// also, what the fuck was I thinking with the function 'scanToParent()' as a function that takes
|
||||
// a pid arg? what? is this like pstree? I'm not sure what I wanted this for
|
||||
// but it sounds interesting.
|
||||
func scanToParent(pid int) (bool, string) {
|
||||
ppid, err := GetPPID(pid)
|
||||
if err != nil {
|
||||
|
@ -35,8 +49,6 @@ func scanToParent(pid int) (bool, string) {
|
|||
case "make":
|
||||
// keep digging for the parent xterm
|
||||
return scanToParent(ppid)
|
||||
default:
|
||||
return false, comm
|
||||
}
|
||||
if comm == "bash" {
|
||||
}
|
||||
|
@ -81,8 +93,6 @@ func Shell() string {
|
|||
switch envsh {
|
||||
case "/bin/bash":
|
||||
return "bash"
|
||||
default:
|
||||
return envsh
|
||||
}
|
||||
return envsh
|
||||
}
|
||||
|
@ -116,16 +126,17 @@ func XtermCmd(path string, cmd []string) {
|
|||
// runs an xterm
|
||||
// waits until xterm exits
|
||||
func XtermCmdWait(path string, cmd []string) {
|
||||
var argsXterm = getXtermCmd(cmd)
|
||||
// var argsXterm = getXtermCmd(cmd)
|
||||
|
||||
log.Info("XtermCmd() path =", path, "cmd =", argsXterm)
|
||||
log.Info("XtermCmd() path =", path, "cmd =", cmd)
|
||||
|
||||
// keeps git diff from exiting on small diffs
|
||||
os.Setenv("LESS", "-+F -+X -R")
|
||||
|
||||
PathRunLog(path, argsXterm, INFO)
|
||||
PathRunLog(path, cmd, INFO)
|
||||
}
|
||||
|
||||
/*
|
||||
// spawns an xterm with something you can run at a command line
|
||||
// then executes bash
|
||||
func XtermCmdBash(path string, cmd []string) {
|
||||
|
@ -138,3 +149,4 @@ func XtermCmdBash(path string, cmd []string) {
|
|||
log.Info("XtermCmd() path =", path, "cmd =", tmp)
|
||||
go PathRunLog(path, tmp, INFO)
|
||||
}
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue