hcl2: inspect command
This commit is contained in:
parent
a96a8f22b9
commit
51d02f8c2d
|
@ -121,3 +121,12 @@ type ValidateArgs struct {
|
|||
MetaArgs
|
||||
SyntaxOnly bool
|
||||
}
|
||||
|
||||
func (va *InspectArgs) AddFlagSets(flags *flag.FlagSet) {
|
||||
va.MetaArgs.AddFlagSets(flags)
|
||||
}
|
||||
|
||||
// InspectArgs represents a parsed cli line for a `packer inspect`
|
||||
type InspectArgs struct {
|
||||
MetaArgs
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_piping(t *testing.T) {
|
||||
func Test_console(t *testing.T) {
|
||||
|
||||
tc := []struct {
|
||||
piped string
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/template"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
|
@ -15,142 +13,40 @@ type InspectCommand struct {
|
|||
}
|
||||
|
||||
func (c *InspectCommand) Run(args []string) int {
|
||||
flags := c.Meta.FlagSet("inspect", FlagSetNone)
|
||||
ctx := context.Background()
|
||||
|
||||
cfg, ret := c.ParseArgs(args)
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
return c.RunContext(ctx, cfg)
|
||||
}
|
||||
|
||||
func (c *InspectCommand) ParseArgs(args []string) (*InspectArgs, int) {
|
||||
var cfg InspectArgs
|
||||
flags := c.Meta.FlagSet("inspect", FlagSetVars)
|
||||
flags.Usage = func() { c.Ui.Say(c.Help()) }
|
||||
cfg.AddFlagSets(flags)
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
return &cfg, 1
|
||||
}
|
||||
|
||||
args = flags.Args()
|
||||
if len(args) != 1 {
|
||||
flags.Usage()
|
||||
return 1
|
||||
if len(args) == 1 {
|
||||
cfg.Path = args[0]
|
||||
}
|
||||
return &cfg, 0
|
||||
}
|
||||
|
||||
// Parse the template
|
||||
tpl, err := template.ParseFile(args[0])
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err))
|
||||
return 1
|
||||
func (c *InspectCommand) RunContext(ctx context.Context, cla *InspectArgs) int {
|
||||
packerStarter, ret := c.GetConfig(&cla.MetaArgs)
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
// Convenience...
|
||||
ui := c.Ui
|
||||
|
||||
// Description
|
||||
if tpl.Description != "" {
|
||||
ui.Say("Description:\n")
|
||||
ui.Say(tpl.Description + "\n")
|
||||
}
|
||||
|
||||
// Variables
|
||||
if len(tpl.Variables) == 0 {
|
||||
ui.Say("Variables:\n")
|
||||
ui.Say(" <No variables>")
|
||||
} else {
|
||||
requiredHeader := false
|
||||
for k, v := range tpl.Variables {
|
||||
for _, sensitive := range tpl.SensitiveVariables {
|
||||
if ok := strings.Compare(sensitive.Default, v.Default); ok == 0 {
|
||||
v.Default = "<sensitive>"
|
||||
}
|
||||
}
|
||||
if v.Required {
|
||||
if !requiredHeader {
|
||||
requiredHeader = true
|
||||
ui.Say("Required variables:\n")
|
||||
}
|
||||
|
||||
ui.Machine("template-variable", k, v.Default, "1")
|
||||
ui.Say(" " + k)
|
||||
}
|
||||
}
|
||||
|
||||
if requiredHeader {
|
||||
ui.Say("")
|
||||
}
|
||||
|
||||
ui.Say("Optional variables and their defaults:\n")
|
||||
keys := make([]string, 0, len(tpl.Variables))
|
||||
max := 0
|
||||
for k := range tpl.Variables {
|
||||
keys = append(keys, k)
|
||||
if len(k) > max {
|
||||
max = len(k)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
v := tpl.Variables[k]
|
||||
if v.Required {
|
||||
continue
|
||||
}
|
||||
for _, sensitive := range tpl.SensitiveVariables {
|
||||
if ok := strings.Compare(sensitive.Default, v.Default); ok == 0 {
|
||||
v.Default = "<sensitive>"
|
||||
}
|
||||
}
|
||||
|
||||
padding := strings.Repeat(" ", max-len(k))
|
||||
output := fmt.Sprintf(" %s%s = %s", k, padding, v.Default)
|
||||
|
||||
ui.Machine("template-variable", k, v.Default, "0")
|
||||
ui.Say(output)
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("")
|
||||
|
||||
// Builders
|
||||
ui.Say("Builders:\n")
|
||||
if len(tpl.Builders) == 0 {
|
||||
ui.Say(" <No builders>")
|
||||
} else {
|
||||
keys := make([]string, 0, len(tpl.Builders))
|
||||
max := 0
|
||||
for k := range tpl.Builders {
|
||||
keys = append(keys, k)
|
||||
if len(k) > max {
|
||||
max = len(k)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
v := tpl.Builders[k]
|
||||
padding := strings.Repeat(" ", max-len(k))
|
||||
output := fmt.Sprintf(" %s%s", k, padding)
|
||||
if v.Name != v.Type {
|
||||
output = fmt.Sprintf("%s (%s)", output, v.Type)
|
||||
}
|
||||
|
||||
ui.Machine("template-builder", k, v.Type)
|
||||
ui.Say(output)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("")
|
||||
|
||||
// Provisioners
|
||||
ui.Say("Provisioners:\n")
|
||||
if len(tpl.Provisioners) == 0 {
|
||||
ui.Say(" <No provisioners>")
|
||||
} else {
|
||||
for _, v := range tpl.Provisioners {
|
||||
ui.Machine("template-provisioner", v.Type)
|
||||
ui.Say(fmt.Sprintf(" %s", v.Type))
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("\nNote: If your build names contain user variables or template\n" +
|
||||
"functions such as 'timestamp', these are processed at build time,\n" +
|
||||
"and therefore only show in their raw form here.")
|
||||
|
||||
return 0
|
||||
return packerStarter.InspectConfig(packer.InspectConfigOptions{
|
||||
Ui: c.Ui,
|
||||
})
|
||||
}
|
||||
|
||||
func (*InspectCommand) Help() string {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
package command
|
|
@ -439,24 +439,62 @@ func (p *PackerConfig) EvaluateExpression(line string) (out string, exit bool, d
|
|||
case line == "help":
|
||||
return PackerConsoleHelp, false, nil
|
||||
case line == "variables":
|
||||
out := &strings.Builder{}
|
||||
out.WriteString("> input-variables:\n\n")
|
||||
for _, v := range p.InputVariables {
|
||||
val, _ := v.Value()
|
||||
fmt.Fprintf(out, "var.%s: %q [debug: %#v]\n", v.Name, PrintableCtyValue(val), v)
|
||||
}
|
||||
out.WriteString("\n> local-variables:\n\n")
|
||||
for _, v := range p.LocalVariables {
|
||||
val, _ := v.Value()
|
||||
fmt.Fprintf(out, "local.%s: %q\n", v.Name, PrintableCtyValue(val))
|
||||
}
|
||||
|
||||
return out.String(), false, nil
|
||||
return p.printVariables(), false, nil
|
||||
default:
|
||||
return p.handleEval(line)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PackerConfig) printVariables() string {
|
||||
out := &strings.Builder{}
|
||||
out.WriteString("> input-variables:\n\n")
|
||||
for _, v := range p.InputVariables {
|
||||
val, _ := v.Value()
|
||||
fmt.Fprintf(out, "var.%s: %q [debug: %#v]\n", v.Name, PrintableCtyValue(val), v)
|
||||
}
|
||||
out.WriteString("\n> local-variables:\n\n")
|
||||
for _, v := range p.LocalVariables {
|
||||
val, _ := v.Value()
|
||||
fmt.Fprintf(out, "local.%s: %q\n", v.Name, PrintableCtyValue(val))
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func (p *PackerConfig) printBuilds() string {
|
||||
out := &strings.Builder{}
|
||||
out.WriteString("> builds:\n")
|
||||
for i, build := range p.Builds {
|
||||
name := build.Name
|
||||
if name == "" {
|
||||
name = fmt.Sprintf("<unnamed build %d>", i)
|
||||
}
|
||||
fmt.Fprintf(out, "\n > %s:\n", name)
|
||||
fmt.Fprintf(out, "\n provisioners:\n\n")
|
||||
if len(build.ProvisionerBlocks) == 0 {
|
||||
fmt.Fprintf(out, " <no provisioner>\n")
|
||||
}
|
||||
for _, prov := range build.ProvisionerBlocks {
|
||||
str := prov.PType
|
||||
if prov.PName != "" {
|
||||
str = strings.Join([]string{prov.PType, prov.PName}, ".")
|
||||
}
|
||||
fmt.Fprintf(out, " %s\n", str)
|
||||
}
|
||||
fmt.Fprintf(out, "\n post-processors:\n\n")
|
||||
if len(build.PostProcessors) == 0 {
|
||||
fmt.Fprintf(out, " <no post-processor>\n")
|
||||
}
|
||||
for _, pp := range build.PostProcessors {
|
||||
str := strings.Join([]string{pp.PType, pp.PName}, ".")
|
||||
if pp.PName != "" {
|
||||
str = strings.Join([]string{pp.PType, pp.PName}, ".")
|
||||
}
|
||||
fmt.Fprintf(out, " %s\n", str)
|
||||
}
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func (p *PackerConfig) handleEval(line string) (out string, exit bool, diags hcl.Diagnostics) {
|
||||
|
||||
// Parse the given line as an expression
|
||||
|
@ -479,3 +517,12 @@ func (p *PackerConfig) FixConfig(_ packer.FixConfigOptions) (diags hcl.Diagnosti
|
|||
// No Fixers exist for HCL2 configs so there is nothing to do here for now.
|
||||
return
|
||||
}
|
||||
|
||||
func (p *PackerConfig) InspectConfig(opts packer.InspectConfigOptions) int {
|
||||
|
||||
ui := opts.Ui
|
||||
ui.Say("Packer Inspect: HCL2 mode\n")
|
||||
ui.Say(p.printVariables())
|
||||
ui.Say(p.printBuilds())
|
||||
return 0
|
||||
}
|
||||
|
|
123
packer/core.go
123
packer/core.go
|
@ -424,6 +424,129 @@ func (c *Core) EvaluateExpression(line string) (string, bool, hcl.Diagnostics) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Core) InspectConfig(opts InspectConfigOptions) int {
|
||||
|
||||
// Convenience...
|
||||
ui := opts.Ui
|
||||
tpl := c.Template
|
||||
ui.Say("Packer Inspect: JSON mode")
|
||||
|
||||
// Description
|
||||
if tpl.Description != "" {
|
||||
ui.Say("Description:\n")
|
||||
ui.Say(tpl.Description + "\n")
|
||||
}
|
||||
|
||||
// Variables
|
||||
if len(tpl.Variables) == 0 {
|
||||
ui.Say("Variables:\n")
|
||||
ui.Say(" <No variables>")
|
||||
} else {
|
||||
requiredHeader := false
|
||||
for k, v := range tpl.Variables {
|
||||
for _, sensitive := range tpl.SensitiveVariables {
|
||||
if ok := strings.Compare(sensitive.Default, v.Default); ok == 0 {
|
||||
v.Default = "<sensitive>"
|
||||
}
|
||||
}
|
||||
if v.Required {
|
||||
if !requiredHeader {
|
||||
requiredHeader = true
|
||||
ui.Say("Required variables:\n")
|
||||
}
|
||||
|
||||
ui.Machine("template-variable", k, v.Default, "1")
|
||||
ui.Say(" " + k)
|
||||
}
|
||||
}
|
||||
|
||||
if requiredHeader {
|
||||
ui.Say("")
|
||||
}
|
||||
|
||||
ui.Say("Optional variables and their defaults:\n")
|
||||
keys := make([]string, 0, len(tpl.Variables))
|
||||
max := 0
|
||||
for k := range tpl.Variables {
|
||||
keys = append(keys, k)
|
||||
if len(k) > max {
|
||||
max = len(k)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
v := tpl.Variables[k]
|
||||
if v.Required {
|
||||
continue
|
||||
}
|
||||
for _, sensitive := range tpl.SensitiveVariables {
|
||||
if ok := strings.Compare(sensitive.Default, v.Default); ok == 0 {
|
||||
v.Default = "<sensitive>"
|
||||
}
|
||||
}
|
||||
|
||||
padding := strings.Repeat(" ", max-len(k))
|
||||
output := fmt.Sprintf(" %s%s = %s", k, padding, v.Default)
|
||||
|
||||
ui.Machine("template-variable", k, v.Default, "0")
|
||||
ui.Say(output)
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("")
|
||||
|
||||
// Builders
|
||||
ui.Say("Builders:\n")
|
||||
if len(tpl.Builders) == 0 {
|
||||
ui.Say(" <No builders>")
|
||||
} else {
|
||||
keys := make([]string, 0, len(tpl.Builders))
|
||||
max := 0
|
||||
for k := range tpl.Builders {
|
||||
keys = append(keys, k)
|
||||
if len(k) > max {
|
||||
max = len(k)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
v := tpl.Builders[k]
|
||||
padding := strings.Repeat(" ", max-len(k))
|
||||
output := fmt.Sprintf(" %s%s", k, padding)
|
||||
if v.Name != v.Type {
|
||||
output = fmt.Sprintf("%s (%s)", output, v.Type)
|
||||
}
|
||||
|
||||
ui.Machine("template-builder", k, v.Type)
|
||||
ui.Say(output)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("")
|
||||
|
||||
// Provisioners
|
||||
ui.Say("Provisioners:\n")
|
||||
if len(tpl.Provisioners) == 0 {
|
||||
ui.Say(" <No provisioners>")
|
||||
} else {
|
||||
for _, v := range tpl.Provisioners {
|
||||
ui.Machine("template-provisioner", v.Type)
|
||||
ui.Say(fmt.Sprintf(" %s", v.Type))
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("\nNote: If your build names contain user variables or template\n" +
|
||||
"functions such as 'timestamp', these are processed at build time,\n" +
|
||||
"and therefore only show in their raw form here.")
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *Core) FixConfig(opts FixConfigOptions) hcl.Diagnostics {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ type Handler interface {
|
|||
Evaluator
|
||||
BuildGetter
|
||||
ConfigFixer
|
||||
ConfigInspector
|
||||
}
|
||||
|
||||
//go:generate enumer -type FixConfigMode
|
||||
|
@ -52,3 +53,12 @@ type ConfigFixer interface {
|
|||
// FixConfig will output the config in a fixed manner.
|
||||
FixConfig(FixConfigOptions) hcl.Diagnostics
|
||||
}
|
||||
|
||||
type InspectConfigOptions struct {
|
||||
Ui
|
||||
}
|
||||
|
||||
type ConfigInspector interface {
|
||||
// Inspect will output self inspection for a configuration
|
||||
InspectConfig(InspectConfigOptions) (ret int)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue