util.go - viper - [fork] go viper port for 9front
 (HTM) git clone https://git.drkhsh.at/viper.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       util.go (5502B)
       ---
            1 // Copyright © 2014 Steve Francia <spf@spf13.com>.
            2 //
            3 // Use of this source code is governed by an MIT-style
            4 // license that can be found in the LICENSE file.
            5 
            6 // Viper is a application configuration system.
            7 // It believes that applications can be configured a variety of ways
            8 // via flags, ENVIRONMENT variables, configuration files retrieved
            9 // from the file system, or a remote key/value store.
           10 
           11 package viper
           12 
           13 import (
           14         "fmt"
           15         "os"
           16         "path/filepath"
           17         "runtime"
           18         "strings"
           19         "unicode"
           20 
           21         "github.com/spf13/afero"
           22         "github.com/spf13/cast"
           23         jww "github.com/spf13/jwalterweatherman"
           24 )
           25 
           26 // ConfigParseError denotes failing to parse configuration file.
           27 type ConfigParseError struct {
           28         err error
           29 }
           30 
           31 // Error returns the formatted configuration error.
           32 func (pe ConfigParseError) Error() string {
           33         return fmt.Sprintf("While parsing config: %s", pe.err.Error())
           34 }
           35 
           36 // toCaseInsensitiveValue checks if the value is a  map;
           37 // if so, create a copy and lower-case the keys recursively.
           38 func toCaseInsensitiveValue(value interface{}) interface{} {
           39         switch v := value.(type) {
           40         case map[interface{}]interface{}:
           41                 value = copyAndInsensitiviseMap(cast.ToStringMap(v))
           42         case map[string]interface{}:
           43                 value = copyAndInsensitiviseMap(v)
           44         }
           45 
           46         return value
           47 }
           48 
           49 // copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
           50 // any map it makes case insensitive.
           51 func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
           52         nm := make(map[string]interface{})
           53 
           54         for key, val := range m {
           55                 lkey := strings.ToLower(key)
           56                 switch v := val.(type) {
           57                 case map[interface{}]interface{}:
           58                         nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
           59                 case map[string]interface{}:
           60                         nm[lkey] = copyAndInsensitiviseMap(v)
           61                 default:
           62                         nm[lkey] = v
           63                 }
           64         }
           65 
           66         return nm
           67 }
           68 
           69 func insensitiviseMap(m map[string]interface{}) {
           70         for key, val := range m {
           71                 switch val.(type) {
           72                 case map[interface{}]interface{}:
           73                         // nested map: cast and recursively insensitivise
           74                         val = cast.ToStringMap(val)
           75                         insensitiviseMap(val.(map[string]interface{}))
           76                 case map[string]interface{}:
           77                         // nested map: recursively insensitivise
           78                         insensitiviseMap(val.(map[string]interface{}))
           79                 }
           80 
           81                 lower := strings.ToLower(key)
           82                 if key != lower {
           83                         // remove old key (not lower-cased)
           84                         delete(m, key)
           85                 }
           86                 // update map
           87                 m[lower] = val
           88         }
           89 }
           90 
           91 func absPathify(inPath string) string {
           92         jww.INFO.Println("Trying to resolve absolute path to", inPath)
           93 
           94         if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
           95                 inPath = userHomeDir() + inPath[5:]
           96         }
           97 
           98         if strings.HasPrefix(inPath, "$") {
           99                 end := strings.Index(inPath, string(os.PathSeparator))
          100 
          101                 var value, suffix string
          102                 if end == -1 {
          103                         value = os.Getenv(inPath[1:])
          104                 } else {
          105                         value = os.Getenv(inPath[1:end])
          106                         suffix = inPath[end:]
          107                 }
          108 
          109                 inPath = value + suffix
          110         }
          111 
          112         if filepath.IsAbs(inPath) {
          113                 return filepath.Clean(inPath)
          114         }
          115 
          116         p, err := filepath.Abs(inPath)
          117         if err == nil {
          118                 return filepath.Clean(p)
          119         }
          120 
          121         jww.ERROR.Println("Couldn't discover absolute path")
          122         jww.ERROR.Println(err)
          123         return ""
          124 }
          125 
          126 // Check if file Exists
          127 func exists(fs afero.Fs, path string) (bool, error) {
          128         stat, err := fs.Stat(path)
          129         if err == nil {
          130                 return !stat.IsDir(), nil
          131         }
          132         if os.IsNotExist(err) {
          133                 return false, nil
          134         }
          135         return false, err
          136 }
          137 
          138 func stringInSlice(a string, list []string) bool {
          139         for _, b := range list {
          140                 if b == a {
          141                         return true
          142                 }
          143         }
          144         return false
          145 }
          146 
          147 func userHomeDir() string {
          148         if runtime.GOOS == "windows" {
          149                 home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
          150                 if home == "" {
          151                         home = os.Getenv("USERPROFILE")
          152                 }
          153                 return home
          154         }
          155         return os.Getenv("HOME")
          156 }
          157 
          158 func safeMul(a, b uint) uint {
          159         c := a * b
          160         if a > 1 && b > 1 && c/b != a {
          161                 return 0
          162         }
          163         return c
          164 }
          165 
          166 // parseSizeInBytes converts strings like 1GB or 12 mb into an unsigned integer number of bytes
          167 func parseSizeInBytes(sizeStr string) uint {
          168         sizeStr = strings.TrimSpace(sizeStr)
          169         lastChar := len(sizeStr) - 1
          170         multiplier := uint(1)
          171 
          172         if lastChar > 0 {
          173                 if sizeStr[lastChar] == 'b' || sizeStr[lastChar] == 'B' {
          174                         if lastChar > 1 {
          175                                 switch unicode.ToLower(rune(sizeStr[lastChar-1])) {
          176                                 case 'k':
          177                                         multiplier = 1 << 10
          178                                         sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
          179                                 case 'm':
          180                                         multiplier = 1 << 20
          181                                         sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
          182                                 case 'g':
          183                                         multiplier = 1 << 30
          184                                         sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
          185                                 default:
          186                                         multiplier = 1
          187                                         sizeStr = strings.TrimSpace(sizeStr[:lastChar])
          188                                 }
          189                         }
          190                 }
          191         }
          192 
          193         size := cast.ToInt(sizeStr)
          194         if size < 0 {
          195                 size = 0
          196         }
          197 
          198         return safeMul(uint(size), multiplier)
          199 }
          200 
          201 // deepSearch scans deep maps, following the key indexes listed in the
          202 // sequence "path".
          203 // The last value is expected to be another map, and is returned.
          204 //
          205 // In case intermediate keys do not exist, or map to a non-map value,
          206 // a new map is created and inserted, and the search continues from there:
          207 // the initial map "m" may be modified!
          208 func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
          209         for _, k := range path {
          210                 m2, ok := m[k]
          211                 if !ok {
          212                         // intermediate key does not exist
          213                         // => create it and continue from there
          214                         m3 := make(map[string]interface{})
          215                         m[k] = m3
          216                         m = m3
          217                         continue
          218                 }
          219                 m3, ok := m2.(map[string]interface{})
          220                 if !ok {
          221                         // intermediate key is a value
          222                         // => replace with a new map
          223                         m3 = make(map[string]interface{})
          224                         m[k] = m3
          225                 }
          226                 // continue search from here
          227                 m = m3
          228         }
          229         return m
          230 }