func (o *Opts) Version(version string) *Opts {
	g := reflect.ValueOf(&o.internalOpts).Elem()
	o.addOptArg(g.Type().Field(1), g.Field(1))
	o.version = version
	return o
}
Version sets the version of the program
and renders the 'version' template in the help text
package opts
import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"
)
var flagValueType = reflect.TypeOf((*flag.Value)(nil)).Elem()
type Opts struct {
	item
	parent       *Opts
	cmds         map[string]*Opts
	opts         []*item
	args         []*item
	arglist      *argumentlist
	optnames     map[string]bool
	envnames     map[string]bool
	order        []string
	templates    map[string]string
	internalOpts struct {
		Help, Version bool
	}
	cfgPath               string
	erred                 error
	cmdname               *reflect.Value
	repo, author, version string
	pkgrepo, pkgauthor    string
	LineWidth int
	PadAll bool
	PadWidth int
}
type argumentlist struct {
	item
	min int
}
type item struct {
	val       reflect.Value
	name      string
	shortName string
	envName   string
	useEnv    bool
	typeName  string
	help      string
	defstr    string
}
func New(config interface{}) *Opts {
	v := reflect.ValueOf(config)
	o := fork(nil, v)
	if o.erred != nil {
		return o
	}
	pkgpath := v.Elem().Type().PkgPath()
	parts := strings.Split(pkgpath, "/")
	if len(parts) >= 3 {
		o.pkgauthor = parts[1]
		o.Name(parts[2])
		switch parts[0] {
		case "github.com", "bitbucket.org":
			o.pkgrepo = "https://" + strings.Join(parts[0:3], "/")
		}
	}
	return o
}
func Parse(config interface{}) *Opts {
	return New(config).Parse()
}
func fork(parent *Opts, val reflect.Value) *Opts {
	var order []string = nil
	var tmpls map[string]string = nil
	if parent == nil {
		order = make([]string, len(DefaultOrder))
		copy(order, DefaultOrder)
		tmpls = map[string]string{}
	} else {
		order = parent.order
		tmpls = parent.templates
	}
	o := &Opts{
		item: item{
			val: val,
		},
		parent: parent,
		optnames: map[string]bool{},
		envnames: map[string]bool{},
		cmds:     map[string]*Opts{},
		opts:     []*item{},
		order:     order,
		templates: tmpls,
		LineWidth: 72,
		PadAll:    true,
		PadWidth:  2,
	}
	if val.Type().Kind() != reflect.Ptr {
		o.errorf("opts: %s should be a pointer to a struct", val.Type().Name())
		return o
	}
	o.addFields(val.Elem())
	g := reflect.ValueOf(&o.internalOpts).Elem()
	o.addOptArg(g.Type().Field(0), g.Field(0))
	return o
}
func (o *Opts) addFields(c reflect.Value) *Opts {
	t := c.Type()
	k := t.Kind()
	if k == reflect.Ptr {
		c = c.Elem()
		t = c.Type()
		k = t.Kind()
	}
	if k != reflect.Struct {
		o.errorf("opts: %s should be a pointer to a struct (got %s)", t.Name(), k)
		return o
	}
	for i := 0; i < c.NumField(); i++ {
		val := c.Field(i)
		if !val.CanSet() {
			continue
		}
		sf := t.Field(i)
		k := sf.Type.Kind()
		if sf.Type.Implements(flagValueType) {
			o.addOptArg(sf, val)
			continue
		}
		switch k {
		case reflect.Ptr, reflect.Struct:
			if sf.Tag.Get("type") == "embedded" {
				o.addFields(val)
			} else {
				o.addCmd(sf, val)
			}
		case reflect.Slice:
			if sf.Type.Elem().Kind() != reflect.String {
				o.errorf("arglist must be of type []string")
				return o
			}
			o.addArgs(sf, val)
		case reflect.Bool, reflect.String, reflect.Int, reflect.Int64:
			if sf.Tag.Get("type") == "cmdname" {
				if k != reflect.String {
					o.errorf("cmdname field '%s' must be a string", sf.Name)
					return o
				}
				o.cmdname = &val
			} else {
				o.addOptArg(sf, val)
			}
		case reflect.Interface:
			o.errorf("Struct field '%s' interface type must implement flag.Value", sf.Name)
			return o
		default:
			o.errorf("Struct field '%s' has unsupported type: %s", sf.Name, k)
			return o
		}
	}
	return o
}
func (o *Opts) errorf(format string, args ...interface{}) *Opts {
	if o.erred == nil {
		o.erred = fmt.Errorf(format, args...)
	}
	return o
}
func (o *Opts) addCmd(sf reflect.StructField, val reflect.Value) {
	if o.arglist != nil {
		o.errorf("argslists and commands cannot be used together")
		return
	}
	switch sf.Type.Kind() {
	case reflect.Ptr:
		if val.IsNil() {
			ptr := reflect.New(val.Type().Elem())
			val.Set(ptr)
		}
	case reflect.Struct:
		val = val.Addr()
	}
	name := sf.Tag.Get("name")
	if name == "" || name == "!" {
		name = camel2dash(sf.Name)  
	}
	sub := fork(o, val)
	sub.name = name
	sub.help = sf.Tag.Get("help")
	o.cmds[name] = sub
}
func (o *Opts) addArgs(sf reflect.StructField, val reflect.Value) {
	if len(o.cmds) > 0 {
		o.errorf("argslists and commands cannot be used together")
		return
	}
	if o.arglist != nil {
		o.errorf("only 1 arglist field is allowed ('%s' already defined)", o.arglist.name)
		return
	}
	name := sf.Tag.Get("name")
	if name == "" || name == "!" {
		name = camel2dash(sf.Name)  
	}
	if val.Len() != 0 {
		o.errorf("arglist '%s' is required so it should not be set. "+
			"If you'd like to set a default, consider using an option instead.", name)
		return
	}
	min, _ := strconv.Atoi(sf.Tag.Get("min"))
	o.arglist = &argumentlist{
		item: item{
			val:  val,
			name: name,
			help: sf.Tag.Get("help"),
		},
		min: min,
	}
}
var durationType = reflect.TypeOf(time.Second)
func (o *Opts) addOptArg(sf reflect.StructField, val reflect.Value) {
	i := &item{val: val}
	i.name = sf.Tag.Get("name")
	if i.name == "" {
		i.name = camel2dash(sf.Name)  
	}
	i.envName = sf.Tag.Get("env")
	if i.envName != "" {
		if o.envnames[i.envName] {
			o.errorf("option env name '%s' already in use", i.name)
			return
		}
		o.envnames[i.envName] = true
		i.useEnv = true
	}
	t := sf.Tag.Get("type")
	if t == "" {
		t = "opt"
	}
	if o.optnames[i.name] {
		o.errorf("option name '%s' already in use", i.name)
		return
	}
	o.optnames[i.name] = true
	i.help = sf.Tag.Get("help")
	defstr := sf.Tag.Get("default")
	if defstr != "" {
		i.defstr = defstr
	} else if def := val.Interface(); def != reflect.Zero(sf.Type).Interface() {
		i.defstr = fmt.Sprintf("%v", def)
	}
	switch t {
	case "opt":
		if short := sf.Tag.Get("short"); short != "" {
			if o.optnames[short] {
				o.errorf("option short name '%s' already in use", short)
				return
			} else {
				o.optnames[i.shortName] = true
				i.shortName = short
			}
		}
		o.opts = append(o.opts, i)
	case "arg":
		if sf.Type.Kind() != reflect.String {
			o.errorf("arg '%s' type must be a string", i.name)
			return
		}
		o.args = append(o.args, i)
	default:
		o.errorf("Invalid optype: %s", t)
	}
}
func (o *Opts) Name(name string) *Opts {
	o.name = name
	return o
}