-
Notifications
You must be signed in to change notification settings - Fork 287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
encoding: missing support for toml #68
Comments
Original reply by @mpvl in cuelang/cue#68 (comment) I'm fine with TOML, being as common as it is, to be one of the few more configuration formats that's natively supported. At the moment, YAML, JSON, Go, Proto, and OpenAPI are higher on the list to complete support for, though. Note that generating TOML output should already not be too hard using the text/template builtin package. CUE has some limited support for time and date parsing through the time builtin package. It is high on the list to complete this support as part of the OpenAPI support effort. With this, a time field is indicated as:
where meetingTime is a string with the respective time format. I don't understand why arrays of tables are not just lists of values. It seems to be a special TOML notation that needs no special treatment in CUE. I do plan to add support for associative lists at some point, which would allow one to define different items of a list at different locations, though, sticking to CUE's associativity and commutativity properties, without any guarantee of order other than adhering to some topological sort. |
Is this feature request on the radar for getting some attention soon? Using text/template works in simple cases but can get out of hand pretty quickly. |
This is not currently a priority because there are aspects like package management that are higher priority. But we would very much welcome community contributions in this space. |
MVP in cue. import (
"strings"
"encoding/json"
)
cue: {
tables: {
global_tags: {
cluster: "foo"
environment?: string
}
agent: {
interval: "interval"
}
}
table_arrays: {
"inputs.prometheus": [
{
metric_version: 2
}, {
metric_version: 2
},
]
}
}
toml: strings.Join([ for table, kv in cue.tables {
strings.Join(["[\(table)]"]+[ for k, v in kv {"\(k) = \(json.Marshal(v))"}], "\n")
}]+[ for table, array in cue.table_arrays {
strings.Join([ for kv in array {
strings.Join(["[[\(table)]]"]+[ for k, v in kv {"\(k) = \(json.Marshal(v))"}], "\n")
}], "\n\n")
}], "\n\n") renders [global_tags]
cluster = "foo"
[agent]
interval = "interval"
[[inputs.prometheus]]
metric_version = 2
[[inputs.prometheus]]
metric_version = 2 https://cuelang.org/play/?id=YEIedqgEzNT#cue@export@cue Nesting tables are hard to implement and likely requires extension in cue. |
Multiple pieces are left to be done, such as tables with headers, comments, node positions, and error positions. However, this is already a significant enough amount of code and tests which can be reviewed and merged on its own. The Go API will remain experimental for the foreseeable future. We will hook up this encoding to cmd/cue and the standard library once it is more complete, particularly once we have an encoder. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I4daca2d0e34e60ef891233872ae978a5df0ebedd
Multiple pieces are left to be done, such as tables with headers, comments, node positions, and error positions. However, this is already a significant enough amount of code and tests which can be reviewed and merged on its own. The Go API will remain experimental for the foreseeable future. We will hook up this encoding to cmd/cue and the standard library once it is more complete, particularly once we have an encoder. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I4daca2d0e34e60ef891233872ae978a5df0ebedd
Multiple pieces are left to be done, such as tables with headers, comments, node positions, and error positions. However, this is already a significant enough amount of code and tests which can be reviewed and merged on its own. The Go API will remain experimental for the foreseeable future. We will hook up this encoding to cmd/cue and the standard library once it is more complete, particularly once we have an encoder. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I4daca2d0e34e60ef891233872ae978a5df0ebedd
Multiple pieces are left to be done, such as tables with headers, comments, node positions, and error positions. However, this is already a significant enough amount of code and tests which can be reviewed and merged on its own. The Go API will remain experimental for the foreseeable future. We will hook up this encoding to cmd/cue and the standard library once it is more complete, particularly once we have an encoder. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I4daca2d0e34e60ef891233872ae978a5df0ebedd Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1194508 Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Roger Peppe <[email protected]>
Given some input TOML, we can use our new encoding/toml.Decoder to obtain an ast.Node and then compile that to a cue.Value. Similarly, we can use go-toml's Unmarshal API on the same input TOML to obtain a Go value directly. Those two values should be equivalent, which we check via qt.JSONEquals. Two test cases fail this new check: the one involving duplicate keys, which is a known bug in our decoder, and the pair of tests involving empty TOML input, which we decoded as a CUE null. It seems like all TOML decoders decode empty input as an empty struct, and the TOML spec also hints that way as it allows empty tables which "simply have no key/value pairs within them". Moreover, since we create an ast.File, it seems best to leave it empty, which equals an empty struct, rather than add a "null" embedding. While here, add a TODO to remind myself to revisit literal decoding. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I83e34b939f1c2dd3b7928e14076f69c39e5054e0
And teach the tests about inputs which we expect to fail. `want` is now `wantCUE` for clarity; `wantErr` uses `qt.ErrorMatches`. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I2796a76faed01ed62c78145e257c8022efeb5ec3
Given some input TOML, we can use our new encoding/toml.Decoder to obtain an ast.Node and then compile that to a cue.Value. Similarly, we can use go-toml's Unmarshal API on the same input TOML to obtain a Go value directly. Those two values should be equivalent, which we check via qt.JSONEquals. Two test cases fail this new check: the one involving duplicate keys, which is a known bug in our decoder, and the pair of tests involving empty TOML input, which we decoded as a CUE null. It seems like all TOML decoders decode empty input as an empty struct, and the TOML spec also hints that way as it allows empty tables which "simply have no key/value pairs within them". Moreover, since we create an ast.File, it seems best to leave it empty, which equals an empty struct, rather than add a "null" embedding. While here, add a TODO to remind myself to revisit literal decoding. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I83e34b939f1c2dd3b7928e14076f69c39e5054e0
And teach the tests about inputs which we expect to fail. `want` is now `wantCUE` for clarity; `wantErr` uses `qt.ErrorMatches`. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I2796a76faed01ed62c78145e257c8022efeb5ec3
Given some input TOML, we can use our new encoding/toml.Decoder to obtain an ast.Node and then compile that to a cue.Value. Similarly, we can use go-toml's Unmarshal API on the same input TOML to obtain a Go value directly. Those two values should be equivalent, which we check via qt.JSONEquals. Two test cases fail this new check: the one involving duplicate keys, which is a known bug in our decoder, and the pair of tests involving empty TOML input, which we decoded as a CUE null. It seems like all TOML decoders decode empty input as an empty struct, and the TOML spec also hints that way as it allows empty tables which "simply have no key/value pairs within them". Moreover, since we create an ast.File, it seems best to leave it empty, which equals an empty struct, rather than add a "null" embedding. While here, add a TODO to remind myself to revisit literal decoding. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I83e34b939f1c2dd3b7928e14076f69c39e5054e0 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1194706 Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Roger Peppe <[email protected]>
And teach the tests about inputs which we expect to fail. `want` is now `wantCUE` for clarity; `wantErr` uses `qt.ErrorMatches`. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I2796a76faed01ed62c78145e257c8022efeb5ec3
And teach the tests about inputs which we expect to fail. `want` is now `wantCUE` for clarity; `wantErr` uses `qt.ErrorMatches`. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I2796a76faed01ed62c78145e257c8022efeb5ec3 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1194707 Reviewed-by: Roger Peppe <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
This is a significant amount of code given that there are effectively three ways in which table arrays can be used. First, declaring a new array and repeating its key like: [[foo]] leaf = "one" [[foo]] leaf = "two" resulting in appending to the same array: foo: [ {leaf: "one"}, {leaf: "two"}, ] Second, a table array can be created under an existing table: [foo] leaf = "one" [[foo.bar]] leaf = "two" resulting in: foo: { leaf: "one" bar: [ {leaf: "two"}, ] } Third, and perhaps most confusing, a table or table array can be created under an existing table array, adding to the table's last element: [[foo]] leaf = "one" [foo.bar] leaf = "two" [[foo.baz]] leaf = "three" resulting in: foo: [ { leaf: "one" bar: { leaf: "two" } baz: [ {leaf: "three"} ] }, } We add test cases for all of these edge cases, as well as test cases to ensure that unique keys are handled correctly, and that we reject declaring a key as both a table and an array table. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I2b483a67810b7c42ddf319a04a0f22724877b8a9
This is a significant amount of code given that there are effectively three ways in which table arrays can be used. First, declaring a new array and repeating its key like: [[foo]] leaf = "one" [[foo]] leaf = "two" resulting in appending to the same array: foo: [ {leaf: "one"}, {leaf: "two"}, ] Second, a table array can be created under an existing table: [foo] leaf = "one" [[foo.bar]] leaf = "two" resulting in: foo: { leaf: "one" bar: [ {leaf: "two"}, ] } Third, and perhaps most confusing, a table or table array can be created under an existing table array, adding to the table's last element: [[foo]] leaf = "one" [foo.bar] leaf = "two" [[foo.baz]] leaf = "three" resulting in: foo: [ { leaf: "one" bar: { leaf: "two" } baz: [ {leaf: "three"} ] }, } We add test cases for all of these edge cases, as well as test cases to ensure that unique keys are handled correctly, and that we reject declaring a key as both a table and an array table. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I2b483a67810b7c42ddf319a04a0f22724877b8a9
This is a significant amount of code given that there are effectively three ways in which table arrays can be used. First, declaring a new array and repeating its key like: [[foo]] leaf = "one" [[foo]] leaf = "two" resulting in appending to the same array: foo: [ {leaf: "one"}, {leaf: "two"}, ] Second, a table array can be created under an existing table: [foo] leaf = "one" [[foo.bar]] leaf = "two" resulting in: foo: { leaf: "one" bar: [ {leaf: "two"}, ] } Third, and perhaps most confusing, a table or table array can be created under an existing table array, adding to the table's last element: [[foo]] leaf = "one" [foo.bar] leaf = "two" [[foo.baz]] leaf = "three" resulting in: foo: [ { leaf: "one" bar: { leaf: "two" } baz: [ {leaf: "three"} ] }, } We add test cases for all of these edge cases, as well as test cases to ensure that unique keys are handled correctly, and that we reject declaring a key as both a table and an array table. Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I2b483a67810b7c42ddf319a04a0f22724877b8a9 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1195025 Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Aram Hăvărneanu <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
For now, all we test is that it can re-encode all the decoder test cases because it does not yet aim to keep any comments, style, order, or structure from the original CUE value. The go-toml library we use is not able to encode its AST nodes to TOML, so for now we encode as Go "any" values which drop that information. This will be resolved in the near future via an encoder that produces TOML syntax directly without going through an "any" phase first. For the time being, this basic encoder works, even if it produces unnecessarily verbose output such as [foo] [foo.bar] [foo.bar.'baz.zzz zzz'] one = '1' rather than the shorter [foo.bar.'baz.zzz zzz'] one = "1" Updates #68. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I5012bba77fb77b8bf1dd1d73615d34c3438cd147 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1198539 Reviewed-by: Roger Peppe <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
A TOML decoder and encoder are now in master and wired up to Given that initial support is now merged, we have closed this issue, but we have opened a number of others for follow-up tasks: |
Originally opened by @xinau in cuelang/cue#68
(Go) Tools like InfluxDB, GitLab CI (Runner), Traefik use TOML as their configuration language. Atm. CUE has no encoding support for TOML configuration files to be imported or exported. Since Go doesn't have native support for TOML, a third-party implementation needs to be imported as it's the case for YAML. Another thing to be aware of is that the native support for Date-Time, Date, Time values in TOML. Maybe this could be something CUE might want to support in the future as well. Also a mapping of array of tables to a appropriate CUE representation might be needed.
The text was updated successfully, but these errors were encountered: