├── README.md └── main.go /README.md: -------------------------------------------------------------------------------- 1 | go-envdata 2 | ========== 3 | 4 | go-envdata packages environment variables into Go binaries. Inspired by [go-bindata](https://sourcegraph.com/github.com/jteeuwen/go-bindata). 5 | 6 | Tries to be shell/OS-agnostic, but currently tested with bash and *nix systems. 7 | 8 | Usage 9 | ----- 10 | 11 | ### Step 1: generate code 12 | 13 | Capture ambient environment: 14 | ``` 15 | go-envdata -pkg env -o env/env.go 16 | ``` 17 | 18 | Capture environment defined by config file: 19 | ``` 20 | env -i PATH=$PATH bash -c 'source my-config.sh; go-envdata; 21 | ``` 22 | or 23 | ``` 24 | env -i PATH=$PATH bash -c "./setup-environment.sh; go-envdata" 25 | ``` 26 | where `my-config.sh` and `setup-environment.sh` are files you define to setup the environment variables. 27 | 28 | ### Step 2: import generated code 29 | 30 | Include the following import in files that reference the environment. 31 | ``` 32 | import _ "path/to/package/of/generated/file" 33 | ``` 34 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "os" 9 | "sort" 10 | "strings" 11 | ) 12 | 13 | type Config struct { 14 | // Name of the package to use in generated code. Defaults to 'env'. 15 | Package string 16 | 17 | // Output defines the output file for the generated code. 18 | // If left empty, prints to stdout. 19 | Output string 20 | 21 | // Space separated list of environment variables NOT to capture. 22 | Ignore string 23 | 24 | // Generate a file that doesn't set any default environment variables. 25 | Dev bool 26 | } 27 | 28 | var alwaysIgnore = []string{"PWD", "SHLVL", "_", "PATH"} 29 | 30 | func NewDefaultConfig() *Config { 31 | return &Config{ 32 | Package: "env", 33 | } 34 | } 35 | 36 | func parseArgs() *Config { 37 | c := NewDefaultConfig() 38 | flag.StringVar(&c.Package, "pkg", c.Package, "Package name to use in generated code.") 39 | flag.StringVar(&c.Output, "o", c.Output, "Optional name of the output file to be generated.") 40 | flag.StringVar(&c.Ignore, "ignore", c.Ignore, "Space separated list of environment variables to ignore.") 41 | flag.BoolVar(&c.Dev, "dev", c.Dev, "Do not capture the environment, but instead generate a file that just reads from the runtime environment.") 42 | flag.Parse() 43 | 44 | return c 45 | } 46 | 47 | func writeDev(w io.Writer, c *Config) error { 48 | return writeRelease(w, c, nil) 49 | } 50 | 51 | func writeRelease(w io.Writer, c *Config, env map[string]string) error { 52 | var defaultsMapExpr string 53 | if len(env) == 0 { 54 | defaultsMapExpr = "" 55 | } else { 56 | var kvExprs []string 57 | for k, v := range env { 58 | kvExprs = append(kvExprs, fmt.Sprintf("\t%q: %q,", k, v)) 59 | } 60 | sort.Strings(kvExprs) // sort for stable ordering 61 | defaultsMapExpr = "\n" + strings.Join(kvExprs, "\n") + "\n" 62 | } 63 | 64 | _, err := fmt.Fprintf(w, `// Package %s sets default values for environment variables. 65 | // Usage: in any package that calls os.Getenv or references the environment, include: 66 | // 67 | // import _ "full/path/to/%s" 68 | // 69 | package %s 70 | 71 | import "os" 72 | 73 | var defaults = map[string]string{%s} 74 | 75 | func init() { 76 | setDefaultEnv() 77 | } 78 | 79 | func setDefaultEnv() { 80 | for k, v := range defaults { 81 | if os.Getenv(k) == "" { 82 | os.Setenv(k, v) 83 | } 84 | } 85 | } 86 | `, c.Package, c.Package, c.Package, defaultsMapExpr) 87 | if err != nil { 88 | return err 89 | } 90 | return nil 91 | } 92 | 93 | // Transcribe reads environment variables and emits a Go source file with their default values. 94 | func Transcribe(c *Config) error { 95 | // Get environment to capture 96 | ignore_ := strings.Fields(c.Ignore) 97 | ignore := make(map[string]bool) 98 | for _, ig := range ignore_ { 99 | ignore[ig] = true 100 | } 101 | for _, ig := range alwaysIgnore { 102 | ignore[ig] = true 103 | } 104 | env := make(map[string]string) 105 | for _, keyval := range os.Environ() { 106 | key := strings.SplitN(keyval, "=", 2)[0] 107 | val := os.Getenv(key) 108 | if !ignore[key] { 109 | env[key] = val 110 | } 111 | } 112 | 113 | // Write file 114 | var out io.Writer 115 | if c.Output == "" { 116 | out = os.Stdout 117 | } else { 118 | fd, err := os.Create(c.Output) 119 | if err != nil { 120 | return nil 121 | } 122 | defer fd.Close() 123 | bfd := bufio.NewWriter(fd) 124 | defer bfd.Flush() 125 | out = bfd 126 | } 127 | 128 | if c.Dev { 129 | writeDev(out, c) 130 | } else { 131 | writeRelease(out, c, env) 132 | } 133 | return nil 134 | } 135 | 136 | func main() { 137 | c := parseArgs() 138 | if err := Transcribe(c); err != nil { 139 | fmt.Fprintf(os.Stderr, "go-envdata: %v\n", err) 140 | os.Exit(1) 141 | } 142 | } 143 | --------------------------------------------------------------------------------