1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
package command
import (
"bufio"
"context"
"fmt"
"io"
"strings"
"github.com/chzyer/readline"
"github.com/hashicorp/packer/helper/wrappedreadline"
"github.com/hashicorp/packer/helper/wrappedstreams"
"github.com/hashicorp/packer/packer"
"github.com/posener/complete"
)
var TiniestBuilder = strings.NewReader(`{
"builders": [
{
"type":"null",
"communicator": "none"
}
]
}`)
type ConsoleCommand struct {
Meta
}
func (c *ConsoleCommand) Run(args []string) int {
ctx := context.Background()
cfg, ret := c.ParseArgs(args)
if ret != 0 {
return ret
}
return c.RunContext(ctx, cfg)
}
func (c *ConsoleCommand) ParseArgs(args []string) (*ConsoleArgs, int) {
var cfg ConsoleArgs
flags := c.Meta.FlagSet("console", FlagSetVars)
flags.Usage = func() { c.Ui.Say(c.Help()) }
cfg.AddFlagSets(flags)
if err := flags.Parse(args); err != nil {
return &cfg, 1
}
args = flags.Args()
if len(args) == 1 {
cfg.Path = args[0]
}
return &cfg, 0
}
func (c *ConsoleCommand) RunContext(ctx context.Context, cla *ConsoleArgs) int {
packerStarter, ret := c.GetConfig(&cla.MetaArgs)
if ret != 0 {
return ret
}
_ = packerStarter.Initialize()
// Determine if stdin is a pipe. If so, we evaluate directly.
if c.StdinPiped() {
return c.modePiped(packerStarter)
}
return c.modeInteractive(packerStarter)
}
func (*ConsoleCommand) Help() string {
helpText := `
Usage: packer console [options] [TEMPLATE]
Creates a console for testing variable interpolation.
If a template is provided, this command will load the template and any
variables defined therein into its context to be referenced during
interpolation.
Options:
-var 'key=value' Variable for templates, can be used multiple times.
-var-file=path JSON or HCL2 file containing user variables. [ Note that even in HCL mode this expects file to contain JSON, a fix is comming soon ]
`
return strings.TrimSpace(helpText)
}
func (*ConsoleCommand) Synopsis() string {
return "creates a console for testing variable interpolation"
}
func (*ConsoleCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictNothing
}
func (*ConsoleCommand) AutocompleteFlags() complete.Flags {
return complete.Flags{
"-var": complete.PredictNothing,
"-var-file": complete.PredictNothing,
}
}
func (c *ConsoleCommand) modePiped(cfg packer.Evaluator) int {
var lastResult string
scanner := bufio.NewScanner(wrappedstreams.Stdin())
ret := 0
for scanner.Scan() {
result, _, diags := cfg.EvaluateExpression(strings.TrimSpace(scanner.Text()))
if len(diags) > 0 {
ret = writeDiags(c.Ui, nil, diags)
}
// Store the last result
lastResult = result
}
// Output the final result
c.Ui.Message(lastResult)
return ret
}
func (c *ConsoleCommand) modeInteractive(cfg packer.Evaluator) int {
// Setup the UI so we can output directly to stdout
l, err := readline.NewEx(wrappedreadline.Override(&readline.Config{
Prompt: "> ",
InterruptPrompt: "^C",
EOFPrompt: "exit",
HistorySearchFold: true,
}))
if err != nil {
c.Ui.Error(fmt.Sprintf(
"Error initializing console: %s",
err))
return 1
}
for {
// Read a line
line, err := l.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
break
} else {
continue
}
} else if err == io.EOF {
break
}
out, exit, diags := cfg.EvaluateExpression(line)
ret := writeDiags(c.Ui, nil, diags)
if exit {
return ret
}
c.Ui.Say(out)
if exit {
return ret
}
}
return 0
}
|