/
read.go
166 lines (142 loc) · 3.42 KB
/
read.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
package interact
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"
"syscall"
"github.com/gookit/color"
"github.com/gookit/goutil/cliutil"
"github.com/gookit/goutil/envutil"
"golang.org/x/crypto/ssh/terminal"
)
// ReadInput read user input form Stdin
func ReadInput(question string) (string, error) {
if len(question) > 0 {
color.Print(question)
}
scanner := bufio.NewScanner(os.Stdin)
if !scanner.Scan() { // reading
return "", scanner.Err()
}
answer := scanner.Text()
return strings.TrimSpace(answer), nil
}
// ReadLine read one line from user input.
// Usage:
// in := ReadLine("")
// ans := ReadLine("your name?")
func ReadLine(question string) (string, error) {
if len(question) > 0 {
color.Print(question)
}
reader := bufio.NewReader(os.Stdin)
answer, _, err := reader.ReadLine()
return strings.TrimSpace(string(answer)), err
}
// ReadFirst read first char
func ReadFirst(question string) (string, error) {
answer, err := ReadLine(question)
if len(answer) == 0 {
return "", err
}
return string(answer[0]), err
}
// AnswerIsYes check user inputted answer is right
// Usage:
// fmt.Print("are you OK?")
// ok := AnswerIsYes()
// ok := AnswerIsYes(true)
func AnswerIsYes(defVal ...bool) bool {
mark := " [yes|no]: "
if len(defVal) > 0 {
var defShow string
if defVal[0] {
defShow = "yes"
} else {
defShow = "no"
}
mark = fmt.Sprintf(" [yes|no](default <cyan>%s</>): ", defShow)
}
// _, err := fmt.Scanln(&answer)
// _, err := fmt.Scan(&answer)
fChar, err := ReadFirst(mark)
if err != nil {
panic(err)
}
if len(fChar) > 0 {
fChar := strings.ToLower(fChar)
if fChar == "y" {
return true
} else if fChar == "n" {
return false
}
} else if len(defVal) > 0 { // has default value
return defVal[0]
}
fmt.Print("Please try again")
return AnswerIsYes()
}
// ReadPassword from terminal
func ReadPassword(message ...string) string {
if len(message) > 0 {
print(message[0])
} else {
print("Enter Password: ")
}
bs, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
return ""
}
println() // new line
return string(bs)
}
// GetHiddenInput interactively prompts for input without echoing to the terminal.
// usage:
// // askPassword
// pwd := GetHiddenInput("Enter Password:")
func GetHiddenInput(message string, trimmed bool) string {
var err error
var input string
var hasResult bool
// like *nix, git-bash ...
if envutil.HasShellEnv("sh") {
// COMMAND: sh -c 'read -p "Enter Password:" -s user_input && echo $user_input'
cmd := fmt.Sprintf(`'read -p "%s" -s user_input && echo $user_input'`, message)
input, err = cliutil.ShellExec(cmd)
if err != nil {
fmt.Println("error:", err)
return ""
}
println() // new line
hasResult = true
} else if envutil.IsWin() { // at windows cmd.exe
// create a temp VB script file
vbFile, err := ioutil.TempFile("", "cliapp")
if err != nil {
return ""
}
defer func() {
// delete file
vbFile.Close()
_ = os.Remove(vbFile.Name())
}()
script := fmt.Sprintf(`wscript.echo(InputBox("%s", "", "password here"))`, message)
_, _ = vbFile.WriteString(script)
hasResult = true
// exec VB script
// COMMAND: cscript //nologo vbFile.Name()
input, err = cliutil.ExecCmd("cscript", []string{"//nologo", vbFile.Name()})
if err != nil {
return ""
}
}
if hasResult {
if trimmed {
return strings.TrimSpace(input)
}
return input
}
panic("current env is not support the method")
}