Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Just an example for envflag (soon to be expanded at github.com/confactor/envflag)
// see http://godoc.org/github.com/arnehormann/goof/envflag
package main
import (
"fmt"
"io"
"os"
"sort"
"strings"
"text/tabwriter"
"github.com/arnehormann/goof/envflag"
)
// example for a custom envflag.Enumerator
type mode string
func Mode(m string) *mode {
// this is very, very ugly and just for demonstration purposes...
defaultMode := "prod"
result := (*mode)(&defaultMode)
result.Set(m) // ignore errors, keep default
return result
}
func (m *mode) Values() []string {
return []string{"prod", "dev", "test"}
}
func (m *mode) Set(v string) error {
switch v {
case "prod", "dev", "test":
default:
return fmt.Errorf("unknown mode %q", v)
}
*m = mode(v)
return nil
}
func (m *mode) String() string {
return *(*string)(m)
}
func (m *mode) Describe(v string) string {
switch v {
case "prod":
return "production environment"
case "dev":
return "development environment"
case "test":
return "test environment"
}
return ""
}
func main() {
var err error
// this is the whole configuration. If no optional struct tags exist,
// everything is inferred from the field name, type and initial value.
config := struct {
Host string `desc:"target smtp server name or ip"`
Port uint `desc:"smtp port (usually 25 or 587)"`
User string `desc:"user name"`
Password string `key:"pass" desc:"login password"`
SortArgs bool `arg:"sorthelp" tag:"help"`
FullHelp bool `args:"fh,v" desc:"print full help text" tag:"help"`
Mode *mode `desc:"program mode"`
}{
Host: "127.0.0.1",
Port: 587,
SortArgs: true,
Mode: Mode("test"),
}
// create a set of parameters (environment variables prefixed with MYAPP_)
env := envflag.Environment("myapp/")
params := env.WithParameters("") // api messup, I'll get rid of this
// register the struct
params.Register(&config)
// seed configuration parameters from environment variables
// could also load from a file instead of os.Getenv
err = params.SetValues(os.Getenv)
if err != nil {
panic(err)
}
// parse command line arguments, overwrite existing values with ones given there
err = params.Parse(os.Args[1:])
if err != nil {
panic(err)
}
// fetch available parameters and sort them by command line argument name
p := parameters(params.Explore())
if config.SortArgs {
sort.Sort(p)
}
w := tabwriter.NewWriter(os.Stdout, 4, 0, 2, ' ', 0)
if config.FullHelp {
printHelp(w, p)
} else {
printArgTable(w, p)
}
w.Flush()
}
type parameters []envflag.Parameter
func (ps parameters) Len() int {
return len(ps)
}
func (ps parameters) Swap(i, j int) {
ps[i], ps[j] = ps[j], ps[i]
}
func (ps parameters) Less(i, j int) bool {
return ps[i].ArgKey < ps[j].ArgKey
}
func HasTag(tag, key string) bool {
parts := strings.Split(tag, " ")
for _, p := range parts {
if p == key {
return true
}
}
return false
}
func printArgTable(w io.Writer, params parameters) {
fmt.Fprintf(w, "Key\tArg\tEnv\tValue\tDefault\tDescription\n")
for i := range params {
p := &params[i]
// show usage of tag
if HasTag(p.Tag, "help") {
fmt.Fprintf(w, "%s\t-%s\t%s\t%q\t%q\t[?] %s\n",
p.Key, p.ArgKey, p.EnvKey, p.Value, p.DefaultValue, p.Description,
)
} else {
fmt.Fprintf(w, "%s\t-%s\t%s\t%q\t%q\t%s\n",
p.Key, p.ArgKey, p.EnvKey, p.Value, p.DefaultValue, p.Description,
)
}
}
}
func printHelp(w io.Writer, params parameters) {
fmt.Fprintf(w, "List of available configuration options:\n\n")
for _, p := range params {
var defaultVal string
if p.Value != p.DefaultValue {
defaultVal = fmt.Sprintf(" (default %q)", p.DefaultValue)
}
desc := p.Description
if desc == "" {
desc = "<no description>"
}
fmt.Fprintf(
w,
"ENV: $%s\tType: %s\n"+
"ARG: -%s\n"+
"\t%s\n"+
"\tvalue: %q%s\n",
p.EnvKey, p.Type,
strings.Join(append([]string{p.ArgKey}, p.ArgAliases...), ", -"),
desc,
p.Value, defaultVal,
)
// show usage of options
for _, o := range p.Options {
fmt.Fprintf(w, "\t[%s]\t%s\n", o.Value, o.Description)
}
fmt.Fprintln(w)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment