main.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package main
  2. import (
  3. "encoding/json"
  4. "flag"
  5. "log"
  6. "os"
  7. "path"
  8. "strconv"
  9. "time"
  10. "github.com/coreos/etcd/third_party/github.com/BurntSushi/toml"
  11. )
  12. func init() {
  13. log.SetFlags(0)
  14. flag.Usage = usage
  15. flag.Parse()
  16. }
  17. func usage() {
  18. log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0]))
  19. flag.PrintDefaults()
  20. os.Exit(1)
  21. }
  22. func main() {
  23. if flag.NArg() != 0 {
  24. flag.Usage()
  25. }
  26. var tmp interface{}
  27. if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil {
  28. log.Fatalf("Error decoding JSON: %s", err)
  29. }
  30. tomlData := translate(tmp)
  31. if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil {
  32. log.Fatalf("Error encoding TOML: %s", err)
  33. }
  34. }
  35. func translate(typedJson interface{}) interface{} {
  36. switch v := typedJson.(type) {
  37. case map[string]interface{}:
  38. if len(v) == 2 && in("type", v) && in("value", v) {
  39. return untag(v)
  40. }
  41. m := make(map[string]interface{}, len(v))
  42. for k, v2 := range v {
  43. m[k] = translate(v2)
  44. }
  45. return m
  46. case []interface{}:
  47. tabArray := make([]map[string]interface{}, len(v))
  48. for i := range v {
  49. if m, ok := translate(v[i]).(map[string]interface{}); ok {
  50. tabArray[i] = m
  51. } else {
  52. log.Fatalf("JSON arrays may only contain objects. This " +
  53. "corresponds to only tables being allowed in " +
  54. "TOML table arrays.")
  55. }
  56. }
  57. return tabArray
  58. }
  59. log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
  60. panic("unreachable")
  61. }
  62. func untag(typed map[string]interface{}) interface{} {
  63. t := typed["type"].(string)
  64. v := typed["value"]
  65. switch t {
  66. case "string":
  67. return v.(string)
  68. case "integer":
  69. v := v.(string)
  70. n, err := strconv.Atoi(v)
  71. if err != nil {
  72. log.Fatalf("Could not parse '%s' as integer: %s", v, err)
  73. }
  74. return n
  75. case "float":
  76. v := v.(string)
  77. f, err := strconv.ParseFloat(v, 64)
  78. if err != nil {
  79. log.Fatalf("Could not parse '%s' as float64: %s", v, err)
  80. }
  81. return f
  82. case "datetime":
  83. v := v.(string)
  84. t, err := time.Parse("2006-01-02T15:04:05Z", v)
  85. if err != nil {
  86. log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
  87. }
  88. return t
  89. case "bool":
  90. v := v.(string)
  91. switch v {
  92. case "true":
  93. return true
  94. case "false":
  95. return false
  96. }
  97. log.Fatalf("Could not parse '%s' as a boolean.", v)
  98. case "array":
  99. v := v.([]interface{})
  100. array := make([]interface{}, len(v))
  101. for i := range v {
  102. if m, ok := v[i].(map[string]interface{}); ok {
  103. array[i] = untag(m)
  104. } else {
  105. log.Fatalf("Arrays may only contain other arrays or "+
  106. "primitive values, but found a '%T'.", m)
  107. }
  108. }
  109. return array
  110. }
  111. log.Fatalf("Unrecognized tag type '%s'.", t)
  112. panic("unreachable")
  113. }
  114. func in(key string, m map[string]interface{}) bool {
  115. _, ok := m[key]
  116. return ok
  117. }