packer: Add "Ask" method to Ui to ask for input

This commit is contained in:
Mitchell Hashimoto 2013-06-14 15:17:03 -07:00
parent cbd3f59578
commit e0f2bcf8a2
7 changed files with 81 additions and 8 deletions

View File

@ -10,8 +10,8 @@ import (
func testEnvironment() packer.Environment { func testEnvironment() packer.Environment {
config := packer.DefaultEnvironmentConfig() config := packer.DefaultEnvironmentConfig()
config.Ui = &packer.ReaderWriterUi{ config.Ui = &packer.ReaderWriterUi{
new(bytes.Buffer), Reader: new(bytes.Buffer),
new(bytes.Buffer), Writer: new(bytes.Buffer),
} }
env, err := packer.NewEnvironment(config) env, err := packer.NewEnvironment(config)

View File

@ -68,7 +68,11 @@ type EnvironmentConfig struct {
func DefaultEnvironmentConfig() *EnvironmentConfig { func DefaultEnvironmentConfig() *EnvironmentConfig {
config := &EnvironmentConfig{} config := &EnvironmentConfig{}
config.Commands = make([]string, 0) config.Commands = make([]string, 0)
config.Ui = &ReaderWriterUi{os.Stdin, os.Stdout} config.Ui = &ReaderWriterUi{
Reader: os.Stdin,
Writer: os.Stdout,
}
return config return config
} }

View File

@ -13,8 +13,8 @@ import (
func testEnvironment() Environment { func testEnvironment() Environment {
config := DefaultEnvironmentConfig() config := DefaultEnvironmentConfig()
config.Ui = &ReaderWriterUi{ config.Ui = &ReaderWriterUi{
new(bytes.Buffer), Reader: new(bytes.Buffer),
new(bytes.Buffer), Writer: new(bytes.Buffer),
} }
env, err := NewEnvironment(config) env, err := NewEnvironment(config)
@ -292,7 +292,10 @@ func TestEnvironmentProvisioner_Error(t *testing.T) {
func TestEnvironment_SettingUi(t *testing.T) { func TestEnvironment_SettingUi(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true) assert := asserts.NewTestingAsserts(t, true)
ui := &ReaderWriterUi{new(bytes.Buffer), new(bytes.Buffer)} ui := &ReaderWriterUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
}
config := &EnvironmentConfig{} config := &EnvironmentConfig{}
config.Ui = ui config.Ui = ui

View File

@ -17,6 +17,15 @@ type UiServer struct {
ui packer.Ui ui packer.Ui
} }
func (u *Ui) Ask(query string) string {
var result string
if err := u.client.Call("Ui.Ask", query, &result); err != nil {
panic(err)
}
return result
}
func (u *Ui) Error(message string) { func (u *Ui) Error(message string) {
if err := u.client.Call("Ui.Error", message, new(interface{})); err != nil { if err := u.client.Call("Ui.Error", message, new(interface{})); err != nil {
panic(err) panic(err)
@ -35,6 +44,11 @@ func (u *Ui) Say(message string) {
} }
} }
func (u *UiServer) Ask(query string, reply *string) error {
*reply = u.ui.Ask(query)
return nil
}
func (u *UiServer) Error(message *string, reply *interface{}) error { func (u *UiServer) Error(message *string, reply *interface{}) error {
u.ui.Error(*message) u.ui.Error(*message)

View File

@ -7,6 +7,8 @@ import (
) )
type testUi struct { type testUi struct {
askCalled bool
askQuery string
errorCalled bool errorCalled bool
errorMessage string errorMessage string
messageCalled bool messageCalled bool
@ -15,6 +17,12 @@ type testUi struct {
sayMessage string sayMessage string
} }
func (u *testUi) Ask(query string) string {
u.askCalled = true
u.askQuery = query
return "foo"
}
func (u *testUi) Error(message string) { func (u *testUi) Error(message string) {
u.errorCalled = true u.errorCalled = true
u.errorMessage = message u.errorMessage = message
@ -50,6 +58,11 @@ func TestUiRPC(t *testing.T) {
uiClient := &Ui{client} uiClient := &Ui{client}
// Basic error and say tests // Basic error and say tests
result := uiClient.Ask("query")
assert.True(ui.askCalled, "ask should be called")
assert.Equal(ui.askQuery, "query", "should be correct")
assert.Equal(result, "foo", "should have correct result")
uiClient.Error("message") uiClient.Error("message")
assert.Equal(ui.errorMessage, "message", "message should be correct") assert.Equal(ui.errorMessage, "message", "message should be correct")

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"sync"
) )
type UiColor uint type UiColor uint
@ -21,6 +22,7 @@ const (
// world. This sort of control allows us to strictly control how output // world. This sort of control allows us to strictly control how output
// is formatted and various levels of output. // is formatted and various levels of output.
type Ui interface { type Ui interface {
Ask(string) string
Say(string) Say(string)
Message(string) Message(string)
Error(string) Error(string)
@ -46,6 +48,11 @@ type PrefixedUi struct {
type ReaderWriterUi struct { type ReaderWriterUi struct {
Reader io.Reader Reader io.Reader
Writer io.Writer Writer io.Writer
l sync.Mutex
}
func (u *ColoredUi) Ask(query string) string {
return u.Ui.Ask(u.colorize(query, u.Color, true))
} }
func (u *ColoredUi) Say(message string) { func (u *ColoredUi) Say(message string) {
@ -74,6 +81,10 @@ func (u *ColoredUi) colorize(message string, color UiColor, bold bool) string {
return fmt.Sprintf("\033[%d;%d;40m%s\033[0m", attr, color, message) return fmt.Sprintf("\033[%d;%d;40m%s\033[0m", attr, color, message)
} }
func (u *PrefixedUi) Ask(query string) string {
return u.Ui.Ask(fmt.Sprintf("%s: %s", u.SayPrefix, query))
}
func (u *PrefixedUi) Say(message string) { func (u *PrefixedUi) Say(message string) {
u.Ui.Say(fmt.Sprintf("%s: %s", u.SayPrefix, message)) u.Ui.Say(fmt.Sprintf("%s: %s", u.SayPrefix, message))
} }
@ -86,7 +97,29 @@ func (u *PrefixedUi) Error(message string) {
u.Ui.Error(fmt.Sprintf("%s: %s", u.SayPrefix, message)) u.Ui.Error(fmt.Sprintf("%s: %s", u.SayPrefix, message))
} }
func (rw *ReaderWriterUi) Ask(query string) string {
rw.l.Lock()
defer rw.l.Unlock()
log.Printf("ui: ask: %s", query)
if query != "" {
if _, err := fmt.Fprint(rw.Writer, query+" "); err != nil {
panic(err)
}
}
var line string
if _, err := fmt.Fscanln(rw.Reader, &line); err != nil {
panic(err)
}
return line
}
func (rw *ReaderWriterUi) Say(message string) { func (rw *ReaderWriterUi) Say(message string) {
rw.l.Lock()
defer rw.l.Unlock()
log.Printf("ui: %s", message) log.Printf("ui: %s", message)
_, err := fmt.Fprint(rw.Writer, message+"\n") _, err := fmt.Fprint(rw.Writer, message+"\n")
if err != nil { if err != nil {
@ -95,6 +128,9 @@ func (rw *ReaderWriterUi) Say(message string) {
} }
func (rw *ReaderWriterUi) Message(message string) { func (rw *ReaderWriterUi) Message(message string) {
rw.l.Lock()
defer rw.l.Unlock()
log.Printf("ui: %s", message) log.Printf("ui: %s", message)
_, err := fmt.Fprintf(rw.Writer, message+"\n") _, err := fmt.Fprintf(rw.Writer, message+"\n")
if err != nil { if err != nil {
@ -103,6 +139,9 @@ func (rw *ReaderWriterUi) Message(message string) {
} }
func (rw *ReaderWriterUi) Error(message string) { func (rw *ReaderWriterUi) Error(message string) {
rw.l.Lock()
defer rw.l.Unlock()
log.Printf("ui error: %s", message) log.Printf("ui error: %s", message)
_, err := fmt.Fprint(rw.Writer, message+"\n") _, err := fmt.Fprint(rw.Writer, message+"\n")
if err != nil { if err != nil {

View File

@ -8,8 +8,8 @@ import (
func testUi() *ReaderWriterUi { func testUi() *ReaderWriterUi {
return &ReaderWriterUi{ return &ReaderWriterUi{
new(bytes.Buffer), Reader: new(bytes.Buffer),
new(bytes.Buffer), Writer: new(bytes.Buffer),
} }
} }