162 lines
3.4 KiB
Go
162 lines
3.4 KiB
Go
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
|
|
}
|