github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/interact/query.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package interact 5 6 import ( 7 "bufio" 8 "fmt" 9 "io" 10 "strings" 11 ) 12 13 // QueryVerify writes a question to w and waits for an answer to be read from 14 // scanner. It will pass the answer into the verify function. Verify, if 15 // non-nil, should check the answer for validity, returning an error that will 16 // be written out to the user, or nil if answer is valid. 17 // 18 // This function takes a scanner rather than an io.Reader to avoid the case 19 // where the scanner reads past the delimiter and thus might lose data. It is 20 // expected that this method will be used repeatedly with the same scanner if 21 // multiple queries are required. 22 func QueryVerify(question []byte, scanner *bufio.Scanner, w io.Writer, verify func(string) error) (answer string, err error) { 23 defer fmt.Fprint(w, "\n") 24 for { 25 if _, err = w.Write(question); err != nil { 26 return "", err 27 } 28 29 if !scanner.Scan() { 30 if err := scanner.Err(); err != nil { 31 return "", err 32 } 33 return "", io.EOF 34 } 35 answer = scanner.Text() 36 if verify == nil { 37 return answer, nil 38 } 39 err := verify(answer) 40 // valid answer, return it! 41 if err == nil { 42 return answer, nil 43 } 44 // invalid answer, inform user of problem and retry. 45 _, err = fmt.Fprint(w, err, "\n\n") 46 if err != nil { 47 return "", err 48 } 49 } 50 } 51 52 // MatchOptions returns a function that performs a case insensitive comparison 53 // against the given list of options. To make a verification function that 54 // accepts an empty default, include an empty string in the list. 55 func MatchOptions(options []string, err error) func(string) error { 56 return func(s string) error { 57 for _, opt := range options { 58 if strings.ToLower(opt) == strings.ToLower(s) { 59 return nil 60 } 61 } 62 return err 63 } 64 } 65 66 // FindMatch does a case-insensitive search of the given options and returns the 67 // matching option. Found reports whether s was found in the options. 68 func FindMatch(s string, options []string) (match string, found bool) { 69 for _, opt := range options { 70 if strings.ToLower(opt) == strings.ToLower(s) { 71 return opt, true 72 } 73 } 74 return "", false 75 }