util.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package coreutil
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "reflect"
  9. "strconv"
  10. "strings"
  11. "github.com/go-yaml/yaml"
  12. )
  13. // ParseConfig, reads yaml or json file into a struct
  14. func ParseConfig(srcfile string, out interface{}) (err error) {
  15. if srcfile == "" {
  16. return
  17. }
  18. f, err := os.Open(srcfile)
  19. if err != nil {
  20. return err
  21. }
  22. defer f.Close()
  23. if strings.HasSuffix(srcfile, ".json") {
  24. // Read as JSON
  25. json.NewDecoder(f).Decode(out)
  26. return
  27. }
  28. if strings.HasSuffix(srcfile, ".yaml") {
  29. data, err := ioutil.ReadAll(f)
  30. if err != nil {
  31. return err
  32. }
  33. // Read as yaml
  34. yaml.Unmarshal(data, out)
  35. }
  36. return err
  37. }
  38. func SaveConfig(name string, obj interface{}) (err error) {
  39. var data []byte
  40. if strings.HasSuffix(name, ".json") {
  41. data, err = json.MarshalIndent(obj, " ", " ")
  42. if err != nil {
  43. return err
  44. }
  45. }
  46. if strings.HasSuffix(name, ".yaml") {
  47. data, err = yaml.Marshal(obj)
  48. if err != nil {
  49. return err
  50. }
  51. }
  52. f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
  53. if err != nil {
  54. log.Fatalf("Unable to save config: %v\n", err)
  55. }
  56. defer f.Close()
  57. f.Write(data)
  58. f.Sync()
  59. return err
  60. }
  61. // ParseOptions parses mount options like -o uid=100,gid=100 to struct
  62. func ParseOptions(opt string, out interface{}) (err error) {
  63. mountopts := map[string]string{}
  64. parts := strings.Split(opt, ",")
  65. // First Map to keyvalue
  66. for _, v := range parts {
  67. if keyindex := strings.Index(v, "="); keyindex != -1 { // Eq
  68. key := strings.TrimSpace(v[:keyindex])
  69. value := strings.TrimSpace(v[keyindex+1:])
  70. mountopts[key] = value
  71. } else {
  72. mountopts[v] = "true"
  73. }
  74. }
  75. // Assign map to object by Tag by iterating fields
  76. typ := reflect.TypeOf(out).Elem() // Should be pointer
  77. val := reflect.ValueOf(out).Elem()
  78. for i := 0; i < typ.NumField(); i++ {
  79. fieldTyp := typ.Field(i)
  80. fieldVal := val.Field(i)
  81. name := strings.ToLower(fieldTyp.Name)
  82. if tag, ok := fieldTyp.Tag.Lookup("opt"); ok {
  83. tagParts := strings.Split(tag, ",")
  84. if len(tagParts) > 0 && tagParts[0] != "" {
  85. name = tagParts[0]
  86. }
  87. }
  88. if v, ok := mountopts[name]; ok {
  89. err = StringAssign(v, fieldVal.Addr().Interface())
  90. if err != nil {
  91. return err
  92. }
  93. }
  94. }
  95. return
  96. }
  97. // StringAssign parseString and place value in
  98. func StringAssign(s string, v interface{}) (err error) {
  99. val := reflect.ValueOf(v).Elem()
  100. switch val.Kind() {
  101. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: // More values
  102. parsed, err := strconv.ParseInt(s, 10, 64)
  103. if err != nil {
  104. return err
  105. }
  106. sval := reflect.ValueOf(parsed)
  107. val.Set(sval.Convert(val.Type()))
  108. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: // More values
  109. parsed, err := strconv.ParseUint(s, 10, 64)
  110. if err != nil {
  111. return err
  112. }
  113. sval := reflect.ValueOf(parsed)
  114. val.Set(sval.Convert(val.Type()))
  115. case reflect.Bool:
  116. parsed, err := strconv.ParseBool(s)
  117. if err != nil {
  118. return err
  119. }
  120. sval := reflect.ValueOf(parsed)
  121. val.Set(sval)
  122. }
  123. return
  124. }
  125. func OptionString(o interface{}) string {
  126. ret := ""
  127. typ := reflect.TypeOf(o) // Should be pointer
  128. val := reflect.ValueOf(o)
  129. for i := 0; i < typ.NumField(); i++ {
  130. fieldTyp := typ.Field(i)
  131. fieldVal := val.Field(i)
  132. name := strings.ToLower(fieldTyp.Name)
  133. desc := ""
  134. if tag, ok := fieldTyp.Tag.Lookup("opt"); ok {
  135. tagParts := strings.Split(tag, ",")
  136. if len(tagParts) > 0 && tagParts[0] != "" {
  137. name = tagParts[0]
  138. }
  139. /*if len(tagParts) >= 2 {
  140. desc = tagParts[1]
  141. }*/
  142. }
  143. if i != 0 {
  144. ret += ","
  145. }
  146. if desc != "" {
  147. ret += fmt.Sprintf("%s=%v (%s)", name, fieldVal.Interface(), desc)
  148. } else {
  149. ret += fmt.Sprintf("%s=%v", name, fieldVal.Interface())
  150. }
  151. }
  152. return ret
  153. }
  154. func OptionMap(o interface{}) map[string]string {
  155. ret := map[string]string{}
  156. typ := reflect.TypeOf(o) // Should be pointer
  157. val := reflect.ValueOf(o)
  158. for i := 0; i < typ.NumField(); i++ {
  159. fieldTyp := typ.Field(i)
  160. fieldVal := val.Field(i)
  161. name := strings.ToLower(fieldTyp.Name)
  162. if tag, ok := fieldTyp.Tag.Lookup("opt"); ok {
  163. tagParts := strings.Split(tag, ",")
  164. if len(tagParts) > 0 && tagParts[0] != "" {
  165. name = tagParts[0]
  166. }
  167. }
  168. ret[name] = fmt.Sprintf("%v", fieldVal.Interface())
  169. }
  170. return ret
  171. }