Merge pull request #4479 from ashb/ui-ask-whole-line

Use bufio.Scanner in BasicUi.Ask so we can read whole lines
This commit is contained in:
Matthew Hooker 2017-01-30 11:37:37 -08:00 committed by GitHub
commit 866e06195b
2 changed files with 56 additions and 3 deletions

View File

@ -1,6 +1,7 @@
package packer package packer
import ( import (
"bufio"
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
@ -64,6 +65,7 @@ type BasicUi struct {
ErrorWriter io.Writer ErrorWriter io.Writer
l sync.Mutex l sync.Mutex
interrupted bool interrupted bool
scanner *bufio.Scanner
} }
// MachineReadableUi is a UI that only outputs machine-readable output // MachineReadableUi is a UI that only outputs machine-readable output
@ -174,6 +176,9 @@ func (rw *BasicUi) Ask(query string) (string, error) {
return "", errors.New("interrupted") return "", errors.New("interrupted")
} }
if rw.scanner == nil {
rw.scanner = bufio.NewScanner(rw.Reader)
}
sigCh := make(chan os.Signal, 1) sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt) signal.Notify(sigCh, os.Interrupt)
defer signal.Stop(sigCh) defer signal.Stop(sigCh)
@ -188,10 +193,13 @@ func (rw *BasicUi) Ask(query string) (string, error) {
result := make(chan string, 1) result := make(chan string, 1)
go func() { go func() {
var line string var line string
if _, err := fmt.Fscanln(rw.Reader, &line); err != nil { if rw.scanner.Scan() {
log.Printf("ui: scan err: %s", err) line = rw.scanner.Text()
}
if err := rw.scanner.Err(); err != nil {
log.Printf("ui: scan err: %s", err)
return
} }
result <- line result <- line
}() }()

View File

@ -16,6 +16,12 @@ func readWriter(ui *BasicUi) (result string) {
return return
} }
// Reset the input Reader than add some input to it.
func writeReader(ui *BasicUi, input string) {
buffer := ui.Reader.(*bytes.Buffer)
buffer.WriteString(input)
}
func readErrorWriter(ui *BasicUi) (result string) { func readErrorWriter(ui *BasicUi) (result string) {
buffer := ui.ErrorWriter.(*bytes.Buffer) buffer := ui.ErrorWriter.(*bytes.Buffer)
result = buffer.String() result = buffer.String()
@ -192,6 +198,45 @@ func TestBasicUi_Say(t *testing.T) {
} }
} }
func TestBasicUi_Ask(t *testing.T) {
var actual, expected string
var err error
var testCases = []struct {
Prompt, Input, Answer string
}{
{"[c]ontinue or [a]bort", "c\n", "c"},
{"[c]ontinue or [a]bort", "c", "c"},
// Empty input shouldn't give an error
{"Name", "Joe Bloggs\n", "Joe Bloggs"},
{"Name", "Joe Bloggs", "Joe Bloggs"},
{"Name", "\n", ""},
}
for _, testCase := range testCases {
// Because of the internal bufio we can't eaily reset the input, so create a new one each time
bufferUi := testUi()
writeReader(bufferUi, testCase.Input)
actual, err = bufferUi.Ask(testCase.Prompt)
if err != nil {
t.Fatal(err)
}
if actual != testCase.Answer {
t.Fatalf("bad answer: %#v", actual)
}
actual = readWriter(bufferUi)
expected = testCase.Prompt + " "
if actual != expected {
t.Fatalf("bad prompt: %#v", actual)
}
}
}
func TestMachineReadableUi_ImplUi(t *testing.T) { func TestMachineReadableUi_ImplUi(t *testing.T) {
var raw interface{} var raw interface{}
raw = &MachineReadableUi{} raw = &MachineReadableUi{}