From 89be12ae21ea3b843c69655dbc6c988276c943dd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 11 Aug 2013 19:05:07 -0700 Subject: [PATCH] packer: Add MachineReadableUi --- packer/ui.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ packer/ui_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/packer/ui.go b/packer/ui.go index ef8dc5572..b2b10293a 100644 --- a/packer/ui.go +++ b/packer/ui.go @@ -11,6 +11,7 @@ import ( "runtime" "strings" "sync" + "time" "unicode" ) @@ -63,6 +64,12 @@ type BasicUi struct { interrupted bool } +// MachineReadableUi is a UI that only outputs machine-readable output +// to the given Writer. +type MachineReadableUi struct { + Writer io.Writer +} + func (u *ColoredUi) Ask(query string) (string, error) { return u.Ui.Ask(u.colorize(query, u.Color, true)) } @@ -232,3 +239,42 @@ func (rw *BasicUi) Error(message string) { func (rw *BasicUi) Machine(t string, args ...string) { log.Printf("machine readable: %s %#v", t, args) } + +func (u *MachineReadableUi) Ask(query string) (string, error) { + return "", errors.New("machine-readable UI can't ask") +} + +func (u *MachineReadableUi) Say(message string) { + u.Machine("ui", "say", message) +} + +func (u *MachineReadableUi) Message(message string) { + u.Machine("ui", "message", message) +} + +func (u *MachineReadableUi) Error(message string) { + u.Machine("ui", "error", message) +} + +func (u *MachineReadableUi) Machine(category string, args ...string) { + now := time.Now().UTC() + + // Determine if we have a target, and set it + target := "" + commaIdx := strings.Index(category, ",") + if commaIdx > -1 { + target = category[0:commaIdx] + category = category[commaIdx+1:] + } + + // Prepare the args + for i, v := range args { + args[i] = strings.Replace(v, ",", "%!(PACKER_COMMA)", -1) + } + argsString := strings.Join(args, ",") + + _, err := fmt.Fprintf(u.Writer, "%d,%s,%s,%s", now.Unix(), target, category, argsString) + if err != nil { + panic(err) + } +} diff --git a/packer/ui_test.go b/packer/ui_test.go index 13ed53a18..b5cb0f345 100644 --- a/packer/ui_test.go +++ b/packer/ui_test.go @@ -3,6 +3,7 @@ package packer import ( "bytes" "cgl.tideland.biz/asserts" + "strings" "testing" ) @@ -106,6 +107,44 @@ func TestBasicUi_Say(t *testing.T) { assert.Equal(readWriter(bufferUi), "5\n", "formatting") } +func TestMachineReadableUi_ImplUi(t *testing.T) { + var raw interface{} + raw = &MachineReadableUi{} + if _, ok := raw.(Ui); !ok { + t.Fatalf("MachineReadableUi must implement Ui") + } +} + +func TestMachineReadableUi(t *testing.T) { + var data, expected string + + buf := new(bytes.Buffer) + ui := &MachineReadableUi{Writer: buf} + + ui.Machine("foo", "bar", "baz") + data = strings.SplitN(buf.String(), ",", 2)[1] + expected = ",foo,bar,baz" + if data != expected { + t.Fatalf("bad: %s", data) + } + + buf.Reset() + ui.Machine("mitchellh,foo", "bar", "baz") + data = strings.SplitN(buf.String(), ",", 2)[1] + expected = "mitchellh,foo,bar,baz" + if data != expected { + t.Fatalf("bad: %s", data) + } + + buf.Reset() + ui.Machine("foo", "foo,bar") + data = strings.SplitN(buf.String(), ",", 2)[1] + expected = ",foo,foo%!(PACKER_COMMA)bar" + if data != expected { + t.Fatalf("bad: %s", data) + } +} + // This reads the output from the bytes.Buffer in our test object // and then resets the buffer. func readWriter(ui *BasicUi) (result string) {