package main import ( "flag" "github.com/carlosframework/platform/internal/cliflag" ) // flags.go is the carlos CLI's face of internal/cliflag (the spec's // claimed short-flag namespace: -a app, -c channel, -d destination, // -e environment, -v version). The four helpers below are the only way the aliased // flags are registered in this package; sites with something bespoke to // say pass it through, and an empty usage takes the flag's common // wording. The table itself, the registrar, and the usage printer live // in internal/cliflag so out-of-package verbs (internal/vet) register // through the same table instead of open-coding an alias pair. // cliAliases is the claimed table, shared with every registrar caller. var cliAliases = cliflag.Aliases // aliasedString registers name and its short form against one variable // with one default — see cliflag.String for the default-value trap this // signature exists to prevent. func aliasedString(fs *flag.FlagSet, name, def, usage string) *string { return cliflag.String(fs, name, def, usage) } // flagUsage renders a flag set with aliases folded into their primary // and -- canonical; see cliflag.Usage. func flagUsage(fs *flag.FlagSet, header string) func() { return cliflag.Usage(fs, header) } // consoleOption registers --console, and with it --destination / -d: // every verb that can be pointed at a console can equally be pointed at a // named destination in .carlos/config, which is where its console comes // from. The destination lands in the package-level destinationFlag that // loadConfig reads (config.go). func consoleOption(fs *flag.FlagSet, usage string) *string { c := fs.String("console", "", usage) destinationOption(fs) return c } // destinationOption registers --destination / -d alone, for the verbs that // read or write .carlos/config without taking --console (auth default). func destinationOption(fs *flag.FlagSet) { fs.Var(destinationValue{}, "destination", "use the `name`d block from .carlos/config's destinations (default: CARLOS_DESTINATION, else the file's default or only one)") fs.Var(destinationValue{}, cliAliases["destination"], "alias for --destination") } // destinationValue writes straight to destinationFlag. A flag.Value rather // than fs.StringVar because StringVar assigns the default at registration: // a verb that builds a second flag set mid-run (deploy re-running auth // login on a moved console) would otherwise wipe the destination the // operator chose. type destinationValue struct{} func (destinationValue) String() string { return destinationFlag } func (destinationValue) Set(v string) error { destinationFlag = v; return nil } func appFlag(fs *flag.FlagSet, usage string) *string { if usage == "" { usage = "app name" } return aliasedString(fs, "app", "", usage) } func channelFlag(fs *flag.FlagSet, usage string) *string { if usage == "" { usage = "release channel" } return aliasedString(fs, "channel", "", usage) } func environmentFlag(fs *flag.FlagSet, usage string) *string { if usage == "" { usage = "named environment bundle (omit for the default bundle)" } return aliasedString(fs, "environment", "", usage) } func versionFlag(fs *flag.FlagSet, usage string) *string { if usage == "" { usage = "version (git short sha)" } return aliasedString(fs, "version", "", usage) } // flagWasSet reports whether the user typed a flag, by its primary name // OR its short alias — the wizard and the saved deploy block must never // override an explicit choice. fs.Visit reports the spelling actually // typed (measured in the spec), so matching the primary alone would go // false when -a was given: a wizard that then re-prompts for a value // the user just named. alias is "" for unaliased names, and f.Name is // never "", so the extra compare is inert there. func flagWasSet(fs *flag.FlagSet, name string) bool { alias := cliAliases[name] set := false fs.Visit(func(f *flag.Flag) { if f.Name == name || f.Name == alias { set = true } }) return set }