github.com/astaxie/beego@v1.12.3/config/yaml/yaml.go (about)

     1  // Copyright 2014 beego Author. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package yaml for config provider
    16  //
    17  // depend on github.com/beego/goyaml2
    18  //
    19  // go install github.com/beego/goyaml2
    20  //
    21  // Usage:
    22  //  import(
    23  //   _ "github.com/astaxie/beego/config/yaml"
    24  //     "github.com/astaxie/beego/config"
    25  //  )
    26  //
    27  //  cnf, err := config.NewConfig("yaml", "config.yaml")
    28  //
    29  //More docs http://beego.me/docs/module/config.md
    30  package yaml
    31  
    32  import (
    33  	"bytes"
    34  	"encoding/json"
    35  	"errors"
    36  	"fmt"
    37  	"io/ioutil"
    38  	"log"
    39  	"os"
    40  	"strings"
    41  	"sync"
    42  
    43  	"github.com/astaxie/beego/config"
    44  	"github.com/beego/goyaml2"
    45  )
    46  
    47  // Config is a yaml config parser and implements Config interface.
    48  type Config struct{}
    49  
    50  // Parse returns a ConfigContainer with parsed yaml config map.
    51  func (yaml *Config) Parse(filename string) (y config.Configer, err error) {
    52  	cnf, err := ReadYmlReader(filename)
    53  	if err != nil {
    54  		return
    55  	}
    56  	y = &ConfigContainer{
    57  		data: cnf,
    58  	}
    59  	return
    60  }
    61  
    62  // ParseData parse yaml data
    63  func (yaml *Config) ParseData(data []byte) (config.Configer, error) {
    64  	cnf, err := parseYML(data)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	return &ConfigContainer{
    70  		data: cnf,
    71  	}, nil
    72  }
    73  
    74  // ReadYmlReader Read yaml file to map.
    75  // if json like, use json package, unless goyaml2 package.
    76  func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
    77  	buf, err := ioutil.ReadFile(path)
    78  	if err != nil {
    79  		return
    80  	}
    81  
    82  	return parseYML(buf)
    83  }
    84  
    85  // parseYML parse yaml formatted []byte to map.
    86  func parseYML(buf []byte) (cnf map[string]interface{}, err error) {
    87  	if len(buf) < 3 {
    88  		return
    89  	}
    90  
    91  	if string(buf[0:1]) == "{" {
    92  		log.Println("Look like a Json, try json umarshal")
    93  		err = json.Unmarshal(buf, &cnf)
    94  		if err == nil {
    95  			log.Println("It is Json Map")
    96  			return
    97  		}
    98  	}
    99  
   100  	data, err := goyaml2.Read(bytes.NewReader(buf))
   101  	if err != nil {
   102  		log.Println("Goyaml2 ERR>", string(buf), err)
   103  		return
   104  	}
   105  
   106  	if data == nil {
   107  		log.Println("Goyaml2 output nil? Pls report bug\n" + string(buf))
   108  		return
   109  	}
   110  	cnf, ok := data.(map[string]interface{})
   111  	if !ok {
   112  		log.Println("Not a Map? >> ", string(buf), data)
   113  		cnf = nil
   114  	}
   115  	cnf = config.ExpandValueEnvForMap(cnf)
   116  	return
   117  }
   118  
   119  // ConfigContainer A Config represents the yaml configuration.
   120  type ConfigContainer struct {
   121  	data map[string]interface{}
   122  	sync.RWMutex
   123  }
   124  
   125  // Bool returns the boolean value for a given key.
   126  func (c *ConfigContainer) Bool(key string) (bool, error) {
   127  	v, err := c.getData(key)
   128  	if err != nil {
   129  		return false, err
   130  	}
   131  	return config.ParseBool(v)
   132  }
   133  
   134  // DefaultBool return the bool value if has no error
   135  // otherwise return the defaultval
   136  func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
   137  	v, err := c.Bool(key)
   138  	if err != nil {
   139  		return defaultval
   140  	}
   141  	return v
   142  }
   143  
   144  // Int returns the integer value for a given key.
   145  func (c *ConfigContainer) Int(key string) (int, error) {
   146  	if v, err := c.getData(key); err != nil {
   147  		return 0, err
   148  	} else if vv, ok := v.(int); ok {
   149  		return vv, nil
   150  	} else if vv, ok := v.(int64); ok {
   151  		return int(vv), nil
   152  	}
   153  	return 0, errors.New("not int value")
   154  }
   155  
   156  // DefaultInt returns the integer value for a given key.
   157  // if err != nil return defaultval
   158  func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
   159  	v, err := c.Int(key)
   160  	if err != nil {
   161  		return defaultval
   162  	}
   163  	return v
   164  }
   165  
   166  // Int64 returns the int64 value for a given key.
   167  func (c *ConfigContainer) Int64(key string) (int64, error) {
   168  	if v, err := c.getData(key); err != nil {
   169  		return 0, err
   170  	} else if vv, ok := v.(int64); ok {
   171  		return vv, nil
   172  	}
   173  	return 0, errors.New("not bool value")
   174  }
   175  
   176  // DefaultInt64 returns the int64 value for a given key.
   177  // if err != nil return defaultval
   178  func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
   179  	v, err := c.Int64(key)
   180  	if err != nil {
   181  		return defaultval
   182  	}
   183  	return v
   184  }
   185  
   186  // Float returns the float value for a given key.
   187  func (c *ConfigContainer) Float(key string) (float64, error) {
   188  	if v, err := c.getData(key); err != nil {
   189  		return 0.0, err
   190  	} else if vv, ok := v.(float64); ok {
   191  		return vv, nil
   192  	} else if vv, ok := v.(int); ok {
   193  		return float64(vv), nil
   194  	} else if vv, ok := v.(int64); ok {
   195  		return float64(vv), nil
   196  	}
   197  	return 0.0, errors.New("not float64 value")
   198  }
   199  
   200  // DefaultFloat returns the float64 value for a given key.
   201  // if err != nil return defaultval
   202  func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
   203  	v, err := c.Float(key)
   204  	if err != nil {
   205  		return defaultval
   206  	}
   207  	return v
   208  }
   209  
   210  // String returns the string value for a given key.
   211  func (c *ConfigContainer) String(key string) string {
   212  	if v, err := c.getData(key); err == nil {
   213  		if vv, ok := v.(string); ok {
   214  			return vv
   215  		}
   216  	}
   217  	return ""
   218  }
   219  
   220  // DefaultString returns the string value for a given key.
   221  // if err != nil return defaultval
   222  func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
   223  	v := c.String(key)
   224  	if v == "" {
   225  		return defaultval
   226  	}
   227  	return v
   228  }
   229  
   230  // Strings returns the []string value for a given key.
   231  func (c *ConfigContainer) Strings(key string) []string {
   232  	v := c.String(key)
   233  	if v == "" {
   234  		return nil
   235  	}
   236  	return strings.Split(v, ";")
   237  }
   238  
   239  // DefaultStrings returns the []string value for a given key.
   240  // if err != nil return defaultval
   241  func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
   242  	v := c.Strings(key)
   243  	if v == nil {
   244  		return defaultval
   245  	}
   246  	return v
   247  }
   248  
   249  // GetSection returns map for the given section
   250  func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
   251  
   252  	if v, ok := c.data[section]; ok {
   253  		return v.(map[string]string), nil
   254  	}
   255  	return nil, errors.New("not exist section")
   256  }
   257  
   258  // SaveConfigFile save the config into file
   259  func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
   260  	// Write configuration file by filename.
   261  	f, err := os.Create(filename)
   262  	if err != nil {
   263  		return err
   264  	}
   265  	defer f.Close()
   266  	err = goyaml2.Write(f, c.data)
   267  	return err
   268  }
   269  
   270  // Set writes a new value for key.
   271  func (c *ConfigContainer) Set(key, val string) error {
   272  	c.Lock()
   273  	defer c.Unlock()
   274  	c.data[key] = val
   275  	return nil
   276  }
   277  
   278  // DIY returns the raw value by a given key.
   279  func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
   280  	return c.getData(key)
   281  }
   282  
   283  func (c *ConfigContainer) getData(key string) (interface{}, error) {
   284  
   285  	if len(key) == 0 {
   286  		return nil, errors.New("key is empty")
   287  	}
   288  	c.RLock()
   289  	defer c.RUnlock()
   290  
   291  	keys := strings.Split(key, ".")
   292  	tmpData := c.data
   293  	for idx, k := range keys {
   294  		if v, ok := tmpData[k]; ok {
   295  			switch v.(type) {
   296  			case map[string]interface{}:
   297  				{
   298  					tmpData = v.(map[string]interface{})
   299  					if idx == len(keys)-1 {
   300  						return tmpData, nil
   301  					}
   302  				}
   303  			default:
   304  				{
   305  					return v, nil
   306  				}
   307  
   308  			}
   309  		}
   310  	}
   311  	return nil, fmt.Errorf("not exist key %q", key)
   312  }
   313  
   314  func init() {
   315  	config.Register("yaml", &Config{})
   316  }