sy process --help
sy-process
Merge JSON or YAML files from standard input from specified files. Multi-document YAML files are supported. Merging a
single file is explicitly valid and can be used to check for syntax errors.
USAGE:
sy process [FLAGS] [OPTIONS] [--] [path-or-value]...
FLAGS:
-h, --help Prints help information
--no-overwrite If set, values in the merged document may not overwrite values already present. This is
enabled by default,and can be explicitly turned off with --overwrite.
--no-stdin If set, we will not try to read structured data from standard input. This may be required in
some situations where we are blockingly reading from a standard input which is attached to a
pseudo-terminal.
--overwrite If set, values in the merged document can overwrite values already present. This is disabled
by default,and can be explicitly turned off with --no-overwrite.
OPTIONS:
-a, --at=<pointer>... Use a JSON pointer to specify an existing mapping at which the next merged value
should be placed. This affects only the next following --environment or <path>.
Valid specifications are for example '0/a/b/4' or 'a.b.0'. If it is specified last,
without a following merged value, the entire aggregated value so far is moved.
-e, --environment=<filter>... Import all environment variables matching the given filter. If no filter is set,
all variables are imported. Otherwise it is applied as a glob, e.g. 'FOO*' includes
'FOO_BAR', but not 'BAZ_BAR'.Other valid meta characters are '?' to find any
character, e.g. 'FO?' matches 'FOO'. [default: *]
-o, --output=<mode> Specifies how the merged result should be serialized. [default: json] [possible
values: json, yaml]
-s, --select=<pointer>... Use a JSON pointer to specify which sub-value to use. This affects only the next
following --environment or <path>. Valid specifications are for example '0/a/b/4'
or 'a.b.0', and they must point to a valid value. If it is specified last, without
a following merged value, a sub-value is selected from the aggregated value.
ARGS:
<path-or-value>... The path to the file to include, or '-' to read from standard input. It must be in a
format that can be output using the --output flag. Alternatively it can be a value
assignment like 'a=42' or a.b.c=value.
You can also use these aliases:
- merge
- show
It helps to use this powerful command by understanding its mindset a little.
- it wants to produce a single document (JSON or YAML) from multiple input documents (JSON or YAML)
- by default, it will refuse to overwrite existing values
- multi-document YAML files are fully supported
- standard input is a valid source for documents
- the order of arguments matter, as this program is implemented as state-machine
- by default it produces JSON output
This program helps to quickly manipulate various inputs and produce a new output, which can then
more easily be used in programs like sy substitute
, or to generate configuration files.
Now let's look typical use-cases.
Merge multiple documents into one
This case often arises by the mere necessity of keeping things separate. Even though keeping all data in a single structured data file would work just fine, in practice not all information is under your direct control and thus pulled in separately from other locations.
For substitution, multiple files are not viable, which is why a single file should be produced instead:
sy merge --at=project project.yml --at=team team.yml
{
"project": {
"kind": "ios-game",
"name": "super-punch"
},
"team": {
"name": "dept. nine",
"product-owner": "Max Owner"
}
}
As you can see, we use the --at
flag to put the contents of both files into their
own namespaces. Without that, we would have a clashing name
field which makes the
program fail.
sy merge project.yml team.yml
error: The merge failed due to conflicts
Caused by:
1: Refusing to merge due to the following clashing keys:
name
Overwriting individual values (or creating new ones)
Sometimes during testing, it's useful to change a single value, in the configuration
for instance. You can easily do this using the key=value
specification.
sy merge game-config.yml player.lives=99
error: The merge failed due to conflicts
Caused by:
1: Refusing to merge due to the following clashing keys:
player.lives
However, the above fails as we won't ever overwrite existing values. Let's try to argue with the program to make it work nonetheless:
sy merge game-config.yml player.lives=99 --overwrite
error: The merge failed due to conflicts
Caused by:
1: Refusing to merge due to the following clashing keys:
player.lives
This might appear unexpected, even though it is not when you have understood that the order
matters. In the example above, --overwrite
simply applies too late for overwriting the
value. If we swap their positions, it will work.
sy merge game-config.yml --overwrite player.lives=99 player.invincible=true
{
"enemies": {
"cheat": true,
"type": "aliens"
},
"player": {
"invincible": true,
"lives": 99
}
}
Please note that --overwrite
acts as a toggle and affects all following arguments. You can
toggle it back off with the --no-overwrite
flag
sy merge game-config.yml --overwrite player.lives=99 \
--no-overwrite --at=project project.yml --at=team team.yml \
-o yaml
---
enemies:
cheat: true
type: aliens
player:
lives: 99
project:
kind: ios-game
name: super-punch
team:
name: dept. nine
product-owner: Max Owner
Converting YAML to JSON (or vice versa)
As a side-effect, you can easily convert YAML to JSON, like so...
sy process < game-config.yml
{
"enemies": {
"cheat": true,
"type": "aliens"
},
"player": {
"lives": 3
}
}
...or the other way around:
sy process < game-config.yml | sy process -o yaml
---
enemies:
cheat: true
type: aliens
player:
lives: 3
Accessing to environment variables
More often than not, the environment contains information you will want to make use of in our configuration. It's easy to bring it into your data model, and filter them by their name.
sy process --environment=HO*
{
"HOME": "/root",
"HOSTNAME": "52170f35ed69"
}
Of course this can be combined with all other flags:
sy process --at env --environment=HO* env.NEW=value
{
"env": {
"HOME": "/root",
"HOSTNAME": "52170f35ed69",
"NEW": "value"
}
}
'Pulling up' values to allow general substitution
It's most common to have different sets of configuration for different environments. For example, most deploy to at least two stages: pre-production and production.
When using sy process
for generating configuration to be used by tooling, it's not practical to force
the tooling to know the stage.
Imagine the following configuration file:
cat multi-stage-config.yml
pre-production:
replicas: 1
max-cpu: 200mi
max-memory: 64M
production:
replicas: 3
max-cpu: 2000mi
max-memory: 1024M
Tools either get to know which stage configuration to use, or you 'pull it up' for them:
sy process --select=production multi-stage-config.yml -o yaml
---
max-cpu: 2000mi
max-memory: 1024M
replicas: 3
Using multi-document yaml documents as input
A feature that is still rare in the wild, probably due to lacking tool support, is multi-document YAML files.
We fully support them, but will merge them into a single document before processing it any further.
A file like this...
cat multi-document.yml
---
pre-production:
replicas: 1
max-memory: 64M
---
production:
replicas: 3
max-memory: 1024M
...looks like this when processing. Clashing keys will clash unless --overwrite
is set.
sy process multi-document.yml -o yaml
---
pre-production:
max-memory: 64M
replicas: 1
production:
max-memory: 1024M
replicas: 3
Controlling standard input
We will read JSON or YAML from standard input if possible. To make it more flexible, any non-path flags are applied to standard input. This may lead to unexpected output if more than one document source is specified.
Let's start with a simple case:
cat team.yml | sy process --at=team-from-stdin
{
"team-from-stdin": {
"name": "dept. nine",
"product-owner": "Max Owner"
}
}
In the moment another file is added for processing, it's a bit more difficult to control which argument applies where:
cat team.yml | sy process --at=team-from-stdin --at=project project.yml
{
"kind": "ios-game",
"name": "super-punch",
"project": {
"name": "dept. nine",
"product-owner": "Max Owner"
}
}
As you can see, the project
key is used for standard input, and the team-from-stdin
is seemingly ignored.
To fix this, be explicit to make obvious what you expect:
cat team.yml | sy process --at=team-from-stdin - --at=project project.yml
{
"project": {
"kind": "ios-game",
"name": "super-punch"
},
"team-from-stdin": {
"name": "dept. nine",
"product-owner": "Max Owner"
}
}
Note the single dash (-)
, which indicates when to read from standard input. As
standard input is always consumed entirely, it can only be specified once.