toml.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. package toml
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "runtime"
  9. "strings"
  10. )
  11. type tomlValue struct {
  12. value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
  13. comment string
  14. commented bool
  15. multiline bool
  16. literal bool
  17. position Position
  18. }
  19. // Tree is the result of the parsing of a TOML file.
  20. type Tree struct {
  21. values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
  22. comment string
  23. commented bool
  24. inline bool
  25. position Position
  26. }
  27. func newTree() *Tree {
  28. return newTreeWithPosition(Position{})
  29. }
  30. func newTreeWithPosition(pos Position) *Tree {
  31. return &Tree{
  32. values: make(map[string]interface{}),
  33. position: pos,
  34. }
  35. }
  36. // TreeFromMap initializes a new Tree object using the given map.
  37. func TreeFromMap(m map[string]interface{}) (*Tree, error) {
  38. result, err := toTree(m)
  39. if err != nil {
  40. return nil, err
  41. }
  42. return result.(*Tree), nil
  43. }
  44. // Position returns the position of the tree.
  45. func (t *Tree) Position() Position {
  46. return t.position
  47. }
  48. // Has returns a boolean indicating if the given key exists.
  49. func (t *Tree) Has(key string) bool {
  50. if key == "" {
  51. return false
  52. }
  53. return t.HasPath(strings.Split(key, "."))
  54. }
  55. // HasPath returns true if the given path of keys exists, false otherwise.
  56. func (t *Tree) HasPath(keys []string) bool {
  57. return t.GetPath(keys) != nil
  58. }
  59. // Keys returns the keys of the toplevel tree (does not recurse).
  60. func (t *Tree) Keys() []string {
  61. keys := make([]string, len(t.values))
  62. i := 0
  63. for k := range t.values {
  64. keys[i] = k
  65. i++
  66. }
  67. return keys
  68. }
  69. // Get the value at key in the Tree.
  70. // Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
  71. // If you need to retrieve non-bare keys, use GetPath.
  72. // Returns nil if the path does not exist in the tree.
  73. // If keys is of length zero, the current tree is returned.
  74. func (t *Tree) Get(key string) interface{} {
  75. if key == "" {
  76. return t
  77. }
  78. return t.GetPath(strings.Split(key, "."))
  79. }
  80. // GetPath returns the element in the tree indicated by 'keys'.
  81. // If keys is of length zero, the current tree is returned.
  82. func (t *Tree) GetPath(keys []string) interface{} {
  83. if len(keys) == 0 {
  84. return t
  85. }
  86. subtree := t
  87. for _, intermediateKey := range keys[:len(keys)-1] {
  88. value, exists := subtree.values[intermediateKey]
  89. if !exists {
  90. return nil
  91. }
  92. switch node := value.(type) {
  93. case *Tree:
  94. subtree = node
  95. case []*Tree:
  96. // go to most recent element
  97. if len(node) == 0 {
  98. return nil
  99. }
  100. subtree = node[len(node)-1]
  101. default:
  102. return nil // cannot navigate through other node types
  103. }
  104. }
  105. // branch based on final node type
  106. switch node := subtree.values[keys[len(keys)-1]].(type) {
  107. case *tomlValue:
  108. return node.value
  109. default:
  110. return node
  111. }
  112. }
  113. // GetArray returns the value at key in the Tree.
  114. // It returns []string, []int64, etc type if key has homogeneous lists
  115. // Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
  116. // Returns nil if the path does not exist in the tree.
  117. // If keys is of length zero, the current tree is returned.
  118. func (t *Tree) GetArray(key string) interface{} {
  119. if key == "" {
  120. return t
  121. }
  122. return t.GetArrayPath(strings.Split(key, "."))
  123. }
  124. // GetArrayPath returns the element in the tree indicated by 'keys'.
  125. // If keys is of length zero, the current tree is returned.
  126. func (t *Tree) GetArrayPath(keys []string) interface{} {
  127. if len(keys) == 0 {
  128. return t
  129. }
  130. subtree := t
  131. for _, intermediateKey := range keys[:len(keys)-1] {
  132. value, exists := subtree.values[intermediateKey]
  133. if !exists {
  134. return nil
  135. }
  136. switch node := value.(type) {
  137. case *Tree:
  138. subtree = node
  139. case []*Tree:
  140. // go to most recent element
  141. if len(node) == 0 {
  142. return nil
  143. }
  144. subtree = node[len(node)-1]
  145. default:
  146. return nil // cannot navigate through other node types
  147. }
  148. }
  149. // branch based on final node type
  150. switch node := subtree.values[keys[len(keys)-1]].(type) {
  151. case *tomlValue:
  152. switch n := node.value.(type) {
  153. case []interface{}:
  154. return getArray(n)
  155. default:
  156. return node.value
  157. }
  158. default:
  159. return node
  160. }
  161. }
  162. // if homogeneous array, then return slice type object over []interface{}
  163. func getArray(n []interface{}) interface{} {
  164. var s []string
  165. var i64 []int64
  166. var f64 []float64
  167. var bl []bool
  168. for _, value := range n {
  169. switch v := value.(type) {
  170. case string:
  171. s = append(s, v)
  172. case int64:
  173. i64 = append(i64, v)
  174. case float64:
  175. f64 = append(f64, v)
  176. case bool:
  177. bl = append(bl, v)
  178. default:
  179. return n
  180. }
  181. }
  182. if len(s) == len(n) {
  183. return s
  184. } else if len(i64) == len(n) {
  185. return i64
  186. } else if len(f64) == len(n) {
  187. return f64
  188. } else if len(bl) == len(n) {
  189. return bl
  190. }
  191. return n
  192. }
  193. // GetPosition returns the position of the given key.
  194. func (t *Tree) GetPosition(key string) Position {
  195. if key == "" {
  196. return t.position
  197. }
  198. return t.GetPositionPath(strings.Split(key, "."))
  199. }
  200. // SetPositionPath sets the position of element in the tree indicated by 'keys'.
  201. // If keys is of length zero, the current tree position is set.
  202. func (t *Tree) SetPositionPath(keys []string, pos Position) {
  203. if len(keys) == 0 {
  204. t.position = pos
  205. return
  206. }
  207. subtree := t
  208. for _, intermediateKey := range keys[:len(keys)-1] {
  209. value, exists := subtree.values[intermediateKey]
  210. if !exists {
  211. return
  212. }
  213. switch node := value.(type) {
  214. case *Tree:
  215. subtree = node
  216. case []*Tree:
  217. // go to most recent element
  218. if len(node) == 0 {
  219. return
  220. }
  221. subtree = node[len(node)-1]
  222. default:
  223. return
  224. }
  225. }
  226. // branch based on final node type
  227. switch node := subtree.values[keys[len(keys)-1]].(type) {
  228. case *tomlValue:
  229. node.position = pos
  230. return
  231. case *Tree:
  232. node.position = pos
  233. return
  234. case []*Tree:
  235. // go to most recent element
  236. if len(node) == 0 {
  237. return
  238. }
  239. node[len(node)-1].position = pos
  240. return
  241. }
  242. }
  243. // GetPositionPath returns the element in the tree indicated by 'keys'.
  244. // If keys is of length zero, the current tree is returned.
  245. func (t *Tree) GetPositionPath(keys []string) Position {
  246. if len(keys) == 0 {
  247. return t.position
  248. }
  249. subtree := t
  250. for _, intermediateKey := range keys[:len(keys)-1] {
  251. value, exists := subtree.values[intermediateKey]
  252. if !exists {
  253. return Position{0, 0}
  254. }
  255. switch node := value.(type) {
  256. case *Tree:
  257. subtree = node
  258. case []*Tree:
  259. // go to most recent element
  260. if len(node) == 0 {
  261. return Position{0, 0}
  262. }
  263. subtree = node[len(node)-1]
  264. default:
  265. return Position{0, 0}
  266. }
  267. }
  268. // branch based on final node type
  269. switch node := subtree.values[keys[len(keys)-1]].(type) {
  270. case *tomlValue:
  271. return node.position
  272. case *Tree:
  273. return node.position
  274. case []*Tree:
  275. // go to most recent element
  276. if len(node) == 0 {
  277. return Position{0, 0}
  278. }
  279. return node[len(node)-1].position
  280. default:
  281. return Position{0, 0}
  282. }
  283. }
  284. // GetDefault works like Get but with a default value
  285. func (t *Tree) GetDefault(key string, def interface{}) interface{} {
  286. val := t.Get(key)
  287. if val == nil {
  288. return def
  289. }
  290. return val
  291. }
  292. // SetOptions arguments are supplied to the SetWithOptions and SetPathWithOptions functions to modify marshalling behaviour.
  293. // The default values within the struct are valid default options.
  294. type SetOptions struct {
  295. Comment string
  296. Commented bool
  297. Multiline bool
  298. Literal bool
  299. }
  300. // SetWithOptions is the same as Set, but allows you to provide formatting
  301. // instructions to the key, that will be used by Marshal().
  302. func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) {
  303. t.SetPathWithOptions(strings.Split(key, "."), opts, value)
  304. }
  305. // SetPathWithOptions is the same as SetPath, but allows you to provide
  306. // formatting instructions to the key, that will be reused by Marshal().
  307. func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) {
  308. subtree := t
  309. for i, intermediateKey := range keys[:len(keys)-1] {
  310. nextTree, exists := subtree.values[intermediateKey]
  311. if !exists {
  312. nextTree = newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
  313. subtree.values[intermediateKey] = nextTree // add new element here
  314. }
  315. switch node := nextTree.(type) {
  316. case *Tree:
  317. subtree = node
  318. case []*Tree:
  319. // go to most recent element
  320. if len(node) == 0 {
  321. // create element if it does not exist
  322. node = append(node, newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col}))
  323. subtree.values[intermediateKey] = node
  324. }
  325. subtree = node[len(node)-1]
  326. }
  327. }
  328. var toInsert interface{}
  329. switch v := value.(type) {
  330. case *Tree:
  331. v.comment = opts.Comment
  332. v.commented = opts.Commented
  333. toInsert = value
  334. case []*Tree:
  335. for i := range v {
  336. v[i].commented = opts.Commented
  337. }
  338. toInsert = value
  339. case *tomlValue:
  340. v.comment = opts.Comment
  341. v.commented = opts.Commented
  342. v.multiline = opts.Multiline
  343. v.literal = opts.Literal
  344. toInsert = v
  345. default:
  346. toInsert = &tomlValue{value: value,
  347. comment: opts.Comment,
  348. commented: opts.Commented,
  349. multiline: opts.Multiline,
  350. literal: opts.Literal,
  351. position: Position{Line: subtree.position.Line + len(subtree.values) + 1, Col: subtree.position.Col}}
  352. }
  353. subtree.values[keys[len(keys)-1]] = toInsert
  354. }
  355. // Set an element in the tree.
  356. // Key is a dot-separated path (e.g. a.b.c).
  357. // Creates all necessary intermediate trees, if needed.
  358. func (t *Tree) Set(key string, value interface{}) {
  359. t.SetWithComment(key, "", false, value)
  360. }
  361. // SetWithComment is the same as Set, but allows you to provide comment
  362. // information to the key, that will be reused by Marshal().
  363. func (t *Tree) SetWithComment(key string, comment string, commented bool, value interface{}) {
  364. t.SetPathWithComment(strings.Split(key, "."), comment, commented, value)
  365. }
  366. // SetPath sets an element in the tree.
  367. // Keys is an array of path elements (e.g. {"a","b","c"}).
  368. // Creates all necessary intermediate trees, if needed.
  369. func (t *Tree) SetPath(keys []string, value interface{}) {
  370. t.SetPathWithComment(keys, "", false, value)
  371. }
  372. // SetPathWithComment is the same as SetPath, but allows you to provide comment
  373. // information to the key, that will be reused by Marshal().
  374. func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
  375. t.SetPathWithOptions(keys, SetOptions{Comment: comment, Commented: commented}, value)
  376. }
  377. // Delete removes a key from the tree.
  378. // Key is a dot-separated path (e.g. a.b.c).
  379. func (t *Tree) Delete(key string) error {
  380. keys, err := parseKey(key)
  381. if err != nil {
  382. return err
  383. }
  384. return t.DeletePath(keys)
  385. }
  386. // DeletePath removes a key from the tree.
  387. // Keys is an array of path elements (e.g. {"a","b","c"}).
  388. func (t *Tree) DeletePath(keys []string) error {
  389. keyLen := len(keys)
  390. if keyLen == 1 {
  391. delete(t.values, keys[0])
  392. return nil
  393. }
  394. tree := t.GetPath(keys[:keyLen-1])
  395. item := keys[keyLen-1]
  396. switch node := tree.(type) {
  397. case *Tree:
  398. delete(node.values, item)
  399. return nil
  400. }
  401. return errors.New("no such key to delete")
  402. }
  403. // createSubTree takes a tree and a key and create the necessary intermediate
  404. // subtrees to create a subtree at that point. In-place.
  405. //
  406. // e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b]
  407. // and tree[a][b][c]
  408. //
  409. // Returns nil on success, error object on failure
  410. func (t *Tree) createSubTree(keys []string, pos Position) error {
  411. subtree := t
  412. for i, intermediateKey := range keys {
  413. nextTree, exists := subtree.values[intermediateKey]
  414. if !exists {
  415. tree := newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
  416. tree.position = pos
  417. tree.inline = subtree.inline
  418. subtree.values[intermediateKey] = tree
  419. nextTree = tree
  420. }
  421. switch node := nextTree.(type) {
  422. case []*Tree:
  423. subtree = node[len(node)-1]
  424. case *Tree:
  425. subtree = node
  426. default:
  427. return fmt.Errorf("unknown type for path %s (%s): %T (%#v)",
  428. strings.Join(keys, "."), intermediateKey, nextTree, nextTree)
  429. }
  430. }
  431. return nil
  432. }
  433. // LoadBytes creates a Tree from a []byte.
  434. func LoadBytes(b []byte) (tree *Tree, err error) {
  435. defer func() {
  436. if r := recover(); r != nil {
  437. if _, ok := r.(runtime.Error); ok {
  438. panic(r)
  439. }
  440. err = errors.New(r.(string))
  441. }
  442. }()
  443. if len(b) >= 4 && (hasUTF32BigEndianBOM4(b) || hasUTF32LittleEndianBOM4(b)) {
  444. b = b[4:]
  445. } else if len(b) >= 3 && hasUTF8BOM3(b) {
  446. b = b[3:]
  447. } else if len(b) >= 2 && (hasUTF16BigEndianBOM2(b) || hasUTF16LittleEndianBOM2(b)) {
  448. b = b[2:]
  449. }
  450. tree = parseToml(lexToml(b))
  451. return
  452. }
  453. func hasUTF16BigEndianBOM2(b []byte) bool {
  454. return b[0] == 0xFE && b[1] == 0xFF
  455. }
  456. func hasUTF16LittleEndianBOM2(b []byte) bool {
  457. return b[0] == 0xFF && b[1] == 0xFE
  458. }
  459. func hasUTF8BOM3(b []byte) bool {
  460. return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
  461. }
  462. func hasUTF32BigEndianBOM4(b []byte) bool {
  463. return b[0] == 0x00 && b[1] == 0x00 && b[2] == 0xFE && b[3] == 0xFF
  464. }
  465. func hasUTF32LittleEndianBOM4(b []byte) bool {
  466. return b[0] == 0xFF && b[1] == 0xFE && b[2] == 0x00 && b[3] == 0x00
  467. }
  468. // LoadReader creates a Tree from any io.Reader.
  469. func LoadReader(reader io.Reader) (tree *Tree, err error) {
  470. inputBytes, err := ioutil.ReadAll(reader)
  471. if err != nil {
  472. return
  473. }
  474. tree, err = LoadBytes(inputBytes)
  475. return
  476. }
  477. // Load creates a Tree from a string.
  478. func Load(content string) (tree *Tree, err error) {
  479. return LoadBytes([]byte(content))
  480. }
  481. // LoadFile creates a Tree from a file.
  482. func LoadFile(path string) (tree *Tree, err error) {
  483. file, err := os.Open(path)
  484. if err != nil {
  485. return nil, err
  486. }
  487. defer file.Close()
  488. return LoadReader(file)
  489. }