github.com/hashicorp/packer@v1.14.3/command/cli.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package command 5 6 import ( 7 "flag" 8 "strings" 9 10 "github.com/hashicorp/packer/command/enumflag" 11 kvflag "github.com/hashicorp/packer/command/flag-kv" 12 sliceflag "github.com/hashicorp/packer/command/flag-slice" 13 ) 14 15 //go:generate enumer -type configType -trimprefix ConfigType -transform snake 16 type configType int 17 18 const ( 19 ConfigTypeJSON configType = iota // default config type 20 ConfigTypeHCL2 21 ) 22 23 func (c *configType) Set(value string) error { 24 v, err := configTypeString(value) 25 if err == nil { 26 *c = v 27 } 28 return err 29 } 30 31 // ConfigType tells what type of config we should use, it can return values 32 // like "hcl" or "json". 33 // Make sure Args was correctly set before. 34 func (ma *MetaArgs) GetConfigType() (configType, error) { 35 if ma.Path == "" { 36 return ma.ConfigType, nil 37 } 38 name := ma.Path 39 if name == "-" { 40 // TODO(azr): To allow piping HCL2 confs (when args is "-"), we probably 41 // will need to add a setting that says "this is an HCL config". 42 return ma.ConfigType, nil 43 } 44 if strings.HasSuffix(name, ".pkr.hcl") || 45 strings.HasSuffix(name, ".pkr.json") { 46 return ConfigTypeHCL2, nil 47 } 48 isDir, err := isDir(name) 49 if isDir { 50 return ConfigTypeHCL2, err 51 } 52 return ma.ConfigType, err 53 } 54 55 // NewMetaArgs parses cli args and put possible values 56 func (ma *MetaArgs) AddFlagSets(fs *flag.FlagSet) { 57 fs.Var((*sliceflag.StringFlag)(&ma.Only), "only", "") 58 fs.Var((*sliceflag.StringFlag)(&ma.Except), "except", "") 59 fs.Var((*kvflag.Flag)(&ma.Vars), "var", "") 60 fs.Var((*kvflag.StringSlice)(&ma.VarFiles), "var-file", "") 61 fs.Var(&ma.ConfigType, "config-type", "set to 'hcl2' to run in hcl2 mode when no file is passed.") 62 } 63 64 // MetaArgs defines commonalities between all commands 65 type MetaArgs struct { 66 // TODO(azr): in the future, I want to allow passing multiple path to 67 // merge HCL confs together; but this will probably need an RFC first. 68 Path string 69 Paths []string 70 Only, Except []string 71 Vars map[string]string 72 VarFiles []string 73 // set to "hcl2" to force hcl2 mode 74 ConfigType configType 75 76 // WarnOnUndeclared does not have a common default, as the default varies per sub-command usage. 77 // Refer to individual command FlagSets for usage. 78 WarnOnUndeclaredVar bool 79 // UseSequential specifies to use a sequential/phased approach for 80 // evaluating datasources/locals instead of a DAG. 81 // 82 // This allows users to fall-back to using the approach used by Packer 83 // before the introduction of a DAG in case they run in an impasse/bug. 84 UseSequential bool 85 } 86 87 func (ba *BuildArgs) AddFlagSets(flags *flag.FlagSet) { 88 flags.BoolVar(&ba.Color, "color", true, "") 89 flags.BoolVar(&ba.Debug, "debug", false, "") 90 flags.BoolVar(&ba.Force, "force", false, "") 91 flags.BoolVar(&ba.TimestampUi, "timestamp-ui", false, "") 92 flags.BoolVar(&ba.MachineReadable, "machine-readable", false, "") 93 94 flags.Int64Var(&ba.ParallelBuilds, "parallel-builds", 0, "") 95 96 flagOnError := enumflag.New(&ba.OnError, "cleanup", "abort", "ask", "run-cleanup-provisioner") 97 flags.Var(flagOnError, "on-error", "") 98 99 flags.BoolVar(&ba.MetaArgs.WarnOnUndeclaredVar, "warn-on-undeclared-var", false, "Show warnings for variable files containing undeclared variables.") 100 flags.BoolVar(&ba.MetaArgs.UseSequential, "use-sequential-evaluation", false, "Fallback to using a sequential approach for local/datasource evaluation.") 101 102 flags.BoolVar(&ba.ReleaseOnly, "ignore-prerelease-plugins", false, "Disable the loading of prerelease plugin binaries (x.y.z-dev).") 103 104 ba.MetaArgs.AddFlagSets(flags) 105 } 106 107 // GetCleanedBuildArgs returns a map containing build flags specified to build for tracking within 108 // the HCP Packer registry. 109 // 110 // Most of the arguments are kept as-is, except for the -var args, where only 111 // the keys are kept to avoid leaking potential secrets. 112 func GetCleanedBuildArgs(ba *BuildArgs) map[string]interface{} { 113 cleanedArgs := map[string]interface{}{ 114 "debug": ba.Debug, 115 "force": ba.Force, 116 "only": ba.Only, 117 "except": ba.Except, 118 "var-files": ba.VarFiles, 119 "path": ba.Path, 120 } 121 122 var varNames []string 123 for k := range ba.Vars { 124 varNames = append(varNames, k) 125 } 126 cleanedArgs["vars"] = varNames 127 128 return cleanedArgs 129 } 130 131 // BuildArgs represents a parsed cli line for a `packer build` 132 type BuildArgs struct { 133 MetaArgs 134 Debug, Force bool 135 Color, TimestampUi, MachineReadable bool 136 ParallelBuilds int64 137 OnError string 138 ReleaseOnly bool 139 } 140 141 func (ia *InitArgs) AddFlagSets(flags *flag.FlagSet) { 142 flags.BoolVar(&ia.Upgrade, "upgrade", false, "upgrade any present plugin to the highest allowed version.") 143 flags.BoolVar(&ia.Force, "force", false, "force installation of a plugin, even if already installed") 144 145 ia.MetaArgs.AddFlagSets(flags) 146 } 147 148 // InitArgs represents a parsed cli line for a `packer init <path>` 149 type InitArgs struct { 150 MetaArgs 151 Upgrade bool 152 Force bool 153 } 154 155 // PluginsRequiredArgs represents a parsed cli line for a `packer plugins required <path>` 156 type PluginsRequiredArgs struct { 157 MetaArgs 158 } 159 160 func (ca *ConsoleArgs) AddFlagSets(flags *flag.FlagSet) { 161 flags.BoolVar(&ca.MetaArgs.UseSequential, "use-sequential-evaluation", false, "Fallback to using a sequential approach for local/datasource evaluation.") 162 } 163 164 // ConsoleArgs represents a parsed cli line for a `packer console` 165 type ConsoleArgs struct { 166 MetaArgs 167 } 168 169 func (fa *FixArgs) AddFlagSets(flags *flag.FlagSet) { 170 flags.BoolVar(&fa.Validate, "validate", true, "") 171 172 fa.MetaArgs.AddFlagSets(flags) 173 } 174 175 // FixArgs represents a parsed cli line for a `packer fix` 176 type FixArgs struct { 177 MetaArgs 178 Validate bool 179 } 180 181 func (va *ValidateArgs) AddFlagSets(flags *flag.FlagSet) { 182 flags.BoolVar(&va.SyntaxOnly, "syntax-only", false, "check syntax only") 183 flags.BoolVar(&va.NoWarnUndeclaredVar, "no-warn-undeclared-var", false, "Ignore warnings for variable files containing undeclared variables.") 184 flags.BoolVar(&va.EvaluateDatasources, "evaluate-datasources", false, "evaluate datasources for validation (HCL2 only, may incur costs)") 185 flags.BoolVar(&va.ReleaseOnly, "ignore-prerelease-plugins", false, "Disable the loading of prerelease plugin binaries (x.y.z-dev).") 186 flags.BoolVar(&va.MetaArgs.UseSequential, "use-sequential-evaluation", false, "Fallback to using a sequential approach for local/datasource evaluation.") 187 188 va.MetaArgs.AddFlagSets(flags) 189 } 190 191 // ValidateArgs represents a parsed cli line for a `packer validate` 192 type ValidateArgs struct { 193 MetaArgs 194 SyntaxOnly, NoWarnUndeclaredVar bool 195 EvaluateDatasources bool 196 ReleaseOnly bool 197 } 198 199 func (va *InspectArgs) AddFlagSets(flags *flag.FlagSet) { 200 flags.BoolVar(&va.MetaArgs.UseSequential, "use-sequential-evaluation", false, "Fallback to using a sequential approach for local/datasource evaluation.") 201 va.MetaArgs.AddFlagSets(flags) 202 } 203 204 // InspectArgs represents a parsed cli line for a `packer inspect` 205 type InspectArgs struct { 206 MetaArgs 207 } 208 209 func (va *HCL2UpgradeArgs) AddFlagSets(flags *flag.FlagSet) { 210 flags.StringVar(&va.OutputFile, "output-file", "", "File where to put the hcl2 generated config. Defaults to JSON_TEMPLATE.pkr.hcl") 211 flags.BoolVar(&va.WithAnnotations, "with-annotations", false, "Adds helper annotations with information about the generated HCL2 blocks.") 212 213 va.MetaArgs.AddFlagSets(flags) 214 } 215 216 // HCL2UpgradeArgs represents a parsed cli line for a `packer hcl2_upgrade` 217 type HCL2UpgradeArgs struct { 218 MetaArgs 219 OutputFile string 220 WithAnnotations bool 221 } 222 223 func (va *FormatArgs) AddFlagSets(flags *flag.FlagSet) { 224 flags.BoolVar(&va.Check, "check", false, "check if the input is formatted") 225 flags.BoolVar(&va.Diff, "diff", false, "display the diff of formatting changes") 226 flags.BoolVar(&va.Write, "write", true, "overwrite source files instead of writing to stdout") 227 flags.BoolVar(&va.Recursive, "recursive", false, "Also process files in subdirectories") 228 va.MetaArgs.AddFlagSets(flags) 229 } 230 231 // FormatArgs represents a parsed cli line for `packer fmt` 232 type FormatArgs struct { 233 MetaArgs 234 Check, Diff, Write, Recursive bool 235 }