2013-03-24 17:03:53 -04:00
|
|
|
package packer
|
|
|
|
|
2013-05-21 02:43:37 -04:00
|
|
|
import (
|
2013-07-02 15:28:25 -04:00
|
|
|
"bytes"
|
2013-06-15 21:24:38 -04:00
|
|
|
"errors"
|
2013-05-21 02:43:37 -04:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2013-05-21 14:40:07 -04:00
|
|
|
"log"
|
2013-06-14 18:59:54 -04:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2013-07-02 15:28:25 -04:00
|
|
|
"strings"
|
2013-06-14 18:17:03 -04:00
|
|
|
"sync"
|
2013-07-09 14:21:42 -04:00
|
|
|
"unicode"
|
2013-05-21 02:43:37 -04:00
|
|
|
)
|
2013-03-24 17:03:53 -04:00
|
|
|
|
2013-06-03 16:35:43 -04:00
|
|
|
type UiColor uint
|
|
|
|
|
|
|
|
const (
|
|
|
|
UiColorRed UiColor = 31
|
|
|
|
UiColorGreen = 32
|
|
|
|
UiColorYellow = 33
|
|
|
|
UiColorBlue = 34
|
|
|
|
UiColorMagenta = 35
|
|
|
|
UiColorCyan = 36
|
|
|
|
)
|
|
|
|
|
2013-03-24 17:03:53 -04:00
|
|
|
// The Ui interface handles all communication for Packer with the outside
|
|
|
|
// world. This sort of control allows us to strictly control how output
|
|
|
|
// is formatted and various levels of output.
|
|
|
|
type Ui interface {
|
2013-06-15 21:24:38 -04:00
|
|
|
Ask(string) (string, error)
|
2013-05-27 18:12:48 -04:00
|
|
|
Say(string)
|
2013-06-03 14:30:38 -04:00
|
|
|
Message(string)
|
2013-05-27 18:12:48 -04:00
|
|
|
Error(string)
|
2013-03-24 17:03:53 -04:00
|
|
|
}
|
|
|
|
|
2013-06-03 16:35:43 -04:00
|
|
|
// ColoredUi is a UI that is colored using terminal colors.
|
|
|
|
type ColoredUi struct {
|
2013-06-12 13:41:58 -04:00
|
|
|
Color UiColor
|
|
|
|
ErrorColor UiColor
|
|
|
|
Ui Ui
|
2013-06-03 16:35:43 -04:00
|
|
|
}
|
|
|
|
|
2013-05-21 16:20:51 -04:00
|
|
|
// PrefixedUi is a UI that wraps another UI implementation and adds a
|
|
|
|
// prefix to all the messages going out.
|
|
|
|
type PrefixedUi struct {
|
2013-06-03 14:30:38 -04:00
|
|
|
SayPrefix string
|
|
|
|
MessagePrefix string
|
|
|
|
Ui Ui
|
2013-05-21 16:20:51 -04:00
|
|
|
}
|
|
|
|
|
2013-03-24 17:03:53 -04:00
|
|
|
// The ReaderWriterUi is a UI that writes and reads from standard Go
|
|
|
|
// io.Reader and io.Writer.
|
|
|
|
type ReaderWriterUi struct {
|
2013-06-15 21:25:34 -04:00
|
|
|
Reader io.Reader
|
|
|
|
Writer io.Writer
|
|
|
|
l sync.Mutex
|
|
|
|
interrupted bool
|
2013-06-14 18:17:03 -04:00
|
|
|
}
|
|
|
|
|
2013-06-15 21:24:38 -04:00
|
|
|
func (u *ColoredUi) Ask(query string) (string, error) {
|
2013-06-14 18:17:03 -04:00
|
|
|
return u.Ui.Ask(u.colorize(query, u.Color, true))
|
2013-03-24 17:03:53 -04:00
|
|
|
}
|
|
|
|
|
2013-06-03 16:35:43 -04:00
|
|
|
func (u *ColoredUi) Say(message string) {
|
2013-06-12 13:41:58 -04:00
|
|
|
u.Ui.Say(u.colorize(message, u.Color, true))
|
2013-06-03 16:35:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *ColoredUi) Message(message string) {
|
2013-06-12 13:41:58 -04:00
|
|
|
u.Ui.Message(u.colorize(message, u.Color, false))
|
2013-06-03 16:35:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *ColoredUi) Error(message string) {
|
2013-06-12 13:41:58 -04:00
|
|
|
color := u.ErrorColor
|
|
|
|
if color == 0 {
|
|
|
|
color = UiColorRed
|
|
|
|
}
|
|
|
|
|
|
|
|
u.Ui.Error(u.colorize(message, color, true))
|
2013-06-03 16:35:43 -04:00
|
|
|
}
|
|
|
|
|
2013-06-12 13:41:58 -04:00
|
|
|
func (u *ColoredUi) colorize(message string, color UiColor, bold bool) string {
|
2013-06-03 16:49:59 -04:00
|
|
|
attr := 0
|
|
|
|
if bold {
|
|
|
|
attr = 1
|
|
|
|
}
|
|
|
|
|
2013-06-12 13:41:58 -04:00
|
|
|
return fmt.Sprintf("\033[%d;%d;40m%s\033[0m", attr, color, message)
|
2013-06-03 16:35:43 -04:00
|
|
|
}
|
|
|
|
|
2013-06-15 21:24:38 -04:00
|
|
|
func (u *PrefixedUi) Ask(query string) (string, error) {
|
2013-07-02 15:28:25 -04:00
|
|
|
return u.Ui.Ask(u.prefixLines(u.SayPrefix, query))
|
2013-06-14 18:17:03 -04:00
|
|
|
}
|
|
|
|
|
2013-05-27 18:12:48 -04:00
|
|
|
func (u *PrefixedUi) Say(message string) {
|
2013-07-02 15:28:25 -04:00
|
|
|
u.Ui.Say(u.prefixLines(u.SayPrefix, message))
|
2013-06-03 14:30:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *PrefixedUi) Message(message string) {
|
2013-07-02 15:28:25 -04:00
|
|
|
u.Ui.Message(u.prefixLines(u.MessagePrefix, message))
|
2013-05-21 16:20:51 -04:00
|
|
|
}
|
|
|
|
|
2013-05-27 18:12:48 -04:00
|
|
|
func (u *PrefixedUi) Error(message string) {
|
2013-07-02 15:28:25 -04:00
|
|
|
u.Ui.Error(u.prefixLines(u.SayPrefix, message))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *PrefixedUi) prefixLines(prefix, message string) string {
|
|
|
|
var result bytes.Buffer
|
|
|
|
|
|
|
|
for _, line := range strings.Split(message, "\n") {
|
|
|
|
result.WriteString(fmt.Sprintf("%s: %s\n", prefix, line))
|
|
|
|
}
|
|
|
|
|
2013-07-09 14:21:42 -04:00
|
|
|
return strings.TrimRightFunc(result.String(), unicode.IsSpace)
|
2013-05-21 16:20:51 -04:00
|
|
|
}
|
|
|
|
|
2013-06-15 21:24:38 -04:00
|
|
|
func (rw *ReaderWriterUi) Ask(query string) (string, error) {
|
2013-06-14 18:17:03 -04:00
|
|
|
rw.l.Lock()
|
|
|
|
defer rw.l.Unlock()
|
|
|
|
|
2013-06-15 21:25:34 -04:00
|
|
|
if rw.interrupted {
|
|
|
|
return "", errors.New("interrupted")
|
|
|
|
}
|
|
|
|
|
2013-06-14 18:59:54 -04:00
|
|
|
sigCh := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(sigCh, os.Interrupt)
|
|
|
|
defer signal.Stop(sigCh)
|
|
|
|
|
2013-06-14 18:17:03 -04:00
|
|
|
log.Printf("ui: ask: %s", query)
|
|
|
|
if query != "" {
|
|
|
|
if _, err := fmt.Fprint(rw.Writer, query+" "); err != nil {
|
2013-06-15 21:24:38 -04:00
|
|
|
return "", err
|
2013-06-14 18:17:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-14 18:59:54 -04:00
|
|
|
result := make(chan string, 1)
|
|
|
|
go func() {
|
|
|
|
var line string
|
|
|
|
if _, err := fmt.Fscanln(rw.Reader, &line); err != nil {
|
|
|
|
log.Printf("ui: scan err: %s", err)
|
|
|
|
}
|
2013-06-14 18:17:03 -04:00
|
|
|
|
2013-06-14 18:59:54 -04:00
|
|
|
result <- line
|
|
|
|
}()
|
|
|
|
|
2013-06-15 21:24:38 -04:00
|
|
|
select {
|
|
|
|
case line := <-result:
|
|
|
|
return line, nil
|
|
|
|
case <-sigCh:
|
2013-06-17 14:40:57 -04:00
|
|
|
// Print a newline so that any further output starts properly
|
|
|
|
// on a new line.
|
|
|
|
fmt.Fprintln(rw.Writer)
|
|
|
|
|
|
|
|
// Mark that we were interrupted so future Ask calls fail.
|
2013-06-15 21:25:34 -04:00
|
|
|
rw.interrupted = true
|
2013-06-17 14:40:57 -04:00
|
|
|
|
2013-06-15 21:24:38 -04:00
|
|
|
return "", errors.New("interrupted")
|
2013-06-14 18:59:54 -04:00
|
|
|
}
|
2013-06-14 18:17:03 -04:00
|
|
|
}
|
|
|
|
|
2013-05-27 18:12:48 -04:00
|
|
|
func (rw *ReaderWriterUi) Say(message string) {
|
2013-06-14 18:17:03 -04:00
|
|
|
rw.l.Lock()
|
|
|
|
defer rw.l.Unlock()
|
|
|
|
|
2013-05-27 18:12:48 -04:00
|
|
|
log.Printf("ui: %s", message)
|
|
|
|
_, err := fmt.Fprint(rw.Writer, message+"\n")
|
2013-05-08 20:09:10 -04:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2013-03-24 17:03:53 -04:00
|
|
|
}
|
2013-05-08 18:12:48 -04:00
|
|
|
|
2013-06-03 14:30:38 -04:00
|
|
|
func (rw *ReaderWriterUi) Message(message string) {
|
2013-06-14 18:17:03 -04:00
|
|
|
rw.l.Lock()
|
|
|
|
defer rw.l.Unlock()
|
|
|
|
|
2013-06-03 14:30:38 -04:00
|
|
|
log.Printf("ui: %s", message)
|
2013-06-24 02:06:59 -04:00
|
|
|
_, err := fmt.Fprint(rw.Writer, message+"\n")
|
2013-06-03 14:30:38 -04:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-27 18:12:48 -04:00
|
|
|
func (rw *ReaderWriterUi) Error(message string) {
|
2013-06-14 18:17:03 -04:00
|
|
|
rw.l.Lock()
|
|
|
|
defer rw.l.Unlock()
|
|
|
|
|
2013-05-27 18:12:48 -04:00
|
|
|
log.Printf("ui error: %s", message)
|
|
|
|
_, err := fmt.Fprint(rw.Writer, message+"\n")
|
2013-05-08 20:09:10 -04:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2013-05-08 18:12:48 -04:00
|
|
|
}
|