Templating features
Some useful templating features are provided when writing configuration files such as :
- Workspace configuration file
- Project configuration files
Basic string interpolation​
All strings can contain interpolated data, whether you are using pure JSON, YAML or Jsonnet :
{
"targets": {
"print-message": {
"executor": "std:commands",
"options": {
"commands": [
{
"program": "echo",
"arguments": ["{{ vars.message }}"]
}
]
}
}
}
}
This print-message target will print the value contained in the vars.message custom variable.
The vars prefix indicates that you want to interpolate a custom variable.
Global variables​
These variables are always available (in both workspace and project configuration files) :
| Path | Description | Example |
|---|---|---|
root | The workspace root directory, as an absolute path. | |
environment.* | The current process environment variables (after loading all .env files). | |
architecture | The current platform architecture. Possible values are listed here. | |
family | The operating system family. Can be either unix or windows. | |
os | The specific current operating system. Possible values are listed here. | |
user | The current user name. | |
hostname | The current machine hostname. This variable can be unset in some cases. | |
sep | Filesystem path component separator for the current platform | |
Dynamic configuration​
Sometimes, you need more than just interpolating strings, for example :
- If you want your configuration file to have a dynamic structure
- If you want to pass a variable of any type outside of a string literal, without the
{{ }}syntax.
When using Jsonnet, all variables are imported through the external variable blaze when compiling your template.
For example, if we need to have different arguments according to the current OS for a command launched through the std:commands executor :
{
local blaze = std.extVar('blaze'),
targets: {
clean: {
executor: 'std:commands',
options: {
commands: if blaze.family == "unix"
then [
{
program: 'rm',
arguments: ['-rf', 'dist']
},
] else [
{
program: 'del',
arguments: ['dist']
}
]
}
}
}
}
Jsonnet libraries​
A good way to refactor your configurations is to create Jsonnet libraries.
They usually are made of .libsonnet files that you can import inside your configuration files.
It can be quite difficult to deal with relative paths imports.
You can easily add Jsonnet library paths by creating a .blaze/.jpath file (if it does not already exist).
Let's say we have a helper.libsonnet file in our library path.
├── libs/
| ├── jsonnet/
| | ├── helper.libsonnet
We need to provide our libraries' parent directory in our .blaze/.jpath.
Directories must be provided line per line.
Relative paths are analyzed from the workspace root directory. Absolute paths are also supported, but not recommended. Non-existent paths will be silently ignored.
If we add the following line to our .jpath file, direct import using import 'helper.libsonnet' should work in Jsonnet files :
libs/jsonnet/
Templating helpers​
Blaze templating system uses Handlebars under the hood.
Standard Handlebars helpers​
All the standard helpers are available.
These helpers include if/else conditions, loops, debugging utilities and more...
Blaze built-in helpers​
Blaze also provides two useful helpers :
- The
shellhelper, for interpolating any system command output. - The
randomhelper, for interpolating random string of arbitrary size.
The shell helper​
Basic usage is as follows :
"{{ shell \"whoami\" trim=true }}"
This will print the result of the whoami command. The trim parameter is here to remove any trailing whitespace at the end of the command output.
The shell helper always run commands in a shell. You can also customize the shell path and kind, just like the std:commands executor.
"{{ shell \"whoami\" shell=\"/bin/bash\" shellKind=\"Posix\" trim=true }}"
By default, commands provided to the shell helper run at the workspace root. You can customize this location by providing a cwd parameter.
// this will output /tmp
"{{ shell \"pwd\" cwd=\"/tmp\" }}"
The random helper​
Basic usage is as follows :
"{{ random 16 }}"
This will interpolate a random alphanumerical string of length 16, like this :
a514Snw21Rf59JpC
The generation is done through rand::rngs::ThreadRng.
A new value will be generated everytime the file is parsed, so be careful since this might cause unwanted cache invalidation.
Custom template helpers​
You can create your own helpers in the form of rhai scripts.
Create a script file in .blaze/helpers :
+-- .blaze
+-- helpers
+-- my-uppercase.rhai
The script filenames must match the following regular expression in order to be picked up by Blaze : ^[a-zA-Z0-9\-_]\.rhai$.
We can then write the script code, in this example we simply take the first indexed parameter that is given to the helper and make it uppercase, assuming it is a string.
let input = params[0];
input.make_uppercase();
input
Finally we can use the helper anywhere in a template string.
"{{ my-uppercase \"Hello world!\" }}"
The interpolated value will then be: HELLO WORLD!.
Handlebars helpers support both indexed and hash (named) parameters.
- Indexed parameters are accessed using the
paramsvariable. - Hash (named) parameters are accessed using the
hashvariable.
Custom variables​
You can store custom variables at the workspace root, in a global file called .blaze/variables.json.
{
"vars": {
"message": "Hello world!",
"some": {
"nested": {
"variable": 1
}
},
"some-values": [1, 2, 3]
}
}
This configuration file also supports Jsonnet and YAML.
Extra variable files​
You can add also add extra files paths with the include key, This can be useful if you want to have non-versioned, user-provided variables :
{
"vars": {
"my-message": "Hello world!"
},
"include": [
"{{ root }}/user-variables.json"
]
}
{
"my-message": "What's up world?"
}
In this example, the variable named my-message will be overriden with a new value What's up world?.
Relative paths will be analyzed from the .blaze directory. Absolute paths are also supported.
Missing files will be considered as an error. If you want any of these files to be optional, you can use the following syntax :
{
"vars": {
"global-var": "Hello world!"
},
"include": [
{
"path": "{{ root }}/optional-user-variables.json",
"optional": true
}
]
}
These extra configuration file also supports Jsonnet and YAML.
Variables overriding order​
This is the order in which variables are being analyzed and might override the previous ones :
- Global variables declared at the
varskey of.blaze/variables.json - Extra file declared at the
includekey of.blaze/variables.json(in the order of declaration) - User provided variables files through the
--vars-filecommand line option. - User provided variables through the
--json-var,--jsonnet-var,yaml-varcommand line options. - User provided variables through the
--str-varcommand line option.
Overriding is done using JSON Merge Patch
If you override variables with a non-object value, it will completely replace the previous state.
Be careful when using YAML since an empty file will be deserialized as null. Use an empty object notation {} instead.