Intro
Some of the nice guys that gave Docker to the world have moved on into a new project for automating CI/CD called dagger.io: this new product starts from nice assumptions and all the experience from the previous project, absolutely interesting indeed. What we are going to peak here is the language at the base of Dagger: CUE, to which I have taken a peak recently.
What is CUE
From the CUE language homepage:
CUE is an open source language, with a rich set of APIs and tooling, for defining, generating, and validating all kinds of data: configuration, APIs, database schemas, code, … you name it.
CUE is a superset of JSON specializing in "Validate, define, and use dynamic and text-based data". This means that all the serialization fans can find this useful: JSON follower, YAML prayers, ProtoBuf believers can give it a try to the language and see what is can do to make more solid their configuration files.
Install GO and CUE
CUE is a CLI tool written in Golang and can be installed as a library for your Golang installation as stated in the minimal documentation:
# install as a library
$ go install cuelang.org/go/cmd/cue@latest
# install as CLI
$ git clone git@github.com:cue-lang/cue.git && cd cue && go get cuelang.org/go/cue
(ensure that your $HOME/go/bin directory is in your path).
Try your installation:
$ cue --help
The declarative power
The main point of CUE is to provide powerful schema definition and serialization to different format via a declarative language, let's see an example with mixed data (string, numbers, collections):
// save this content to a namefile.cue file
// you can declare a generic structure to define your map
nameyourmap: data: "point.json":{ x: 4.5, y: 2.34 }
nameyourmap: yaml_string: """
one: this_is_yaml
two: this_is_also_yaml
"""
nameyourmap:this_is_list: [1, 2, 3.5]
This is a generic CUE file that can be serialized into text formats:
# generate text file from code
$ cue export namefile.cue
{
"nameyourmap": {
"data": {
"point.json": {
"x": 4.5,
"y": 2.34
}
}
}
}
Or:
$ cue export namefile.cue
{
"nameyourmap": {
"data": {
"point.json": {
"x": 4.5,
"y": 2.34
}
},
"yaml_string": "one: this_is_yaml\ntwo: this_is_also_yaml",
"list": [
1,
2,
3.5
]
}
}
This is already great as we can easily write scripts to create large configuration files, inject values or even entire files in the position where it is needed.
We can also see three of the basic characteristics of CUE syntax:
- inline, easy to read
- multiple declarations add new fields
- fields cannot be accidentally over-written (try to add
nameyourmap:this_is_list: [1, 2, 3.5, 4.5]
to the end of the file and you will see an error)
Marshal/Unmarshal formats
In the previous example we had two critical points, at lines 4 and 5 we defined two structure for the fields point.json
and yaml_string
. How is it possible to have two different formats in the same declaration? That is one of the best feature up to now, as strings can be imported from different formats leveraging the right functions:
// save this content to a test1.cue file
// you can declare a generic structure to define your map
nameyourmap: data: "point.json":{ x: 4.5, y: 2.34 }
nameyourmap: yaml_structure: yaml.Unmarshal("""
one: this_is_yaml
two: this_is_also_yaml
""")
nameyourmap:this_is_list: [1, 2, 3.5]
Let's run the code:
$ cue export test1.cue
{
"nameyourmap": {
"data": {
"point.json": {
"x": 4.5,
"y": 2.34
}
},
"yaml_structure": { <<<
"one": "this_is_yaml",
"two": "this_is_also_yaml"
},
"this_is_list": [
1,
2,
3.5
]
}
}
As you can see now the YAML field is not a string anymore but a map defined from the YAML string.
That is all for now. CUE has other superpowers:
- Data Validation
- Schema Definition
- Code Generation and Extraction
- Querying
- Scripting
You can find some explanations in the documentation.
Dagger is built on CUE to provide building CI/CD pipelines quickly and run them anywhere.
If you liked this post please ❤️ and I will consider going on with this walk-through.
Top comments (0)