186 lines
4.3 KiB
Go
186 lines
4.3 KiB
Go
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package flag
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"os"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// EnvironmentPrefix defines a string that will be implicitely prefixed to a
|
||
|
// flag name before looking it up in the environment variables.
|
||
|
var EnvironmentPrefix = ""
|
||
|
|
||
|
// ParseEnv parses flags from environment variables.
|
||
|
// Flags already set will be ignored.
|
||
|
func (f *FlagSet) ParseEnv(environ []string) error {
|
||
|
|
||
|
m := f.formal
|
||
|
|
||
|
env := make(map[string]string)
|
||
|
for _, s := range environ {
|
||
|
i := strings.Index(s, "=")
|
||
|
if i < 1 {
|
||
|
continue
|
||
|
}
|
||
|
env[s[0:i]] = s[i+1 : len(s)]
|
||
|
}
|
||
|
|
||
|
for _, flag := range m {
|
||
|
name := flag.Name
|
||
|
_, set := f.actual[name]
|
||
|
if set {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
flag, alreadythere := m[name]
|
||
|
if !alreadythere {
|
||
|
if name == "help" || name == "h" { // special case for nice help message.
|
||
|
f.usage()
|
||
|
return ErrHelp
|
||
|
}
|
||
|
return f.failf("environment variable provided but not defined: %s", name)
|
||
|
}
|
||
|
|
||
|
envKey := strings.ToUpper(flag.Name)
|
||
|
if f.envPrefix != "" {
|
||
|
envKey = f.envPrefix + "_" + envKey
|
||
|
}
|
||
|
envKey = strings.Replace(envKey, "-", "_", -1)
|
||
|
|
||
|
value, isSet := env[envKey]
|
||
|
if !isSet {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
hasValue := false
|
||
|
if len(value) > 0 {
|
||
|
hasValue = true
|
||
|
}
|
||
|
|
||
|
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
|
||
|
if hasValue {
|
||
|
if err := fv.Set(value); err != nil {
|
||
|
return f.failf("invalid boolean value %q for environment variable %s: %v", value, name, err)
|
||
|
}
|
||
|
} else {
|
||
|
// flag without value is regarded a bool
|
||
|
fv.Set("true")
|
||
|
}
|
||
|
} else {
|
||
|
if err := flag.Value.Set(value); err != nil {
|
||
|
return f.failf("invalid value %q for environment variable %s: %v", value, name, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update f.actual
|
||
|
if f.actual == nil {
|
||
|
f.actual = make(map[string]*Flag)
|
||
|
}
|
||
|
f.actual[name] = flag
|
||
|
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// NewFlagSetWithEnvPrefix returns a new empty flag set with the specified name,
|
||
|
// environment variable prefix, and error handling property.
|
||
|
func NewFlagSetWithEnvPrefix(name string, prefix string, errorHandling ErrorHandling) *FlagSet {
|
||
|
f := NewFlagSet(name, errorHandling)
|
||
|
f.envPrefix = prefix
|
||
|
return f
|
||
|
}
|
||
|
|
||
|
// DefaultConfigFlagname defines the flag name of the optional config file
|
||
|
// path. Used to lookup and parse the config file when a default is set and
|
||
|
// available on disk.
|
||
|
var DefaultConfigFlagname = "config"
|
||
|
|
||
|
// ParseFile parses flags from the file in path.
|
||
|
// Same format as commandline argumens, newlines and lines beginning with a
|
||
|
// "#" charater are ignored. Flags already set will be ignored.
|
||
|
func (f *FlagSet) ParseFile(path string) error {
|
||
|
|
||
|
// Extract arguments from file
|
||
|
fp, err := os.Open(path)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer fp.Close()
|
||
|
|
||
|
scanner := bufio.NewScanner(fp)
|
||
|
for scanner.Scan() {
|
||
|
line := scanner.Text()
|
||
|
|
||
|
// Ignore empty lines
|
||
|
if len(line) == 0 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Ignore comments
|
||
|
if line[:1] == "#" {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Match `key=value` and `key value`
|
||
|
var name, value string
|
||
|
hasValue := false
|
||
|
for i, v := range line {
|
||
|
if v == '=' || v == ' ' {
|
||
|
hasValue = true
|
||
|
name, value = line[:i], line[i+1:]
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if hasValue == false {
|
||
|
name = line
|
||
|
}
|
||
|
|
||
|
// Ignore flag when already set; arguments have precedence over file
|
||
|
if f.actual[name] != nil {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
m := f.formal
|
||
|
flag, alreadythere := m[name]
|
||
|
if !alreadythere {
|
||
|
if name == "help" || name == "h" { // special case for nice help message.
|
||
|
f.usage()
|
||
|
return ErrHelp
|
||
|
}
|
||
|
return f.failf("configuration variable provided but not defined: %s", name)
|
||
|
}
|
||
|
|
||
|
if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
|
||
|
if hasValue {
|
||
|
if err := fv.Set(value); err != nil {
|
||
|
return f.failf("invalid boolean value %q for configuration variable %s: %v", value, name, err)
|
||
|
}
|
||
|
} else {
|
||
|
// flag without value is regarded a bool
|
||
|
fv.Set("true")
|
||
|
}
|
||
|
} else {
|
||
|
if err := flag.Value.Set(value); err != nil {
|
||
|
return f.failf("invalid value %q for configuration variable %s: %v", value, name, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update f.actual
|
||
|
if f.actual == nil {
|
||
|
f.actual = make(map[string]*Flag)
|
||
|
}
|
||
|
f.actual[name] = flag
|
||
|
}
|
||
|
|
||
|
if err := scanner.Err(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|