-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.go
155 lines (136 loc) · 3.46 KB
/
run.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package golbin
import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"runtime"
"strings"
)
/*
Console is structure to contain Command Line, Input and Output.
*/
type Console struct {
Command, StdInput, StdOutput string
Process *os.Process
}
/*
Run executes command from Console field with its input
and sets the output or error whatever gets prompted.
*/
func (konsole *Console) Run() (err error) {
cmd := cmdStringToExecCmd(konsole.Command)
if konsole.StdInput != "" {
cmd.Stdin = strings.NewReader(konsole.StdInput)
}
konsole.Process = cmd.Process
var out bytes.Buffer
cmd.Stdout = &out
err = cmd.Run()
if err == nil {
konsole.StdOutput = out.String()
} else {
konsole.StdOutput = fmt.Sprintf("Stdout: %s\nError: %s", out.String(), err.Error())
}
return
}
/*
ExecOutput can be passed a command to quickly get its output or error.
*/
func ExecOutput(cmdline string) string {
cmd := cmdStringToExecCmd(cmdline)
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err == nil {
return out.String()
}
return fmt.Sprintf("Error: %s", err.Error())
}
/*
Run it for distro to manage opening with correct program
*/
func RunWithAssignedApp(runThis string) string {
var openWith string
if runtime.GOOS == "linux" {
openWith = "xdg-open"
} else if runtime.GOOS == "darwin" {
openWith = "open"
} else {
return fmt.Sprintf("Error: %s is not supported as yet.", runtime.GOOS)
}
if !IsSystemCmd(openWith) {
return fmt.Sprintf("Error: %s not found on this machine.", openWith)
}
cmdToRun := fmt.Sprintf("%s %s", openWith, runThis)
return ExecOutput(cmdToRun)
}
func cmdStringToExecCmd(cmd string) *exec.Cmd {
parts := strings.Fields(cmd)
first := parts[0]
rest := []string{}
if len(parts) > 1 {
rest = mergeTokensWithQuotes(parts[1:])
}
return exec.Command(first, rest...)
}
func execCmd(cmdHandle *exec.Cmd) (out string, err error) {
var stdout, stderr bytes.Buffer
cmdHandle.Stdout = &stdout
cmdHandle.Stderr = &stderr
err = cmdHandle.Run()
if err != nil {
err = errors.New(fmt.Sprintf("'%s' :: '%s'", stderr.String(), err.Error()))
}
out = stdout.String()
return
}
func Exec(cmd string) (string, error) {
cmdHandle := cmdStringToExecCmd(cmd)
return execCmd(cmdHandle)
}
func ExecWithEnv(cmd string, env map[string]string) (string, error) {
cmdHandle := cmdStringToExecCmd(cmd)
cmdHandle.Env = os.Environ()
for envVar, envVal := range env {
cmdHandle.Env = append(cmdHandle.Env, fmt.Sprintf("%s=%s", envVar, envVal))
}
return execCmd(cmdHandle)
}
func mergeTokensWithQuotes(words []string) []string {
tokens := []string{}
var inSingleQuotes, inDoubleQuotes bool
for _, w := range words {
if inSingleQuotes || inDoubleQuotes {
tokens = append(tokens[0:len(tokens)-1], tokens[len(tokens)-1]+" "+w)
if strings.ContainsRune(w, '\'') && inSingleQuotes {
inSingleQuotes = false
} else if strings.ContainsRune(w, '"') && inDoubleQuotes {
inDoubleQuotes = false
}
continue
}
tokens = append(tokens, w)
if strings.ContainsRune(w, '\'') {
if strings.Count(w, "'")%2 == 1 {
inSingleQuotes = true
}
} else if strings.ContainsRune(w, '"') {
if strings.Count(w, "\"")%2 == 1 {
inDoubleQuotes = true
}
}
}
result := make([]string, len(tokens))
for idx, token := range tokens {
result[idx] = stripQuotes(token)
}
return result
}
func stripQuotes(w string) string {
if (w[0] == '\'' && w[len(w)-1] == '\'') || (w[0] == '"' && w[len(w)-1] == '"') {
return w[1 : len(w)-1]
}
return w
}