17
17
package main
18
18
19
19
import (
20
- "bufio"
21
20
"encoding/json"
22
21
"fmt"
23
22
"io/ioutil"
@@ -32,8 +31,10 @@ import (
32
31
"sync"
33
32
34
33
"github.com/ethereum/go-ethereum/common"
34
+ "github.com/ethereum/go-ethereum/console/prompt"
35
35
"github.com/ethereum/go-ethereum/core"
36
36
"github.com/ethereum/go-ethereum/log"
37
+ "github.com/peterh/liner"
37
38
"golang.org/x/crypto/ssh/terminal"
38
39
)
39
40
@@ -76,29 +77,35 @@ type wizard struct {
76
77
servers map [string ]* sshClient // SSH connections to servers to administer
77
78
services map [string ][]string // Ethereum services known to be running on servers
78
79
79
- in * bufio.Reader // Wrapper around stdin to allow reading user input
80
- lock sync.Mutex // Lock to protect configs during concurrent service discovery
80
+ lock sync.Mutex // Lock to protect configs during concurrent service discovery
81
+ }
82
+
83
+ // prompts the user for input with the given prompt string. Returns when a value is entered.
84
+ // Causes the wizard to exit if ctrl-d is pressed
85
+ func promptInput (p string ) string {
86
+ for {
87
+ text , err := prompt .Stdin .PromptInput (p )
88
+ if err != nil {
89
+ if err != liner .ErrPromptAborted {
90
+ log .Crit ("Failed to read user input" , "err" , err )
91
+ }
92
+ } else {
93
+ return text
94
+ }
95
+ }
81
96
}
82
97
83
98
// read reads a single line from stdin, trimming if from spaces.
84
99
func (w * wizard ) read () string {
85
- fmt .Printf ("> " )
86
- text , err := w .in .ReadString ('\n' )
87
- if err != nil {
88
- log .Crit ("Failed to read user input" , "err" , err )
89
- }
100
+ text := promptInput ("> " )
90
101
return strings .TrimSpace (text )
91
102
}
92
103
93
104
// readString reads a single line from stdin, trimming if from spaces, enforcing
94
105
// non-emptyness.
95
106
func (w * wizard ) readString () string {
96
107
for {
97
- fmt .Printf ("> " )
98
- text , err := w .in .ReadString ('\n' )
99
- if err != nil {
100
- log .Crit ("Failed to read user input" , "err" , err )
101
- }
108
+ text := promptInput ("> " )
102
109
if text = strings .TrimSpace (text ); text != "" {
103
110
return text
104
111
}
@@ -108,11 +115,7 @@ func (w *wizard) readString() string {
108
115
// readDefaultString reads a single line from stdin, trimming if from spaces. If
109
116
// an empty line is entered, the default value is returned.
110
117
func (w * wizard ) readDefaultString (def string ) string {
111
- fmt .Printf ("> " )
112
- text , err := w .in .ReadString ('\n' )
113
- if err != nil {
114
- log .Crit ("Failed to read user input" , "err" , err )
115
- }
118
+ text := promptInput ("> " )
116
119
if text = strings .TrimSpace (text ); text != "" {
117
120
return text
118
121
}
@@ -124,11 +127,7 @@ func (w *wizard) readDefaultString(def string) string {
124
127
// value is returned.
125
128
func (w * wizard ) readDefaultYesNo (def bool ) bool {
126
129
for {
127
- fmt .Printf ("> " )
128
- text , err := w .in .ReadString ('\n' )
129
- if err != nil {
130
- log .Crit ("Failed to read user input" , "err" , err )
131
- }
130
+ text := promptInput ("> " )
132
131
if text = strings .ToLower (strings .TrimSpace (text )); text == "" {
133
132
return def
134
133
}
@@ -146,11 +145,7 @@ func (w *wizard) readDefaultYesNo(def bool) bool {
146
145
// interpret it as a URL (http, https or file).
147
146
func (w * wizard ) readURL () * url.URL {
148
147
for {
149
- fmt .Printf ("> " )
150
- text , err := w .in .ReadString ('\n' )
151
- if err != nil {
152
- log .Crit ("Failed to read user input" , "err" , err )
153
- }
148
+ text := promptInput ("> " )
154
149
uri , err := url .Parse (strings .TrimSpace (text ))
155
150
if err != nil {
156
151
log .Error ("Invalid input, expected URL" , "err" , err )
@@ -164,11 +159,7 @@ func (w *wizard) readURL() *url.URL {
164
159
// to parse into an integer.
165
160
func (w * wizard ) readInt () int {
166
161
for {
167
- fmt .Printf ("> " )
168
- text , err := w .in .ReadString ('\n' )
169
- if err != nil {
170
- log .Crit ("Failed to read user input" , "err" , err )
171
- }
162
+ text := promptInput ("> " )
172
163
if text = strings .TrimSpace (text ); text == "" {
173
164
continue
174
165
}
@@ -186,11 +177,7 @@ func (w *wizard) readInt() int {
186
177
// returned.
187
178
func (w * wizard ) readDefaultInt (def int ) int {
188
179
for {
189
- fmt .Printf ("> " )
190
- text , err := w .in .ReadString ('\n' )
191
- if err != nil {
192
- log .Crit ("Failed to read user input" , "err" , err )
193
- }
180
+ text := promptInput ("> " )
194
181
if text = strings .TrimSpace (text ); text == "" {
195
182
return def
196
183
}
@@ -208,11 +195,7 @@ func (w *wizard) readDefaultInt(def int) int {
208
195
// default value is returned.
209
196
func (w * wizard ) readDefaultBigInt (def * big.Int ) * big.Int {
210
197
for {
211
- fmt .Printf ("> " )
212
- text , err := w .in .ReadString ('\n' )
213
- if err != nil {
214
- log .Crit ("Failed to read user input" , "err" , err )
215
- }
198
+ text := promptInput ("> " )
216
199
if text = strings .TrimSpace (text ); text == "" {
217
200
return def
218
201
}
@@ -225,38 +208,11 @@ func (w *wizard) readDefaultBigInt(def *big.Int) *big.Int {
225
208
}
226
209
}
227
210
228
- /*
229
- // readFloat reads a single line from stdin, trimming if from spaces, enforcing it
230
- // to parse into a float.
231
- func (w *wizard) readFloat() float64 {
232
- for {
233
- fmt.Printf("> ")
234
- text, err := w.in.ReadString('\n')
235
- if err != nil {
236
- log.Crit("Failed to read user input", "err", err)
237
- }
238
- if text = strings.TrimSpace(text); text == "" {
239
- continue
240
- }
241
- val, err := strconv.ParseFloat(strings.TrimSpace(text), 64)
242
- if err != nil {
243
- log.Error("Invalid input, expected float", "err", err)
244
- continue
245
- }
246
- return val
247
- }
248
- }
249
- */
250
-
251
211
// readDefaultFloat reads a single line from stdin, trimming if from spaces, enforcing
252
212
// it to parse into a float. If an empty line is entered, the default value is returned.
253
213
func (w * wizard ) readDefaultFloat (def float64 ) float64 {
254
214
for {
255
- fmt .Printf ("> " )
256
- text , err := w .in .ReadString ('\n' )
257
- if err != nil {
258
- log .Crit ("Failed to read user input" , "err" , err )
259
- }
215
+ text := promptInput ("> " )
260
216
if text = strings .TrimSpace (text ); text == "" {
261
217
return def
262
218
}
@@ -285,12 +241,7 @@ func (w *wizard) readPassword() string {
285
241
// it to an Ethereum address.
286
242
func (w * wizard ) readAddress () * common.Address {
287
243
for {
288
- // Read the address from the user
289
- fmt .Printf ("> 0x" )
290
- text , err := w .in .ReadString ('\n' )
291
- if err != nil {
292
- log .Crit ("Failed to read user input" , "err" , err )
293
- }
244
+ text := promptInput ("> 0x" )
294
245
if text = strings .TrimSpace (text ); text == "" {
295
246
return nil
296
247
}
@@ -311,11 +262,7 @@ func (w *wizard) readAddress() *common.Address {
311
262
func (w * wizard ) readDefaultAddress (def common.Address ) common.Address {
312
263
for {
313
264
// Read the address from the user
314
- fmt .Printf ("> 0x" )
315
- text , err := w .in .ReadString ('\n' )
316
- if err != nil {
317
- log .Crit ("Failed to read user input" , "err" , err )
318
- }
265
+ text := promptInput ("> 0x" )
319
266
if text = strings .TrimSpace (text ); text == "" {
320
267
return def
321
268
}
@@ -334,8 +281,9 @@ func (w *wizard) readJSON() string {
334
281
var blob json.RawMessage
335
282
336
283
for {
337
- fmt .Printf ("> " )
338
- if err := json .NewDecoder (w .in ).Decode (& blob ); err != nil {
284
+ text := promptInput ("> " )
285
+ reader := strings .NewReader (text )
286
+ if err := json .NewDecoder (reader ).Decode (& blob ); err != nil {
339
287
log .Error ("Invalid JSON, please try again" , "err" , err )
340
288
continue
341
289
}
@@ -351,10 +299,7 @@ func (w *wizard) readIPAddress() string {
351
299
for {
352
300
// Read the IP address from the user
353
301
fmt .Printf ("> " )
354
- text , err := w .in .ReadString ('\n' )
355
- if err != nil {
356
- log .Crit ("Failed to read user input" , "err" , err )
357
- }
302
+ text := promptInput ("> " )
358
303
if text = strings .TrimSpace (text ); text == "" {
359
304
return ""
360
305
}
0 commit comments