OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / magiconair / properties / properties.go
diff --git a/vendor/github.com/magiconair/properties/properties.go b/vendor/github.com/magiconair/properties/properties.go
new file mode 100644 (file)
index 0000000..85bb186
--- /dev/null
@@ -0,0 +1,811 @@
+// Copyright 2017 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+// BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer.
+// BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used.
+
+import (
+       "fmt"
+       "io"
+       "log"
+       "os"
+       "regexp"
+       "strconv"
+       "strings"
+       "time"
+       "unicode/utf8"
+)
+
+// ErrorHandlerFunc defines the type of function which handles failures
+// of the MustXXX() functions. An error handler function must exit
+// the application after handling the error.
+type ErrorHandlerFunc func(error)
+
+// ErrorHandler is the function which handles failures of the MustXXX()
+// functions. The default is LogFatalHandler.
+var ErrorHandler ErrorHandlerFunc = LogFatalHandler
+
+// LogHandlerFunc defines the function prototype for logging errors.
+type LogHandlerFunc func(fmt string, args ...interface{})
+
+// LogPrintf defines a log handler which uses log.Printf.
+var LogPrintf LogHandlerFunc = log.Printf
+
+// LogFatalHandler handles the error by logging a fatal error and exiting.
+func LogFatalHandler(err error) {
+       log.Fatal(err)
+}
+
+// PanicHandler handles the error by panicking.
+func PanicHandler(err error) {
+       panic(err)
+}
+
+// -----------------------------------------------------------------------------
+
+// A Properties contains the key/value pairs from the properties input.
+// All values are stored in unexpanded form and are expanded at runtime
+type Properties struct {
+       // Pre-/Postfix for property expansion.
+       Prefix  string
+       Postfix string
+
+       // DisableExpansion controls the expansion of properties on Get()
+       // and the check for circular references on Set(). When set to
+       // true Properties behaves like a simple key/value store and does
+       // not check for circular references on Get() or on Set().
+       DisableExpansion bool
+
+       // Stores the key/value pairs
+       m map[string]string
+
+       // Stores the comments per key.
+       c map[string][]string
+
+       // Stores the keys in order of appearance.
+       k []string
+}
+
+// NewProperties creates a new Properties struct with the default
+// configuration for "${key}" expressions.
+func NewProperties() *Properties {
+       return &Properties{
+               Prefix:  "${",
+               Postfix: "}",
+               m:       map[string]string{},
+               c:       map[string][]string{},
+               k:       []string{},
+       }
+}
+
+// Get returns the expanded value for the given key if exists.
+// Otherwise, ok is false.
+func (p *Properties) Get(key string) (value string, ok bool) {
+       v, ok := p.m[key]
+       if p.DisableExpansion {
+               return v, ok
+       }
+       if !ok {
+               return "", false
+       }
+
+       expanded, err := p.expand(v)
+
+       // we guarantee that the expanded value is free of
+       // circular references and malformed expressions
+       // so we panic if we still get an error here.
+       if err != nil {
+               ErrorHandler(fmt.Errorf("%s in %q", err, key+" = "+v))
+       }
+
+       return expanded, true
+}
+
+// MustGet returns the expanded value for the given key if exists.
+// Otherwise, it panics.
+func (p *Properties) MustGet(key string) string {
+       if v, ok := p.Get(key); ok {
+               return v
+       }
+       ErrorHandler(invalidKeyError(key))
+       panic("ErrorHandler should exit")
+}
+
+// ----------------------------------------------------------------------------
+
+// ClearComments removes the comments for all keys.
+func (p *Properties) ClearComments() {
+       p.c = map[string][]string{}
+}
+
+// ----------------------------------------------------------------------------
+
+// GetComment returns the last comment before the given key or an empty string.
+func (p *Properties) GetComment(key string) string {
+       comments, ok := p.c[key]
+       if !ok || len(comments) == 0 {
+               return ""
+       }
+       return comments[len(comments)-1]
+}
+
+// ----------------------------------------------------------------------------
+
+// GetComments returns all comments that appeared before the given key or nil.
+func (p *Properties) GetComments(key string) []string {
+       if comments, ok := p.c[key]; ok {
+               return comments
+       }
+       return nil
+}
+
+// ----------------------------------------------------------------------------
+
+// SetComment sets the comment for the key.
+func (p *Properties) SetComment(key, comment string) {
+       p.c[key] = []string{comment}
+}
+
+// ----------------------------------------------------------------------------
+
+// SetComments sets the comments for the key. If the comments are nil then
+// all comments for this key are deleted.
+func (p *Properties) SetComments(key string, comments []string) {
+       if comments == nil {
+               delete(p.c, key)
+               return
+       }
+       p.c[key] = comments
+}
+
+// ----------------------------------------------------------------------------
+
+// GetBool checks if the expanded value is one of '1', 'yes',
+// 'true' or 'on' if the key exists. The comparison is case-insensitive.
+// If the key does not exist the default value is returned.
+func (p *Properties) GetBool(key string, def bool) bool {
+       v, err := p.getBool(key)
+       if err != nil {
+               return def
+       }
+       return v
+}
+
+// MustGetBool checks if the expanded value is one of '1', 'yes',
+// 'true' or 'on' if the key exists. The comparison is case-insensitive.
+// If the key does not exist the function panics.
+func (p *Properties) MustGetBool(key string) bool {
+       v, err := p.getBool(key)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return v
+}
+
+func (p *Properties) getBool(key string) (value bool, err error) {
+       if v, ok := p.Get(key); ok {
+               return boolVal(v), nil
+       }
+       return false, invalidKeyError(key)
+}
+
+func boolVal(v string) bool {
+       v = strings.ToLower(v)
+       return v == "1" || v == "true" || v == "yes" || v == "on"
+}
+
+// ----------------------------------------------------------------------------
+
+// GetDuration parses the expanded value as an time.Duration (in ns) if the
+// key exists. If key does not exist or the value cannot be parsed the default
+// value is returned. In almost all cases you want to use GetParsedDuration().
+func (p *Properties) GetDuration(key string, def time.Duration) time.Duration {
+       v, err := p.getInt64(key)
+       if err != nil {
+               return def
+       }
+       return time.Duration(v)
+}
+
+// MustGetDuration parses the expanded value as an time.Duration (in ns) if
+// the key exists. If key does not exist or the value cannot be parsed the
+// function panics. In almost all cases you want to use MustGetParsedDuration().
+func (p *Properties) MustGetDuration(key string) time.Duration {
+       v, err := p.getInt64(key)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return time.Duration(v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration {
+       s, ok := p.Get(key)
+       if !ok {
+               return def
+       }
+       v, err := time.ParseDuration(s)
+       if err != nil {
+               return def
+       }
+       return v
+}
+
+// MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetParsedDuration(key string) time.Duration {
+       s, ok := p.Get(key)
+       if !ok {
+               ErrorHandler(invalidKeyError(key))
+       }
+       v, err := time.ParseDuration(s)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return v
+}
+
+// ----------------------------------------------------------------------------
+
+// GetFloat64 parses the expanded value as a float64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetFloat64(key string, def float64) float64 {
+       v, err := p.getFloat64(key)
+       if err != nil {
+               return def
+       }
+       return v
+}
+
+// MustGetFloat64 parses the expanded value as a float64 if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetFloat64(key string) float64 {
+       v, err := p.getFloat64(key)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return v
+}
+
+func (p *Properties) getFloat64(key string) (value float64, err error) {
+       if v, ok := p.Get(key); ok {
+               value, err = strconv.ParseFloat(v, 64)
+               if err != nil {
+                       return 0, err
+               }
+               return value, nil
+       }
+       return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetInt parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned. If the value does not fit into an int the
+// function panics with an out of range error.
+func (p *Properties) GetInt(key string, def int) int {
+       v, err := p.getInt64(key)
+       if err != nil {
+               return def
+       }
+       return intRangeCheck(key, v)
+}
+
+// MustGetInt parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+// If the value does not fit into an int the function panics with
+// an out of range error.
+func (p *Properties) MustGetInt(key string) int {
+       v, err := p.getInt64(key)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return intRangeCheck(key, v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetInt64 parses the expanded value as an int64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetInt64(key string, def int64) int64 {
+       v, err := p.getInt64(key)
+       if err != nil {
+               return def
+       }
+       return v
+}
+
+// MustGetInt64 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetInt64(key string) int64 {
+       v, err := p.getInt64(key)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return v
+}
+
+func (p *Properties) getInt64(key string) (value int64, err error) {
+       if v, ok := p.Get(key); ok {
+               value, err = strconv.ParseInt(v, 10, 64)
+               if err != nil {
+                       return 0, err
+               }
+               return value, nil
+       }
+       return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetUint parses the expanded value as an uint if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned. If the value does not fit into an int the
+// function panics with an out of range error.
+func (p *Properties) GetUint(key string, def uint) uint {
+       v, err := p.getUint64(key)
+       if err != nil {
+               return def
+       }
+       return uintRangeCheck(key, v)
+}
+
+// MustGetUint parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+// If the value does not fit into an int the function panics with
+// an out of range error.
+func (p *Properties) MustGetUint(key string) uint {
+       v, err := p.getUint64(key)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return uintRangeCheck(key, v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetUint64 parses the expanded value as an uint64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetUint64(key string, def uint64) uint64 {
+       v, err := p.getUint64(key)
+       if err != nil {
+               return def
+       }
+       return v
+}
+
+// MustGetUint64 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetUint64(key string) uint64 {
+       v, err := p.getUint64(key)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return v
+}
+
+func (p *Properties) getUint64(key string) (value uint64, err error) {
+       if v, ok := p.Get(key); ok {
+               value, err = strconv.ParseUint(v, 10, 64)
+               if err != nil {
+                       return 0, err
+               }
+               return value, nil
+       }
+       return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetString returns the expanded value for the given key if exists or
+// the default value otherwise.
+func (p *Properties) GetString(key, def string) string {
+       if v, ok := p.Get(key); ok {
+               return v
+       }
+       return def
+}
+
+// MustGetString returns the expanded value for the given key if exists or
+// panics otherwise.
+func (p *Properties) MustGetString(key string) string {
+       if v, ok := p.Get(key); ok {
+               return v
+       }
+       ErrorHandler(invalidKeyError(key))
+       panic("ErrorHandler should exit")
+}
+
+// ----------------------------------------------------------------------------
+
+// Filter returns a new properties object which contains all properties
+// for which the key matches the pattern.
+func (p *Properties) Filter(pattern string) (*Properties, error) {
+       re, err := regexp.Compile(pattern)
+       if err != nil {
+               return nil, err
+       }
+
+       return p.FilterRegexp(re), nil
+}
+
+// FilterRegexp returns a new properties object which contains all properties
+// for which the key matches the regular expression.
+func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties {
+       pp := NewProperties()
+       for _, k := range p.k {
+               if re.MatchString(k) {
+                       // TODO(fs): we are ignoring the error which flags a circular reference.
+                       // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
+                       pp.Set(k, p.m[k])
+               }
+       }
+       return pp
+}
+
+// FilterPrefix returns a new properties object with a subset of all keys
+// with the given prefix.
+func (p *Properties) FilterPrefix(prefix string) *Properties {
+       pp := NewProperties()
+       for _, k := range p.k {
+               if strings.HasPrefix(k, prefix) {
+                       // TODO(fs): we are ignoring the error which flags a circular reference.
+                       // TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
+                       pp.Set(k, p.m[k])
+               }
+       }
+       return pp
+}
+
+// FilterStripPrefix returns a new properties object with a subset of all keys
+// with the given prefix and the prefix removed from the keys.
+func (p *Properties) FilterStripPrefix(prefix string) *Properties {
+       pp := NewProperties()
+       n := len(prefix)
+       for _, k := range p.k {
+               if len(k) > len(prefix) && strings.HasPrefix(k, prefix) {
+                       // TODO(fs): we are ignoring the error which flags a circular reference.
+                       // TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference
+                       // TODO(fs): this function should probably return an error but the signature is fixed
+                       pp.Set(k[n:], p.m[k])
+               }
+       }
+       return pp
+}
+
+// Len returns the number of keys.
+func (p *Properties) Len() int {
+       return len(p.m)
+}
+
+// Keys returns all keys in the same order as in the input.
+func (p *Properties) Keys() []string {
+       keys := make([]string, len(p.k))
+       copy(keys, p.k)
+       return keys
+}
+
+// Set sets the property key to the corresponding value.
+// If a value for key existed before then ok is true and prev
+// contains the previous value. If the value contains a
+// circular reference or a malformed expression then
+// an error is returned.
+// An empty key is silently ignored.
+func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
+       if key == "" {
+               return "", false, nil
+       }
+
+       // if expansion is disabled we allow circular references
+       if p.DisableExpansion {
+               prev, ok = p.Get(key)
+               p.m[key] = value
+               if !ok {
+                       p.k = append(p.k, key)
+               }
+               return prev, ok, nil
+       }
+
+       // to check for a circular reference we temporarily need
+       // to set the new value. If there is an error then revert
+       // to the previous state. Only if all tests are successful
+       // then we add the key to the p.k list.
+       prev, ok = p.Get(key)
+       p.m[key] = value
+
+       // now check for a circular reference
+       _, err = p.expand(value)
+       if err != nil {
+
+               // revert to the previous state
+               if ok {
+                       p.m[key] = prev
+               } else {
+                       delete(p.m, key)
+               }
+
+               return "", false, err
+       }
+
+       if !ok {
+               p.k = append(p.k, key)
+       }
+
+       return prev, ok, nil
+}
+
+// SetValue sets property key to the default string value
+// as defined by fmt.Sprintf("%v").
+func (p *Properties) SetValue(key string, value interface{}) error {
+       _, _, err := p.Set(key, fmt.Sprintf("%v", value))
+       return err
+}
+
+// MustSet sets the property key to the corresponding value.
+// If a value for key existed before then ok is true and prev
+// contains the previous value. An empty key is silently ignored.
+func (p *Properties) MustSet(key, value string) (prev string, ok bool) {
+       prev, ok, err := p.Set(key, value)
+       if err != nil {
+               ErrorHandler(err)
+       }
+       return prev, ok
+}
+
+// String returns a string of all expanded 'key = value' pairs.
+func (p *Properties) String() string {
+       var s string
+       for _, key := range p.k {
+               value, _ := p.Get(key)
+               s = fmt.Sprintf("%s%s = %s\n", s, key, value)
+       }
+       return s
+}
+
+// Write writes all unexpanded 'key = value' pairs to the given writer.
+// Write returns the number of bytes written and any write error encountered.
+func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) {
+       return p.WriteComment(w, "", enc)
+}
+
+// WriteComment writes all unexpanced 'key = value' pairs to the given writer.
+// If prefix is not empty then comments are written with a blank line and the
+// given prefix. The prefix should be either "# " or "! " to be compatible with
+// the properties file format. Otherwise, the properties parser will not be
+// able to read the file back in. It returns the number of bytes written and
+// any write error encountered.
+func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) {
+       var x int
+
+       for _, key := range p.k {
+               value := p.m[key]
+
+               if prefix != "" {
+                       if comments, ok := p.c[key]; ok {
+                               // don't print comments if they are all empty
+                               allEmpty := true
+                               for _, c := range comments {
+                                       if c != "" {
+                                               allEmpty = false
+                                               break
+                                       }
+                               }
+
+                               if !allEmpty {
+                                       // add a blank line between entries but not at the top
+                                       if len(comments) > 0 && n > 0 {
+                                               x, err = fmt.Fprintln(w)
+                                               if err != nil {
+                                                       return
+                                               }
+                                               n += x
+                                       }
+
+                                       for _, c := range comments {
+                                               x, err = fmt.Fprintf(w, "%s%s\n", prefix, encode(c, "", enc))
+                                               if err != nil {
+                                                       return
+                                               }
+                                               n += x
+                                       }
+                               }
+                       }
+               }
+
+               x, err = fmt.Fprintf(w, "%s = %s\n", encode(key, " :", enc), encode(value, "", enc))
+               if err != nil {
+                       return
+               }
+               n += x
+       }
+       return
+}
+
+// Map returns a copy of the properties as a map.
+func (p *Properties) Map() map[string]string {
+       m := make(map[string]string)
+       for k, v := range p.m {
+               m[k] = v
+       }
+       return m
+}
+
+// FilterFunc returns a copy of the properties which includes the values which passed all filters.
+func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties {
+       pp := NewProperties()
+outer:
+       for k, v := range p.m {
+               for _, f := range filters {
+                       if !f(k, v) {
+                               continue outer
+                       }
+                       pp.Set(k, v)
+               }
+       }
+       return pp
+}
+
+// ----------------------------------------------------------------------------
+
+// Delete removes the key and its comments.
+func (p *Properties) Delete(key string) {
+       delete(p.m, key)
+       delete(p.c, key)
+       newKeys := []string{}
+       for _, k := range p.k {
+               if k != key {
+                       newKeys = append(newKeys, k)
+               }
+       }
+       p.k = newKeys
+}
+
+// Merge merges properties, comments and keys from other *Properties into p
+func (p *Properties) Merge(other *Properties) {
+       for k, v := range other.m {
+               p.m[k] = v
+       }
+       for k, v := range other.c {
+               p.c[k] = v
+       }
+
+outer:
+       for _, otherKey := range other.k {
+               for _, key := range p.k {
+                       if otherKey == key {
+                               continue outer
+                       }
+               }
+               p.k = append(p.k, otherKey)
+       }
+}
+
+// ----------------------------------------------------------------------------
+
+// check expands all values and returns an error if a circular reference or
+// a malformed expression was found.
+func (p *Properties) check() error {
+       for _, value := range p.m {
+               if _, err := p.expand(value); err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+func (p *Properties) expand(input string) (string, error) {
+       // no pre/postfix -> nothing to expand
+       if p.Prefix == "" && p.Postfix == "" {
+               return input, nil
+       }
+
+       return expand(input, make(map[string]bool), p.Prefix, p.Postfix, p.m)
+}
+
+// expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values.
+// The function keeps track of the keys that were already expanded and stops if it
+// detects a circular reference or a malformed expression of the form '(prefix)key'.
+func expand(s string, keys map[string]bool, prefix, postfix string, values map[string]string) (string, error) {
+       start := strings.Index(s, prefix)
+       if start == -1 {
+               return s, nil
+       }
+
+       keyStart := start + len(prefix)
+       keyLen := strings.Index(s[keyStart:], postfix)
+       if keyLen == -1 {
+               return "", fmt.Errorf("malformed expression")
+       }
+
+       end := keyStart + keyLen + len(postfix) - 1
+       key := s[keyStart : keyStart+keyLen]
+
+       // fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key)
+
+       if _, ok := keys[key]; ok {
+               return "", fmt.Errorf("circular reference")
+       }
+
+       val, ok := values[key]
+       if !ok {
+               val = os.Getenv(key)
+       }
+
+       // remember that we've seen the key
+       keys[key] = true
+
+       return expand(s[:start]+val+s[end+1:], keys, prefix, postfix, values)
+}
+
+// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters.
+func encode(s string, special string, enc Encoding) string {
+       switch enc {
+       case UTF8:
+               return encodeUtf8(s, special)
+       case ISO_8859_1:
+               return encodeIso(s, special)
+       default:
+               panic(fmt.Sprintf("unsupported encoding %v", enc))
+       }
+}
+
+func encodeUtf8(s string, special string) string {
+       v := ""
+       for pos := 0; pos < len(s); {
+               r, w := utf8.DecodeRuneInString(s[pos:])
+               pos += w
+               v += escape(r, special)
+       }
+       return v
+}
+
+func encodeIso(s string, special string) string {
+       var r rune
+       var w int
+       var v string
+       for pos := 0; pos < len(s); {
+               switch r, w = utf8.DecodeRuneInString(s[pos:]); {
+               case r < 1<<8: // single byte rune -> escape special chars only
+                       v += escape(r, special)
+               case r < 1<<16: // two byte rune -> unicode literal
+                       v += fmt.Sprintf("\\u%04x", r)
+               default: // more than two bytes per rune -> can't encode
+                       v += "?"
+               }
+               pos += w
+       }
+       return v
+}
+
+func escape(r rune, special string) string {
+       switch r {
+       case '\f':
+               return "\\f"
+       case '\n':
+               return "\\n"
+       case '\r':
+               return "\\r"
+       case '\t':
+               return "\\t"
+       default:
+               if strings.ContainsRune(special, r) {
+                       return "\\" + string(r)
+               }
+               return string(r)
+       }
+}
+
+func invalidKeyError(key string) error {
+       return fmt.Errorf("unknown property: %s", key)
+}