pax_global_header00006660000000000000000000000064145457317430014527gustar00rootroot0000000000000052 comment=7b14d21b47bcd34955a2410a6a405621575a2050 golang-github-jamiealquiza-envy-1.1.0/000077500000000000000000000000001454573174300177065ustar00rootroot00000000000000golang-github-jamiealquiza-envy-1.1.0/LICENSE000066400000000000000000000020671454573174300207200ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2017 Jamie Alquiza Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.golang-github-jamiealquiza-envy-1.1.0/README.md000066400000000000000000000115541454573174300211730ustar00rootroot00000000000000[![GoDoc](https://godoc.org/github.com/jamiealquiza/envy?status.svg)](https://godoc.org/github.com/jamiealquiza/envy) # envy Automatically exposes environment variables for all of your flags. It supports the standard flags package along with limited support for [Cobra](https://github.com/spf13/cobra) commands. Envy takes a namespace prefix that will be used for environment variable lookups. Each flag registered in your app will be prefixed, uppercased, and hyphens exchanged for underscores; if a matching environment variable is found, it will set the respective flag value as long as the value is not otherwise explicitly set (see usage for precedence). ### Example: flag Code: ```go package main import ( "flag" "fmt" "github.com/jamiealquiza/envy" ) func main() { var address = flag.String("address", "127.0.0.1", "Some random address") var port = flag.String("port", "8131", "Some random port") envy.Parse("MYAPP") // Expose environment variables. flag.Parse() fmt.Println(*address) fmt.Println(*port) } ``` Output: ```sh # Prints flag defaults % ./example 127.0.0.1 8131 # Setting flags via env vars. % MYAPP_ADDRESS="0.0.0.0" MYAPP_PORT="9080" ./example 0.0.0.0 9080 ``` ### Example: Cobra Code: ```go // Where to execute envy depends on the structure // of your Cobra implementation. A common pattern // is to define a root command and an 'Execute' function // that's called from the application main. We can call // envy ParseCobra here and configure it to recursively // update all child commands. Alternatively, it can be // scoped to child commands at some point in their // initialization. var rootCmd = &cobra.Command{ Use: "myapp", } func Execute() { // Configure envy. cfg := CobraConfig{ // The env var prefix. Prefix: "MYAPP", // Whether to parse persistent flags. Persistent: true, // Whether to recursively update child command FlagSets. Recursive: true, } // Apply. envy.ParseCobra(rootCmd, cfg) if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } } ``` Output: ```sh # Root command flags. % myapp Usage: myapp [command] Available Commands: help Help about any command doathing This is a subcommand Flags: -h, --help help for myapp --some-config A global config [MYAPP_SOME_CONFIG] Use "myapp [command] --help" for more information about a command. # Child command flags. Notice that the prefix # has the subcommand name automatically appended # while preserving global/parent env vars. % myapp doathing Usage: myapp doathing [flags] Flags: -h, --help help for myapp --subcmd-config Another config [MYAPP_DOATHING_SUBCMD_CONFIG] Global Flags: --some-flag A global flag [MYAPP_SOME_FLAG] ``` ### Usage **Variable precedence:** Envy results in the following order of precedence, each item overwriting the previous: `flag default` -> `Envy generated env var` -> `flag set at the CLI`. Results referencing the stdlib flag example code: - `./example` will result in `port` being set to `8131` - `MYAPP_PORT=5678 ./example` will result in `port` being set to `5678` - `MYAPP_PORT=5678 ./example -port=1234` will result in `port` being set to `1234` **Env vars in help output:** Envy can update your app help output so that it includes the environment variable generated/referenced for each flag. This is done by calling `envy.Parse()` before `flag.Parse()`. The above example: ``` Usage of ./example: -address string Some random address [MYAPP_ADDRESS] (default "127.0.0.1") -port string Some random port [MYAPP_PORT] (default "8131") ``` If this isn't desired, simply call `envy.Parse()` after `flag.Parse()`: ```go // ... flag.Parse() envy.Parse("MYAPP") // looks for MYAPP_ADDRESS & MYAPP_PORT // ... ``` ``` Usage of ./example: -address string Some random address (default "127.0.0.1") -port string Some random port (default "8131") ``` **Satisfying types:** Environment variables should be defined using a type that satisfies the respective type in your Go application's flag. For example: - `string` -> `APP_ASTRINGVAR="someString"` - `int` -> `APP_ANINTVAR=42` - `bool` -> `APP_ABOOLVAR=true` **Side effects:** Setting a flag through an Envy generated environment variable will have the same effects on the default `flag.CommandLine` as if the flag were set via the command line. This only affect users that may rely on `flag.CommandLine` methods that make distinctions between set and to-be set flags (such as the `Visit` method). **Cobra compatibility:** The extensive types in Cobra's underlying [pflag](https://github.com/spf13/pflag) have not been tested, hence the "limited support" reference. Also, keep in mind that Cobra can change in a way that breaks support with envy. Functionality was tested as of 2018-11-19. golang-github-jamiealquiza-envy-1.1.0/cobra.go000066400000000000000000000043761454573174300213350ustar00rootroot00000000000000package envy import ( "fmt" "os" "strings" "github.com/spf13/cobra" "github.com/spf13/pflag" ) // CobraConfig holds configurations for calls // to ParseCobra. type CobraConfig struct { // The environment variable prefix. Prefix string // Expose flags for child commands. Recursive bool // Whether to expose flags for persistent FlagSets. Persistent bool } // ParseCobra takes a *cobra.Command and exposes environment variables // for all local flags in the command FlagSet in the form of PREFIX_FLAGNAME // where PREFIX is set to that of CobraConfig.Prefix. Environment variables are // exposed for persistent flags if the CobraConfig.Persistent is set to true. // If CobraConfig.Recursive is set to true, all child command FlagSets will // have environment variables exposed in the form of PREFIX_SUBCOMMMAND_FLAGNAME. func ParseCobra(c *cobra.Command, cfg CobraConfig) { // Check if this is the root command. switch c.Root() == c { case false: // If not, append subcommand names to the prefix. cfg.Prefix = fmt.Sprintf("%s_%s", cfg.Prefix, strings.ToUpper(c.Name())) case true && cfg.Persistent: // If this is the root command, update the // persistent FlagSet, if configured. updateCobra(cfg.Prefix, c.PersistentFlags()) } // Update the current command local FlagSet. updateCobra(cfg.Prefix, c.Flags()) // Recursively update child commands. if cfg.Recursive { for _, child := range c.Commands() { if child.Name() == "help" { continue } ParseCobra(child, cfg) } } } func updateCobra(p string, fs *pflag.FlagSet) { // Build a map of explicitly set flags. set := map[string]interface{}{} fs.Visit(func(f *pflag.Flag) { set[f.Name] = nil }) fs.VisitAll(func(f *pflag.Flag) { if f.Name == "help" { return } // Create an env var name // based on the supplied prefix. envVar := fmt.Sprintf("%s_%s", p, strings.ToUpper(f.Name)) envVar = strings.Replace(envVar, "-", "_", -1) // Update the Flag.Value if the // env var is non "". if val := os.Getenv(envVar); val != "" { // Update the value if it hasn't // already been set. if _, defined := set[f.Name]; !defined { fs.Set(f.Name, val) } } // Append the env var to the // Flag.Usage field. f.Usage = fmt.Sprintf("%s [%s]", f.Usage, envVar) }) } golang-github-jamiealquiza-envy-1.1.0/envy.go000066400000000000000000000024711454573174300212220ustar00rootroot00000000000000// Package envy automatically exposes environment // variables for all of your flags. package envy import ( "flag" "fmt" "os" "strings" ) // Parse takes a prefix string and exposes environment variables // for all flags in the default FlagSet (flag.CommandLine) in the // form of PREFIX_FLAGNAME. func Parse(p string) { update(p, flag.CommandLine) } // update takes a prefix string p and *flag.FlagSet. Each flag // in the FlagSet is exposed as an upper case environment variable // prefixed with p. Any flag that was not explicitly set by a user // is updated to the environment variable, if set. func update(p string, fs *flag.FlagSet) { // Build a map of explicitly set flags. set := map[string]interface{}{} fs.Visit(func(f *flag.Flag) { set[f.Name] = nil }) fs.VisitAll(func(f *flag.Flag) { // Create an env var name // based on the supplied prefix. envVar := fmt.Sprintf("%s_%s", p, strings.ToUpper(f.Name)) envVar = strings.Replace(envVar, "-", "_", -1) // Update the Flag.Value if the // env var is non "". if val := os.Getenv(envVar); val != "" { // Update the value if it hasn't // already been set. if _, defined := set[f.Name]; !defined { fs.Set(f.Name, val) } } // Append the env var to the // Flag.Usage field. f.Usage = fmt.Sprintf("%s [%s]", f.Usage, envVar) }) }