glider/vendor/github.com/nadoo/conflag/conflag.go
2018-07-07 11:07:38 +08:00

152 lines
2.6 KiB
Go

package conflag
import (
"bufio"
"flag"
"os"
"path/filepath"
"strings"
)
// Conflag .
type Conflag struct {
*flag.FlagSet
app string
osArgs []string
cfgFile string
args []string
includes []string
// TODO: add shorthand? or just use pflag?
// shorthand map[byte]string
}
// New ...
func New(args ...string) *Conflag {
if args == nil {
args = os.Args
}
c := &Conflag{}
c.app = args[0]
c.osArgs = args[1:]
c.FlagSet = flag.NewFlagSet(c.app, flag.ExitOnError)
c.FlagSet.StringVar(&c.cfgFile, "config", "", "config file path")
return c
}
// NewFromFile ...
func NewFromFile(app, cfgFile string) *Conflag {
c := &Conflag{}
if app != "" {
c.app = app
} else {
c.app = os.Args[0]
}
c.cfgFile = cfgFile
c.FlagSet = flag.NewFlagSet(c.app, flag.ExitOnError)
c.StringSliceUniqVar(&c.includes, "include", nil, "include file")
return c
}
// Parse ...
func (c *Conflag) Parse() (err error) {
// parse 1st time and see whether there is a conf file.
err = c.FlagSet.Parse(c.osArgs)
if err != nil {
return err
}
// if there is no args, just try to load the app.conf file.
if c.cfgFile == "" && len(c.osArgs) == 0 {
// trim app exetension
for i := len(c.app) - 1; i >= 0 && c.app[i] != '/' && c.app[i] != '\\'; i-- {
if c.app[i] == '.' {
c.cfgFile = c.app[:i]
break
}
}
if c.cfgFile == "" {
c.cfgFile = c.app
}
c.cfgFile += ".conf"
}
if c.cfgFile == "" {
return nil
}
fargs, err := parseFile(c.cfgFile)
if err != nil {
return err
}
c.args = fargs
c.args = append(c.args, c.osArgs...)
// parse 2nd time to get the include file values
err = c.FlagSet.Parse(c.args)
if err != nil {
return err
}
dir := filepath.Dir(c.cfgFile)
// parse 3rd time to parse flags in include file
for _, include := range c.includes {
include = filepath.Join(dir, include)
fargs, err := parseFile(include)
if err != nil {
return err
}
c.args = fargs
c.args = append(c.args, c.osArgs...)
err = c.FlagSet.Parse(c.args)
}
return err
}
func parseFile(cfgFile string) ([]string, error) {
var s []string
fp, err := os.Open(cfgFile)
if err != nil {
return nil, err
}
defer fp.Close()
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
line := scanner.Text()
line = strings.TrimSpace(line)
if len(line) == 0 || line[:1] == "#" {
continue
}
s = append(s, "-"+line)
}
return s, nil
}
// AppDir returns the app dir
func (c *Conflag) AppDir() string {
return filepath.Dir(os.Args[0])
}
// ConfDir returns the config file dir
func (c *Conflag) ConfDir() string {
return filepath.Dir(c.cfgFile)
}