2014-10-27 23:31:02 -04:00
|
|
|
package command
|
2013-08-13 12:36:40 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"github.com/mitchellh/packer/packer"
|
|
|
|
"log"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2014-10-27 23:31:02 -04:00
|
|
|
type InspectCommand struct{
|
|
|
|
Meta
|
2013-08-13 12:36:40 -04:00
|
|
|
}
|
|
|
|
|
2014-10-27 23:31:02 -04:00
|
|
|
func (c *InspectCommand) Run(args []string) int {
|
|
|
|
env, err := c.Meta.Environment()
|
|
|
|
if err != nil {
|
|
|
|
c.Ui.Error(fmt.Sprintf("Error initializing environment: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
2013-08-13 12:36:40 -04:00
|
|
|
|
|
|
|
flags := flag.NewFlagSet("inspect", flag.ContinueOnError)
|
|
|
|
flags.Usage = func() { env.Ui().Say(c.Help()) }
|
|
|
|
if err := flags.Parse(args); err != nil {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
args = flags.Args()
|
|
|
|
if len(args) != 1 {
|
|
|
|
flags.Usage()
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the file into a byte array so that we can parse the template
|
2013-08-13 12:53:30 -04:00
|
|
|
log.Printf("Reading template: %#v", args[0])
|
2013-12-27 11:21:17 -05:00
|
|
|
tpl, err := packer.ParseTemplateFile(args[0], nil)
|
2013-08-13 12:36:40 -04:00
|
|
|
if err != nil {
|
|
|
|
env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convenience...
|
|
|
|
ui := env.Ui()
|
|
|
|
|
2013-12-11 16:48:18 -05:00
|
|
|
// Description
|
|
|
|
if tpl.Description != "" {
|
|
|
|
ui.Say("Description:\n")
|
2013-12-11 17:01:06 -05:00
|
|
|
ui.Say(tpl.Description + "\n")
|
2013-12-11 16:48:18 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 12:36:40 -04:00
|
|
|
// Variables
|
|
|
|
if len(tpl.Variables) == 0 {
|
2013-08-31 20:47:38 -04:00
|
|
|
ui.Say("Variables:\n")
|
2013-08-13 12:36:40 -04:00
|
|
|
ui.Say(" <No variables>")
|
|
|
|
} else {
|
2013-08-31 20:49:22 -04:00
|
|
|
requiredHeader := false
|
2013-08-31 20:47:38 -04:00
|
|
|
for k, v := range tpl.Variables {
|
|
|
|
if v.Required {
|
2013-08-31 20:49:22 -04:00
|
|
|
if !requiredHeader {
|
|
|
|
requiredHeader = true
|
|
|
|
ui.Say("Required variables:\n")
|
|
|
|
}
|
|
|
|
|
2013-08-31 20:47:38 -04:00
|
|
|
ui.Machine("template-variable", k, v.Default, "1")
|
|
|
|
ui.Say(" " + k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-31 20:49:22 -04:00
|
|
|
if requiredHeader {
|
|
|
|
ui.Say("")
|
|
|
|
}
|
|
|
|
|
2013-08-31 20:47:38 -04:00
|
|
|
ui.Say("Optional variables and their defaults:\n")
|
2013-08-13 12:36:40 -04:00
|
|
|
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]
|
2013-08-31 20:47:38 -04:00
|
|
|
if v.Required {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2013-08-13 12:36:40 -04:00
|
|
|
padding := strings.Repeat(" ", max-len(k))
|
2013-09-02 18:38:57 -04:00
|
|
|
output := fmt.Sprintf(" %s%s = %s", k, padding, v.Default)
|
2013-08-13 12:36:40 -04:00
|
|
|
|
2013-08-31 20:47:38 -04:00
|
|
|
ui.Machine("template-variable", k, v.Default, "0")
|
2013-08-13 12:36:40 -04:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2013-08-13 21:35:01 -04:00
|
|
|
ui.Machine("template-builder", k, v.Type)
|
2013-08-13 12:36:40 -04:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-27 11:43:59 -05:00
|
|
|
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.")
|
|
|
|
|
2013-08-13 12:36:40 -04:00
|
|
|
return 0
|
|
|
|
}
|
2014-10-27 23:31:02 -04:00
|
|
|
|
|
|
|
func (*InspectCommand) Help() string {
|
|
|
|
helpText := `
|
|
|
|
Usage: packer inspect TEMPLATE
|
|
|
|
|
|
|
|
Inspects a template, parsing and outputting the components a template
|
|
|
|
defines. This does not validate the contents of a template (other than
|
|
|
|
basic syntax by necessity).
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
|
|
|
-machine-readable Machine-readable output
|
|
|
|
`
|
|
|
|
|
|
|
|
return strings.TrimSpace(helpText)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *InspectCommand) Synopsis() string {
|
|
|
|
return "see components of a template"
|
|
|
|
}
|