yaml.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. // Package yaml for config provider
  15. //
  16. // depend on github.com/beego/goyaml2
  17. //
  18. // go install github.com/beego/goyaml2
  19. //
  20. // Usage:
  21. // import(
  22. // _ "github.com/astaxie/beego/config/yaml"
  23. // "github.com/astaxie/beego/config"
  24. // )
  25. //
  26. // cnf, err := config.NewConfig("yaml", "config.yaml")
  27. //
  28. //More docs http://beego.me/docs/module/config.md
  29. package yaml
  30. import (
  31. "bytes"
  32. "encoding/json"
  33. "errors"
  34. "fmt"
  35. "io/ioutil"
  36. "log"
  37. "os"
  38. "strings"
  39. "sync"
  40. "github.com/astaxie/beego/config"
  41. "github.com/beego/goyaml2"
  42. )
  43. // Config is a yaml config parser and implements Config interface.
  44. type Config struct{}
  45. // Parse returns a ConfigContainer with parsed yaml config map.
  46. func (yaml *Config) Parse(filename string) (y config.Configer, err error) {
  47. cnf, err := ReadYmlReader(filename)
  48. if err != nil {
  49. return
  50. }
  51. y = &ConfigContainer{
  52. data: cnf,
  53. }
  54. return
  55. }
  56. // ParseData parse yaml data
  57. func (yaml *Config) ParseData(data []byte) (config.Configer, error) {
  58. cnf, err := parseYML(data)
  59. if err != nil {
  60. return nil, err
  61. }
  62. return &ConfigContainer{
  63. data: cnf,
  64. }, nil
  65. }
  66. // ReadYmlReader Read yaml file to map.
  67. // if json like, use json package, unless goyaml2 package.
  68. func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
  69. buf, err := ioutil.ReadFile(path)
  70. if err != nil {
  71. return
  72. }
  73. return parseYML(buf)
  74. }
  75. // parseYML parse yaml formatted []byte to map.
  76. func parseYML(buf []byte) (cnf map[string]interface{}, err error) {
  77. if len(buf) < 3 {
  78. return
  79. }
  80. if string(buf[0:1]) == "{" {
  81. log.Println("Look like a Json, try json umarshal")
  82. err = json.Unmarshal(buf, &cnf)
  83. if err == nil {
  84. log.Println("It is Json Map")
  85. return
  86. }
  87. }
  88. data, err := goyaml2.Read(bytes.NewBuffer(buf))
  89. if err != nil {
  90. log.Println("Goyaml2 ERR>", string(buf), err)
  91. return
  92. }
  93. if data == nil {
  94. log.Println("Goyaml2 output nil? Pls report bug\n" + string(buf))
  95. return
  96. }
  97. cnf, ok := data.(map[string]interface{})
  98. if !ok {
  99. log.Println("Not a Map? >> ", string(buf), data)
  100. cnf = nil
  101. }
  102. cnf = config.ExpandValueEnvForMap(cnf)
  103. return
  104. }
  105. // ConfigContainer A Config represents the yaml configuration.
  106. type ConfigContainer struct {
  107. data map[string]interface{}
  108. sync.Mutex
  109. }
  110. // Bool returns the boolean value for a given key.
  111. func (c *ConfigContainer) Bool(key string) (bool, error) {
  112. v, err := c.getData(key)
  113. if err != nil {
  114. return false, err
  115. }
  116. return config.ParseBool(v)
  117. }
  118. // DefaultBool return the bool value if has no error
  119. // otherwise return the defaultval
  120. func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
  121. v, err := c.Bool(key)
  122. if err != nil {
  123. return defaultval
  124. }
  125. return v
  126. }
  127. // Int returns the integer value for a given key.
  128. func (c *ConfigContainer) Int(key string) (int, error) {
  129. if v, err := c.getData(key); err != nil {
  130. return 0, err
  131. } else if vv, ok := v.(int); ok {
  132. return vv, nil
  133. } else if vv, ok := v.(int64); ok {
  134. return int(vv), nil
  135. }
  136. return 0, errors.New("not int value")
  137. }
  138. // DefaultInt returns the integer value for a given key.
  139. // if err != nil return defaltval
  140. func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
  141. v, err := c.Int(key)
  142. if err != nil {
  143. return defaultval
  144. }
  145. return v
  146. }
  147. // Int64 returns the int64 value for a given key.
  148. func (c *ConfigContainer) Int64(key string) (int64, error) {
  149. if v, err := c.getData(key); err != nil {
  150. return 0, err
  151. } else if vv, ok := v.(int64); ok {
  152. return vv, nil
  153. }
  154. return 0, errors.New("not bool value")
  155. }
  156. // DefaultInt64 returns the int64 value for a given key.
  157. // if err != nil return defaltval
  158. func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
  159. v, err := c.Int64(key)
  160. if err != nil {
  161. return defaultval
  162. }
  163. return v
  164. }
  165. // Float returns the float value for a given key.
  166. func (c *ConfigContainer) Float(key string) (float64, error) {
  167. if v, err := c.getData(key); err != nil {
  168. return 0.0, err
  169. } else if vv, ok := v.(float64); ok {
  170. return vv, nil
  171. } else if vv, ok := v.(int); ok {
  172. return float64(vv), nil
  173. } else if vv, ok := v.(int64); ok {
  174. return float64(vv), nil
  175. }
  176. return 0.0, errors.New("not float64 value")
  177. }
  178. // DefaultFloat returns the float64 value for a given key.
  179. // if err != nil return defaltval
  180. func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
  181. v, err := c.Float(key)
  182. if err != nil {
  183. return defaultval
  184. }
  185. return v
  186. }
  187. // String returns the string value for a given key.
  188. func (c *ConfigContainer) String(key string) string {
  189. if v, err := c.getData(key); err == nil {
  190. if vv, ok := v.(string); ok {
  191. return vv
  192. }
  193. }
  194. return ""
  195. }
  196. // DefaultString returns the string value for a given key.
  197. // if err != nil return defaltval
  198. func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
  199. v := c.String(key)
  200. if v == "" {
  201. return defaultval
  202. }
  203. return v
  204. }
  205. // Strings returns the []string value for a given key.
  206. func (c *ConfigContainer) Strings(key string) []string {
  207. v := c.String(key)
  208. if v == "" {
  209. return nil
  210. }
  211. return strings.Split(v, ";")
  212. }
  213. // DefaultStrings returns the []string value for a given key.
  214. // if err != nil return defaltval
  215. func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
  216. v := c.Strings(key)
  217. if v == nil {
  218. return defaultval
  219. }
  220. return v
  221. }
  222. // GetSection returns map for the given section
  223. func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
  224. if v, ok := c.data[section]; ok {
  225. return v.(map[string]string), nil
  226. }
  227. return nil, errors.New("not exist section")
  228. }
  229. // SaveConfigFile save the config into file
  230. func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
  231. // Write configuration file by filename.
  232. f, err := os.Create(filename)
  233. if err != nil {
  234. return err
  235. }
  236. defer f.Close()
  237. err = goyaml2.Write(f, c.data)
  238. return err
  239. }
  240. // Set writes a new value for key.
  241. func (c *ConfigContainer) Set(key, val string) error {
  242. c.Lock()
  243. defer c.Unlock()
  244. c.data[key] = val
  245. return nil
  246. }
  247. // DIY returns the raw value by a given key.
  248. func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
  249. return c.getData(key)
  250. }
  251. func (c *ConfigContainer) getData(key string) (interface{}, error) {
  252. if len(key) == 0 {
  253. return nil, errors.New("key is empty")
  254. }
  255. if v, ok := c.data[key]; ok {
  256. return v, nil
  257. }
  258. return nil, fmt.Errorf("not exist key %q", key)
  259. }
  260. func init() {
  261. config.Register("yaml", &Config{})
  262. }