1
0

Updated libraries

This commit is contained in:
konrad
2019-05-07 21:42:24 +02:00
parent 2b160b73c3
commit 3d7fd9ca20
313 changed files with 37947 additions and 6783 deletions

View File

@ -267,7 +267,7 @@ func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
return u.layer.MkdirAll(name, perm)
}
if dir {
return syscall.EEXIST
return ErrFileExists
}
return u.layer.MkdirAll(name, perm)
}
@ -282,7 +282,8 @@ func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error {
return u.layer.MkdirAll(name, perm)
}
if dir {
return syscall.EEXIST
// This is in line with how os.MkdirAll behaves.
return nil
}
return u.layer.MkdirAll(name, perm)
}

View File

@ -1 +1,3 @@
module github.com/spf13/afero
require golang.org/x/text v0.3.0

2
vendor/github.com/spf13/afero/go.sum generated vendored Normal file
View File

@ -0,0 +1,2 @@
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -155,7 +155,8 @@ var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, err
}
// Readdir will weave the two directories together and
// return a single view of the overlayed directories
// return a single view of the overlayed directories.
// At the end of the directory view, the error is io.EOF if c > 0.
func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) {
var merge DirsMerger = f.Merger
if merge == nil {
@ -185,9 +186,23 @@ func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) {
}
f.files = append(f.files, merged...)
}
if c == -1 {
if c <= 0 && len(f.files) == 0 {
return f.files, nil
}
if f.off >= len(f.files) {
return nil, io.EOF
}
if c <= 0 {
return f.files[f.off:], nil
}
if c > len(f.files) {
c = len(f.files)
}
defer func() { f.off += c }()
return f.files[f.off:c], nil
}

View File

@ -1,8 +1,9 @@
language: go
env:
- GO111MODULE=on
sudo: required
go:
- 1.7.5
- 1.8
- "1.11.x"
- tip
os:
- linux

12
vendor/github.com/spf13/cast/cast.go generated vendored
View File

@ -122,6 +122,18 @@ func ToStringMapBool(i interface{}) map[string]bool {
return v
}
// ToStringMapInt casts an interface to a map[string]int type.
func ToStringMapInt(i interface{}) map[string]int {
v, _ := ToStringMapIntE(i)
return v
}
// ToStringMapInt64 casts an interface to a map[string]int64 type.
func ToStringMapInt64(i interface{}) map[string]int64 {
v, _ := ToStringMapInt64E(i)
return v
}
// ToStringMap casts an interface to a map[string]interface{} type.
func ToStringMap(i interface{}) map[string]interface{} {
v, _ := ToStringMapE(i)

View File

@ -990,6 +990,87 @@ func ToStringMapE(i interface{}) (map[string]interface{}, error) {
}
}
// ToStringMapIntE casts an interface to a map[string]int{} type.
func ToStringMapIntE(i interface{}) (map[string]int, error) {
var m = map[string]int{}
if i == nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
}
switch v := i.(type) {
case map[interface{}]interface{}:
for k, val := range v {
m[ToString(k)] = ToInt(val)
}
return m, nil
case map[string]interface{}:
for k, val := range v {
m[k] = ToInt(val)
}
return m, nil
case map[string]int:
return v, nil
case string:
err := jsonStringToObject(v, &m)
return m, err
}
if reflect.TypeOf(i).Kind() != reflect.Map {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
}
mVal := reflect.ValueOf(m)
v := reflect.ValueOf(i)
for _, keyVal := range v.MapKeys() {
val, err := ToIntE(v.MapIndex(keyVal).Interface())
if err != nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
}
mVal.SetMapIndex(keyVal, reflect.ValueOf(val))
}
return m, nil
}
// ToStringMapInt64E casts an interface to a map[string]int64{} type.
func ToStringMapInt64E(i interface{}) (map[string]int64, error) {
var m = map[string]int64{}
if i == nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
}
switch v := i.(type) {
case map[interface{}]interface{}:
for k, val := range v {
m[ToString(k)] = ToInt64(val)
}
return m, nil
case map[string]interface{}:
for k, val := range v {
m[k] = ToInt64(val)
}
return m, nil
case map[string]int64:
return v, nil
case string:
err := jsonStringToObject(v, &m)
return m, err
}
if reflect.TypeOf(i).Kind() != reflect.Map {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
}
mVal := reflect.ValueOf(m)
v := reflect.ValueOf(i)
for _, keyVal := range v.MapKeys() {
val, err := ToInt64E(v.MapIndex(keyVal).Interface())
if err != nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
}
mVal.SetMapIndex(keyVal, reflect.ValueOf(val))
}
return m, nil
}
// ToSliceE casts an interface to a []interface{} type.
func ToSliceE(i interface{}) ([]interface{}, error) {
var s []interface{}
@ -1137,9 +1218,11 @@ func StringToDate(s string) (time.Time, error) {
"2006-01-02 15:04:05.999999999 -0700 MST", // Time.String()
"2006-01-02",
"02 Jan 2006",
"2006-01-02T15:04:05-0700", // RFC3339 without timezone hh:mm colon
"2006-01-02 15:04:05 -07:00",
"2006-01-02 15:04:05 -0700",
"2006-01-02 15:04:05Z07:00", // RFC3339 without T
"2006-01-02 15:04:05Z0700", // RFC3339 without T or timezone hh:mm colon
"2006-01-02 15:04:05",
time.Kitchen,
time.Stamp,

7
vendor/github.com/spf13/cast/go.mod generated vendored Normal file
View File

@ -0,0 +1,7 @@
module github.com/spf13/cast
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)

6
vendor/github.com/spf13/cast/go.sum generated vendored Normal file
View File

@ -0,0 +1,6 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=

View File

@ -20,3 +20,5 @@ _cgo_export.*
_testmain.go
*.exe
*.bench
go.sum

View File

@ -64,6 +64,13 @@ func SetStdoutThreshold(threshold Threshold) {
reloadDefaultNotepad()
}
// SetStdoutOutput set the stdout output for the default notepad. Default is stdout.
func SetStdoutOutput(handle io.Writer) {
defaultNotepad.outHandle = handle
defaultNotepad.init()
reloadDefaultNotepad()
}
// SetPrefix set the prefix for the default logger. Empty by default.
func SetPrefix(prefix string) {
defaultNotepad.SetPrefix(prefix)
@ -76,6 +83,13 @@ func SetFlags(flags int) {
reloadDefaultNotepad()
}
// SetLogListeners configures the default logger with one or more log listeners.
func SetLogListeners(l ...LogListener) {
defaultNotepad.logListeners = l
defaultNotepad.init()
reloadDefaultNotepad()
}
// Level returns the current global log threshold.
func LogThreshold() Threshold {
return defaultNotepad.logThreshold
@ -95,19 +109,3 @@ func GetLogThreshold() Threshold {
func GetStdoutThreshold() Threshold {
return defaultNotepad.GetStdoutThreshold()
}
// LogCountForLevel returns the number of log invocations for a given threshold.
func LogCountForLevel(l Threshold) uint64 {
return defaultNotepad.LogCountForLevel(l)
}
// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
// greater than or equal to a given threshold.
func LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 {
return defaultNotepad.LogCountForLevelsGreaterThanorEqualTo(threshold)
}
// ResetLogCounters resets the invocation counters for all levels.
func ResetLogCounters() {
defaultNotepad.ResetLogCounters()
}

View File

@ -1 +1,7 @@
module github.com/spf13/jwalterweatherman
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)

View File

@ -6,50 +6,41 @@
package jwalterweatherman
import (
"io"
"sync/atomic"
)
type logCounter struct {
counter uint64
// Counter is an io.Writer that increments a counter on Write.
type Counter struct {
count uint64
}
func (c *logCounter) incr() {
atomic.AddUint64(&c.counter, 1)
func (c *Counter) incr() {
atomic.AddUint64(&c.count, 1)
}
func (c *logCounter) resetCounter() {
atomic.StoreUint64(&c.counter, 0)
// Reset resets the counter.
func (c *Counter) Reset() {
atomic.StoreUint64(&c.count, 0)
}
func (c *logCounter) getCount() uint64 {
return atomic.LoadUint64(&c.counter)
// Count returns the current count.
func (c *Counter) Count() uint64 {
return atomic.LoadUint64(&c.count)
}
func (c *logCounter) Write(p []byte) (n int, err error) {
func (c *Counter) Write(p []byte) (n int, err error) {
c.incr()
return len(p), nil
}
// LogCountForLevel returns the number of log invocations for a given threshold.
func (n *Notepad) LogCountForLevel(l Threshold) uint64 {
return n.logCounters[l].getCount()
}
// LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations
// greater than or equal to a given threshold.
func (n *Notepad) LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 {
var cnt uint64
for i := int(threshold); i < len(n.logCounters); i++ {
cnt += n.LogCountForLevel(Threshold(i))
}
return cnt
}
// ResetLogCounters resets the invocation counters for all levels.
func (n *Notepad) ResetLogCounters() {
for _, np := range n.logCounters {
np.resetCounter()
// LogCounter creates a LogListener that counts log statements >= the given threshold.
func LogCounter(counter *Counter, t1 Threshold) LogListener {
return func(t2 Threshold) io.Writer {
if t2 < t1 {
// Not interested in this threshold.
return nil
}
return counter
}
}

View File

@ -8,6 +8,7 @@ package jwalterweatherman
import (
"fmt"
"io"
"io/ioutil"
"log"
)
@ -58,13 +59,28 @@ type Notepad struct {
prefix string
flags int
// One per Threshold
logCounters [7]*logCounter
logListeners []LogListener
}
// NewNotepad create a new notepad.
func NewNotepad(outThreshold Threshold, logThreshold Threshold, outHandle, logHandle io.Writer, prefix string, flags int) *Notepad {
n := &Notepad{}
// A LogListener can ble supplied to a Notepad to listen on log writes for a given
// threshold. This can be used to capture log events in unit tests and similar.
// Note that this function will be invoked once for each log threshold. If
// the given threshold is not of interest to you, return nil.
// Note that these listeners will receive log events for a given threshold, even
// if the current configuration says not to log it. That way you can count ERRORs even
// if you don't print them to the console.
type LogListener func(t Threshold) io.Writer
// NewNotepad creates a new Notepad.
func NewNotepad(
outThreshold Threshold,
logThreshold Threshold,
outHandle, logHandle io.Writer,
prefix string, flags int,
logListeners ...LogListener,
) *Notepad {
n := &Notepad{logListeners: logListeners}
n.loggers = [7]**log.Logger{&n.TRACE, &n.DEBUG, &n.INFO, &n.WARN, &n.ERROR, &n.CRITICAL, &n.FATAL}
n.outHandle = outHandle
@ -95,28 +111,43 @@ func (n *Notepad) init() {
for t, logger := range n.loggers {
threshold := Threshold(t)
counter := &logCounter{}
n.logCounters[t] = counter
prefix := n.prefix + threshold.String() + " "
switch {
case threshold >= n.logThreshold && threshold >= n.stdoutThreshold:
*logger = log.New(io.MultiWriter(counter, logAndOut), prefix, n.flags)
*logger = log.New(n.createLogWriters(threshold, logAndOut), prefix, n.flags)
case threshold >= n.logThreshold:
*logger = log.New(io.MultiWriter(counter, n.logHandle), prefix, n.flags)
*logger = log.New(n.createLogWriters(threshold, n.logHandle), prefix, n.flags)
case threshold >= n.stdoutThreshold:
*logger = log.New(io.MultiWriter(counter, n.outHandle), prefix, n.flags)
*logger = log.New(n.createLogWriters(threshold, n.outHandle), prefix, n.flags)
default:
// counter doesn't care about prefix and flags, so don't use them
// for performance.
*logger = log.New(counter, "", 0)
*logger = log.New(n.createLogWriters(threshold, ioutil.Discard), prefix, n.flags)
}
}
}
func (n *Notepad) createLogWriters(t Threshold, handle io.Writer) io.Writer {
if len(n.logListeners) == 0 {
return handle
}
writers := []io.Writer{handle}
for _, l := range n.logListeners {
w := l(t)
if w != nil {
writers = append(writers, w)
}
}
if len(writers) == 1 {
return handle
}
return io.MultiWriter(writers...)
}
// SetLogThreshold changes the threshold above which messages are written to the
// log file.
func (n *Notepad) SetLogThreshold(threshold Threshold) {

View File

@ -925,13 +925,16 @@ func stripUnknownFlagValue(args []string) []string {
}
first := args[0]
if first[0] == '-' {
if len(first) > 0 && first[0] == '-' {
//--unknown --next-flag ...
return args
}
//--unknown arg ... (args will be arg ...)
return args[1:]
if len(args) > 1 {
return args[1:]
}
return nil
}
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {

149
vendor/github.com/spf13/pflag/string_to_int.go generated vendored Normal file
View File

@ -0,0 +1,149 @@
package pflag
import (
"bytes"
"fmt"
"strconv"
"strings"
)
// -- stringToInt Value
type stringToIntValue struct {
value *map[string]int
changed bool
}
func newStringToIntValue(val map[string]int, p *map[string]int) *stringToIntValue {
ssv := new(stringToIntValue)
ssv.value = p
*ssv.value = val
return ssv
}
// Format: a=1,b=2
func (s *stringToIntValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make(map[string]int, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return fmt.Errorf("%s must be formatted as key=value", pair)
}
var err error
out[kv[0]], err = strconv.Atoi(kv[1])
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
for k, v := range out {
(*s.value)[k] = v
}
}
s.changed = true
return nil
}
func (s *stringToIntValue) Type() string {
return "stringToInt"
}
func (s *stringToIntValue) String() string {
var buf bytes.Buffer
i := 0
for k, v := range *s.value {
if i > 0 {
buf.WriteRune(',')
}
buf.WriteString(k)
buf.WriteRune('=')
buf.WriteString(strconv.Itoa(v))
i++
}
return "[" + buf.String() + "]"
}
func stringToIntConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// An empty string would cause an empty map
if len(val) == 0 {
return map[string]int{}, nil
}
ss := strings.Split(val, ",")
out := make(map[string]int, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return nil, fmt.Errorf("%s must be formatted as key=value", pair)
}
var err error
out[kv[0]], err = strconv.Atoi(kv[1])
if err != nil {
return nil, err
}
}
return out, nil
}
// GetStringToInt return the map[string]int value of a flag with the given name
func (f *FlagSet) GetStringToInt(name string) (map[string]int, error) {
val, err := f.getFlagType(name, "stringToInt", stringToIntConv)
if err != nil {
return map[string]int{}, err
}
return val.(map[string]int), nil
}
// StringToIntVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]int variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) {
f.VarP(newStringToIntValue(value, p), name, "", usage)
}
// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) {
f.VarP(newStringToIntValue(value, p), name, shorthand, usage)
}
// StringToIntVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]int variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToIntVar(p *map[string]int, name string, value map[string]int, usage string) {
CommandLine.VarP(newStringToIntValue(value, p), name, "", usage)
}
// StringToIntVarP is like StringToIntVar, but accepts a shorthand letter that can be used after a single dash.
func StringToIntVarP(p *map[string]int, name, shorthand string, value map[string]int, usage string) {
CommandLine.VarP(newStringToIntValue(value, p), name, shorthand, usage)
}
// StringToInt defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]int variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToInt(name string, value map[string]int, usage string) *map[string]int {
p := map[string]int{}
f.StringToIntVarP(&p, name, "", value, usage)
return &p
}
// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int {
p := map[string]int{}
f.StringToIntVarP(&p, name, shorthand, value, usage)
return &p
}
// StringToInt defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]int variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToInt(name string, value map[string]int, usage string) *map[string]int {
return CommandLine.StringToIntP(name, "", value, usage)
}
// StringToIntP is like StringToInt, but accepts a shorthand letter that can be used after a single dash.
func StringToIntP(name, shorthand string, value map[string]int, usage string) *map[string]int {
return CommandLine.StringToIntP(name, shorthand, value, usage)
}

160
vendor/github.com/spf13/pflag/string_to_string.go generated vendored Normal file
View File

@ -0,0 +1,160 @@
package pflag
import (
"bytes"
"encoding/csv"
"fmt"
"strings"
)
// -- stringToString Value
type stringToStringValue struct {
value *map[string]string
changed bool
}
func newStringToStringValue(val map[string]string, p *map[string]string) *stringToStringValue {
ssv := new(stringToStringValue)
ssv.value = p
*ssv.value = val
return ssv
}
// Format: a=1,b=2
func (s *stringToStringValue) Set(val string) error {
var ss []string
n := strings.Count(val, "=")
switch n {
case 0:
return fmt.Errorf("%s must be formatted as key=value", val)
case 1:
ss = append(ss, strings.Trim(val, `"`))
default:
r := csv.NewReader(strings.NewReader(val))
var err error
ss, err = r.Read()
if err != nil {
return err
}
}
out := make(map[string]string, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return fmt.Errorf("%s must be formatted as key=value", pair)
}
out[kv[0]] = kv[1]
}
if !s.changed {
*s.value = out
} else {
for k, v := range out {
(*s.value)[k] = v
}
}
s.changed = true
return nil
}
func (s *stringToStringValue) Type() string {
return "stringToString"
}
func (s *stringToStringValue) String() string {
records := make([]string, 0, len(*s.value)>>1)
for k, v := range *s.value {
records = append(records, k+"="+v)
}
var buf bytes.Buffer
w := csv.NewWriter(&buf)
if err := w.Write(records); err != nil {
panic(err)
}
w.Flush()
return "[" + strings.TrimSpace(buf.String()) + "]"
}
func stringToStringConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// An empty string would cause an empty map
if len(val) == 0 {
return map[string]string{}, nil
}
r := csv.NewReader(strings.NewReader(val))
ss, err := r.Read()
if err != nil {
return nil, err
}
out := make(map[string]string, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
return nil, fmt.Errorf("%s must be formatted as key=value", pair)
}
out[kv[0]] = kv[1]
}
return out, nil
}
// GetStringToString return the map[string]string value of a flag with the given name
func (f *FlagSet) GetStringToString(name string) (map[string]string, error) {
val, err := f.getFlagType(name, "stringToString", stringToStringConv)
if err != nil {
return map[string]string{}, err
}
return val.(map[string]string), nil
}
// StringToStringVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]string variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) {
f.VarP(newStringToStringValue(value, p), name, "", usage)
}
// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) {
f.VarP(newStringToStringValue(value, p), name, shorthand, usage)
}
// StringToStringVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a map[string]string variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToStringVar(p *map[string]string, name string, value map[string]string, usage string) {
CommandLine.VarP(newStringToStringValue(value, p), name, "", usage)
}
// StringToStringVarP is like StringToStringVar, but accepts a shorthand letter that can be used after a single dash.
func StringToStringVarP(p *map[string]string, name, shorthand string, value map[string]string, usage string) {
CommandLine.VarP(newStringToStringValue(value, p), name, shorthand, usage)
}
// StringToString defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringToString(name string, value map[string]string, usage string) *map[string]string {
p := map[string]string{}
f.StringToStringVarP(&p, name, "", value, usage)
return &p
}
// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string {
p := map[string]string{}
f.StringToStringVarP(&p, name, shorthand, value, usage)
return &p
}
// StringToString defines a string flag with specified name, default value, and usage string.
// The return value is the address of a map[string]string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func StringToString(name string, value map[string]string, usage string) *map[string]string {
return CommandLine.StringToStringP(name, "", value, usage)
}
// StringToStringP is like StringToString, but accepts a shorthand letter that can be used after a single dash.
func StringToStringP(name, shorthand string, value map[string]string, usage string) *map[string]string {
return CommandLine.StringToStringP(name, shorthand, value, usage)
}

View File

@ -21,4 +21,9 @@ _testmain.go
*.exe
*.test
*.bench
*.bench
.vscode
# exclude dependencies in the `/vendor` folder
vendor

View File

@ -1,8 +1,12 @@
go_import_path: github.com/spf13/viper
language: go
env:
global:
- GO111MODULE="on"
go:
- 1.10.x
- 1.11.x
- tip

View File

@ -179,13 +179,14 @@ viper.GetBool("verbose") // true
### Working with Environment Variables
Viper has full support for environment variables. This enables 12 factor
applications out of the box. There are four methods that exist to aid working
applications out of the box. There are five methods that exist to aid working
with ENV:
* `AutomaticEnv()`
* `BindEnv(string...) : error`
* `SetEnvPrefix(string)`
* `SetEnvKeyReplacer(string...) *strings.Replacer`
* `AllowEmptyEnvVar(bool)`
_When working with ENV variables, its important to recognize that Viper
treats ENV variables as case sensitive._
@ -217,6 +218,10 @@ keys to an extent. This is useful if you want to use `-` or something in your
`Get()` calls, but want your environmental variables to use `_` delimiters. An
example of using it can be found in `viper_test.go`.
By default empty environment variables are considered unset and will fall back to
the next configuration source. To treat empty environment variables as set, use
the `AllowEmptyEnv` method.
#### Env example
```go

18
vendor/github.com/spf13/viper/go.mod generated vendored
View File

@ -1,16 +1,24 @@
module github.com/spf13/viper
require (
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
github.com/coreos/etcd v3.3.10+incompatible // indirect
github.com/coreos/go-etcd v2.0.0+incompatible // indirect
github.com/coreos/go-semver v0.2.0 // indirect
github.com/fsnotify/fsnotify v1.4.7
github.com/hashicorp/hcl v1.0.0
github.com/magiconair/properties v1.8.0
github.com/mitchellh/mapstructure v1.0.0
github.com/mitchellh/mapstructure v1.1.2
github.com/pelletier/go-toml v1.2.0
github.com/spf13/afero v1.1.2
github.com/spf13/cast v1.2.0
github.com/spf13/cast v1.3.0
github.com/spf13/jwalterweatherman v1.0.0
github.com/spf13/pflag v1.0.2
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 // indirect
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.2.2
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 // indirect
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 // indirect
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a // indirect
golang.org/x/text v0.3.0 // indirect
gopkg.in/yaml.v2 v2.2.1
gopkg.in/yaml.v2 v2.2.2
)

29
vendor/github.com/spf13/viper/go.sum generated vendored
View File

@ -1,3 +1,7 @@
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -5,22 +9,27 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I=
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 h1:BH3eQWeGbwRU2+wxxuuPOdFBmaiBH81O8BugSjHeTFg=
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -30,6 +30,7 @@ import (
"path/filepath"
"reflect"
"strings"
"sync"
"time"
yaml "gopkg.in/yaml.v2"
@ -186,6 +187,7 @@ type Viper struct {
automaticEnvApplied bool
envKeyReplacer *strings.Replacer
allowEmptyEnv bool
config map[string]interface{}
override map[string]interface{}
@ -276,48 +278,73 @@ func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
}
func WatchConfig() { v.WatchConfig() }
func (v *Viper) WatchConfig() {
initWG := sync.WaitGroup{}
initWG.Add(1)
go func() {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
filename, err := v.getConfigFile()
if err != nil {
log.Println("error:", err)
log.Printf("error: %v\n", err)
return
}
configFile := filepath.Clean(filename)
configDir, _ := filepath.Split(configFile)
realConfigFile, _ := filepath.EvalSymlinks(filename)
done := make(chan bool)
eventsWG := sync.WaitGroup{}
eventsWG.Add(1)
go func() {
for {
select {
case event := <-watcher.Events:
// we only care about the config file
if filepath.Clean(event.Name) == configFile {
if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
err := v.ReadInConfig()
if err != nil {
log.Println("error:", err)
}
case event, ok := <-watcher.Events:
if !ok { // 'Events' channel is closed
eventsWG.Done()
return
}
currentConfigFile, _ := filepath.EvalSymlinks(filename)
// we only care about the config file with the following cases:
// 1 - if the config file was modified or created
// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
const writeOrCreateMask = fsnotify.Write | fsnotify.Create
if (filepath.Clean(event.Name) == configFile &&
event.Op&writeOrCreateMask != 0) ||
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
realConfigFile = currentConfigFile
err := v.ReadInConfig()
if err != nil {
log.Printf("error reading config file: %v\n", err)
}
if v.onConfigChange != nil {
v.onConfigChange(event)
}
} else if filepath.Clean(event.Name) == configFile &&
event.Op&fsnotify.Remove&fsnotify.Remove != 0 {
eventsWG.Done()
return
}
case err := <-watcher.Errors:
log.Println("error:", err)
case err, ok := <-watcher.Errors:
if ok { // 'Errors' channel is not closed
log.Printf("watcher error: %v\n", err)
}
eventsWG.Done()
return
}
}
}()
watcher.Add(configDir)
<-done
initWG.Done() // done initalizing the watch in this go routine, so the parent routine can move on...
eventsWG.Wait() // now, wait for event loop to end in this go-routine...
}()
initWG.Wait() // make sure that the go routine above fully ended before returning
}
// SetConfigFile explicitly defines the path, name and extension of the config file.
@ -347,6 +374,14 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
return strings.ToUpper(in)
}
// AllowEmptyEnv tells Viper to consider set,
// but empty environment variables as valid values instead of falling back.
// For backward compatibility reasons this is false by default.
func AllowEmptyEnv(allowEmptyEnv bool) { v.AllowEmptyEnv(allowEmptyEnv) }
func (v *Viper) AllowEmptyEnv(allowEmptyEnv bool) {
v.allowEmptyEnv = allowEmptyEnv
}
// TODO: should getEnv logic be moved into find(). Can generalize the use of
// rewriting keys many things, Ex: Get('someKey') -> some_key
// (camel case to snake case for JSON keys perhaps)
@ -354,11 +389,14 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
// getEnv is a wrapper around os.Getenv which replaces characters in the original
// key. This allows env vars which have different keys than the config object
// keys.
func (v *Viper) getEnv(key string) string {
func (v *Viper) getEnv(key string) (string, bool) {
if v.envKeyReplacer != nil {
key = v.envKeyReplacer.Replace(key)
}
return os.Getenv(key)
val, ok := os.LookupEnv(key)
return val, ok && (v.allowEmptyEnv || val != "")
}
// ConfigFileUsed returns the file used to populate the config registry.
@ -585,10 +623,9 @@ func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
var parentKey string
var val string
for i := 1; i < len(path); i++ {
parentKey = strings.Join(path[0:i], v.keyDelim)
if val = v.getEnv(v.mergeWithEnvPrefix(parentKey)); val != "" {
if _, ok := v.getEnv(v.mergeWithEnvPrefix(parentKey)); ok {
return parentKey
}
}
@ -774,8 +811,6 @@ func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConf
return err
}
v.insensitiviseMaps()
return nil
}
@ -791,8 +826,6 @@ func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error
return err
}
v.insensitiviseMaps()
return nil
}
@ -835,8 +868,6 @@ func (v *Viper) UnmarshalExact(rawVal interface{}) error {
return err
}
v.insensitiviseMaps()
return nil
}
@ -967,7 +998,7 @@ func (v *Viper) find(lcaseKey string) interface{} {
if v.automaticEnvApplied {
// even if it hasn't been registered, if automaticEnv is used,
// check any Get request
if val = v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); val != "" {
if val, ok := v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); ok {
return val
}
if nested && v.isPathShadowedInAutoEnv(path) != "" {
@ -976,7 +1007,7 @@ func (v *Viper) find(lcaseKey string) interface{} {
}
envkey, exists := v.env[lcaseKey]
if exists {
if val = v.getEnv(envkey); val != "" {
if val, ok := v.getEnv(envkey); ok {
return val
}
}
@ -1222,13 +1253,21 @@ func (v *Viper) ReadConfig(in io.Reader) error {
// MergeConfig merges a new configuration with an existing config.
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
func (v *Viper) MergeConfig(in io.Reader) error {
if v.config == nil {
v.config = make(map[string]interface{})
}
cfg := make(map[string]interface{})
if err := v.unmarshalReader(in, cfg); err != nil {
return err
}
return v.MergeConfigMap(cfg)
}
// MergeConfigMap merges the configuration from the map given with an existing config.
// Note that the map given may be modified.
func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) }
func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error {
if v.config == nil {
v.config = make(map[string]interface{})
}
insensitiviseMap(cfg)
mergeMaps(cfg, v.config, nil)
return nil
}
@ -1534,13 +1573,6 @@ func (v *Viper) WatchRemoteConfigOnChannel() error {
return v.watchKeyValueConfigOnChannel()
}
func (v *Viper) insensitiviseMaps() {
insensitiviseMap(v.config)
insensitiviseMap(v.defaults)
insensitiviseMap(v.override)
insensitiviseMap(v.kvstore)
}
// Retrieve the first found remote configuration.
func (v *Viper) getKeyValueConfig() error {
if RemoteConfig == nil {