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