-
Notifications
You must be signed in to change notification settings - Fork 191
/
Copy pathsysenv.go
205 lines (178 loc) · 4.34 KB
/
sysenv.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package sysutil
import (
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"github.com/gookit/goutil/internal/checkfn"
"github.com/gookit/goutil/internal/comfunc"
"golang.org/x/term"
)
// IsMSys msys(MINGW64) env,不一定支持颜色
func IsMSys() bool {
// "MSYSTEM=MINGW64"
return len(os.Getenv("MSYSTEM")) > 0
}
// IsConsole check out is in stderr/stdout/stdin
//
// Usage:
//
// sysutil.IsConsole(os.Stdout)
func IsConsole(out io.Writer) bool {
o, ok := out.(*os.File)
if !ok {
return false
}
fd := o.Fd()
// fix: cannot use 'o == os.Stdout' to compare
return fd == uintptr(syscall.Stdout) || fd == uintptr(syscall.Stdin) || fd == uintptr(syscall.Stderr)
}
// IsTerminal isatty check
//
// Usage:
//
// sysutil.IsTerminal(os.Stdout.Fd())
func IsTerminal(fd uintptr) bool {
// return isatty.IsTerminal(fd) // "github.com/mattn/go-isatty"
return term.IsTerminal(int(fd))
}
// StdIsTerminal os.Stdout is terminal
func StdIsTerminal() bool {
return IsTerminal(os.Stdout.Fd())
}
// Hostname is alias of os.Hostname, but ignore error
func Hostname() string {
name, _ := os.Hostname()
return name
}
// CurrentShell get current used shell env file.
//
// eg "/bin/zsh" "/bin/bash".
// if onlyName=true, will return "zsh", "bash"
func CurrentShell(onlyName bool) (path string) {
return comfunc.CurrentShell(onlyName)
}
// HasShellEnv has shell env check.
//
// Usage:
//
// HasShellEnv("sh")
// HasShellEnv("bash")
func HasShellEnv(shell string) bool {
// can also use: "echo $0"
out, err := ShellExec("echo OK", shell)
if err != nil {
return false
}
return strings.TrimSpace(out) == "OK"
}
// IsShellSpecialVar reports whether the character identifies a special
// shell variable such as $*.
func IsShellSpecialVar(c uint8) bool {
switch c {
case '*', '#', '$', '@', '!', '?', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return true
}
return false
}
// FindExecutable in the system
//
// Usage:
//
// sysutil.FindExecutable("bash")
func FindExecutable(binName string) (string, error) {
return exec.LookPath(binName)
}
// Executable find in the system, alias of FindExecutable()
//
// Usage:
//
// sysutil.Executable("bash")
func Executable(binName string) (string, error) {
return exec.LookPath(binName)
}
// HasExecutable in the system
//
// Usage:
//
// HasExecutable("bash")
func HasExecutable(binName string) bool {
_, err := exec.LookPath(binName)
return err == nil
}
// Getenv get ENV value by key name, can with default value
func Getenv(name string, def ...string) string {
val := os.Getenv(name)
if val == "" && len(def) > 0 {
val = def[0]
}
return val
}
// Environ like os.Environ, but will returns key-value map[string]string data.
func Environ() map[string]string { return comfunc.Environ() }
// EnvMapWith like os.Environ, but will return key-value map[string]string data.
func EnvMapWith(newEnv map[string]string) map[string]string {
envMp := comfunc.Environ()
for name, value := range newEnv {
envMp[name] = value
}
return envMp
}
// EnvPaths get and split $PATH to []string
func EnvPaths() []string {
return filepath.SplitList(os.Getenv("PATH"))
}
// SearchPathOption settings for SearchPath
type SearchPathOption struct {
// 限制的扩展名
LimitExt []string
}
// SearchPath search executable files in the system $PATH
//
// Usage:
//
// sysutil.SearchPath("go")
func SearchPath(keywords string, limit int) []string {
path := os.Getenv("PATH")
ptn := "*" + keywords + "*"
list := make([]string, 0)
// if windows, will limit with .exe, .bat, .cmd
isWindows := IsWindows()
winExts := []string{".exe", ".bat", ".cmd"}
checked := make(map[string]bool)
for _, dir := range filepath.SplitList(path) {
// Unix shell semantics: path element "" means "."
if dir == "" {
dir = "."
}
// mark dir is checked
if _, ok := checked[dir]; ok {
continue
}
checked[dir] = true
matches, err := filepath.Glob(filepath.Join(dir, ptn))
if err == nil && len(matches) > 0 {
if isWindows {
// if windows, will limit with .exe, .bat, .cmd
for _, fPath := range matches {
fExt := filepath.Ext(fPath)
if checkfn.StringsContains(winExts, fExt) {
continue
}
list = append(list, fPath)
}
} else {
list = append(list, matches...)
}
// limit result size
size := len(list)
if limit > 0 && size >= limit {
list = list[:limit]
break
}
}
}
return list
}