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  }