1717package main
1818
1919import (
20- "bufio"
2120 "encoding/json"
2221 "fmt"
2322 "io/ioutil"
@@ -32,8 +31,10 @@ import (
3231 "sync"
3332
3433 "github.com/ethereum/go-ethereum/common"
34+ "github.com/ethereum/go-ethereum/console/prompt"
3535 "github.com/ethereum/go-ethereum/core"
3636 "github.com/ethereum/go-ethereum/log"
37+ "github.com/peterh/liner"
3738 "golang.org/x/crypto/ssh/terminal"
3839)
3940
@@ -76,29 +77,35 @@ type wizard struct {
7677 servers map [string ]* sshClient // SSH connections to servers to administer
7778 services map [string ][]string // Ethereum services known to be running on servers
7879
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+ }
8196}
8297
8398// read reads a single line from stdin, trimming if from spaces.
8499func (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 ("> " )
90101 return strings .TrimSpace (text )
91102}
92103
93104// readString reads a single line from stdin, trimming if from spaces, enforcing
94105// non-emptyness.
95106func (w * wizard ) readString () string {
96107 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 ("> " )
102109 if text = strings .TrimSpace (text ); text != "" {
103110 return text
104111 }
@@ -108,11 +115,7 @@ func (w *wizard) readString() string {
108115// readDefaultString reads a single line from stdin, trimming if from spaces. If
109116// an empty line is entered, the default value is returned.
110117func (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 ("> " )
116119 if text = strings .TrimSpace (text ); text != "" {
117120 return text
118121 }
@@ -124,11 +127,7 @@ func (w *wizard) readDefaultString(def string) string {
124127// value is returned.
125128func (w * wizard ) readDefaultYesNo (def bool ) bool {
126129 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 ("> " )
132131 if text = strings .ToLower (strings .TrimSpace (text )); text == "" {
133132 return def
134133 }
@@ -146,11 +145,7 @@ func (w *wizard) readDefaultYesNo(def bool) bool {
146145// interpret it as a URL (http, https or file).
147146func (w * wizard ) readURL () * url.URL {
148147 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 ("> " )
154149 uri , err := url .Parse (strings .TrimSpace (text ))
155150 if err != nil {
156151 log .Error ("Invalid input, expected URL" , "err" , err )
@@ -164,11 +159,7 @@ func (w *wizard) readURL() *url.URL {
164159// to parse into an integer.
165160func (w * wizard ) readInt () int {
166161 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 ("> " )
172163 if text = strings .TrimSpace (text ); text == "" {
173164 continue
174165 }
@@ -186,11 +177,7 @@ func (w *wizard) readInt() int {
186177// returned.
187178func (w * wizard ) readDefaultInt (def int ) int {
188179 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 ("> " )
194181 if text = strings .TrimSpace (text ); text == "" {
195182 return def
196183 }
@@ -208,11 +195,7 @@ func (w *wizard) readDefaultInt(def int) int {
208195// default value is returned.
209196func (w * wizard ) readDefaultBigInt (def * big.Int ) * big.Int {
210197 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 ("> " )
216199 if text = strings .TrimSpace (text ); text == "" {
217200 return def
218201 }
@@ -225,38 +208,11 @@ func (w *wizard) readDefaultBigInt(def *big.Int) *big.Int {
225208 }
226209}
227210
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-
251211// readDefaultFloat reads a single line from stdin, trimming if from spaces, enforcing
252212// it to parse into a float. If an empty line is entered, the default value is returned.
253213func (w * wizard ) readDefaultFloat (def float64 ) float64 {
254214 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 ("> " )
260216 if text = strings .TrimSpace (text ); text == "" {
261217 return def
262218 }
@@ -285,12 +241,7 @@ func (w *wizard) readPassword() string {
285241// it to an Ethereum address.
286242func (w * wizard ) readAddress () * common.Address {
287243 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" )
294245 if text = strings .TrimSpace (text ); text == "" {
295246 return nil
296247 }
@@ -311,11 +262,7 @@ func (w *wizard) readAddress() *common.Address {
311262func (w * wizard ) readDefaultAddress (def common.Address ) common.Address {
312263 for {
313264 // 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" )
319266 if text = strings .TrimSpace (text ); text == "" {
320267 return def
321268 }
@@ -334,8 +281,9 @@ func (w *wizard) readJSON() string {
334281 var blob json.RawMessage
335282
336283 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 {
339287 log .Error ("Invalid JSON, please try again" , "err" , err )
340288 continue
341289 }
@@ -351,10 +299,7 @@ func (w *wizard) readIPAddress() string {
351299 for {
352300 // Read the IP address from the user
353301 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 ("> " )
358303 if text = strings .TrimSpace (text ); text == "" {
359304 return ""
360305 }
0 commit comments