github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/command/inspect.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/hashicorp/packer/template" 9 ) 10 11 type InspectCommand struct { 12 Meta 13 } 14 15 func (c *InspectCommand) Run(args []string) int { 16 flags := c.Meta.FlagSet("inspect", FlagSetNone) 17 flags.Usage = func() { c.Ui.Say(c.Help()) } 18 if err := flags.Parse(args); err != nil { 19 return 1 20 } 21 22 args = flags.Args() 23 if len(args) != 1 { 24 flags.Usage() 25 return 1 26 } 27 28 // Parse the template 29 tpl, err := template.ParseFile(args[0]) 30 if err != nil { 31 c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err)) 32 return 1 33 } 34 35 // Convenience... 36 ui := c.Ui 37 38 // Description 39 if tpl.Description != "" { 40 ui.Say("Description:\n") 41 ui.Say(tpl.Description + "\n") 42 } 43 44 // Variables 45 if len(tpl.Variables) == 0 { 46 ui.Say("Variables:\n") 47 ui.Say(" <No variables>") 48 } else { 49 requiredHeader := false 50 for k, v := range tpl.Variables { 51 if v.Required { 52 if !requiredHeader { 53 requiredHeader = true 54 ui.Say("Required variables:\n") 55 } 56 57 ui.Machine("template-variable", k, v.Default, "1") 58 ui.Say(" " + k) 59 } 60 } 61 62 if requiredHeader { 63 ui.Say("") 64 } 65 66 ui.Say("Optional variables and their defaults:\n") 67 keys := make([]string, 0, len(tpl.Variables)) 68 max := 0 69 for k := range tpl.Variables { 70 keys = append(keys, k) 71 if len(k) > max { 72 max = len(k) 73 } 74 } 75 76 sort.Strings(keys) 77 78 for _, k := range keys { 79 v := tpl.Variables[k] 80 if v.Required { 81 continue 82 } 83 84 padding := strings.Repeat(" ", max-len(k)) 85 output := fmt.Sprintf(" %s%s = %s", k, padding, v.Default) 86 87 ui.Machine("template-variable", k, v.Default, "0") 88 ui.Say(output) 89 } 90 } 91 92 ui.Say("") 93 94 // Builders 95 ui.Say("Builders:\n") 96 if len(tpl.Builders) == 0 { 97 ui.Say(" <No builders>") 98 } else { 99 keys := make([]string, 0, len(tpl.Builders)) 100 max := 0 101 for k := range tpl.Builders { 102 keys = append(keys, k) 103 if len(k) > max { 104 max = len(k) 105 } 106 } 107 108 sort.Strings(keys) 109 110 for _, k := range keys { 111 v := tpl.Builders[k] 112 padding := strings.Repeat(" ", max-len(k)) 113 output := fmt.Sprintf(" %s%s", k, padding) 114 if v.Name != v.Type { 115 output = fmt.Sprintf("%s (%s)", output, v.Type) 116 } 117 118 ui.Machine("template-builder", k, v.Type) 119 ui.Say(output) 120 121 } 122 } 123 124 ui.Say("") 125 126 // Provisioners 127 ui.Say("Provisioners:\n") 128 if len(tpl.Provisioners) == 0 { 129 ui.Say(" <No provisioners>") 130 } else { 131 for _, v := range tpl.Provisioners { 132 ui.Machine("template-provisioner", v.Type) 133 ui.Say(fmt.Sprintf(" %s", v.Type)) 134 } 135 } 136 137 ui.Say("\nNote: If your build names contain user variables or template\n" + 138 "functions such as 'timestamp', these are processed at build time,\n" + 139 "and therefore only show in their raw form here.") 140 141 return 0 142 } 143 144 func (*InspectCommand) Help() string { 145 helpText := ` 146 Usage: packer inspect TEMPLATE 147 148 Inspects a template, parsing and outputting the components a template 149 defines. This does not validate the contents of a template (other than 150 basic syntax by necessity). 151 152 Options: 153 154 -machine-readable Machine-readable output 155 ` 156 157 return strings.TrimSpace(helpText) 158 } 159 160 func (c *InspectCommand) Synopsis() string { 161 return "see components of a template" 162 }