-
-
Notifications
You must be signed in to change notification settings - Fork 23
yaml merge
The yaml-merge
command-line tool supports merging multiple YAML/Compatible
files together. It also enables writing arbitrary simple or complex data to a
YAML/Compatible document at any YAML Path, accepting such input from
STDIN (the -
pseudo-file), other compatible files, or both. The tool accepts
2 or more YAML_FILEs as input. Any one of them except the first (left-most)
can be the -
pseudo-file. Content is merged from the files, one at a time
from right-to-left, into the first file's content. This is known as "RHS into
LHS" merging (Right-Hand-Side content is merged into the Left-Hand-Side
document). No files are changed by this process; merging is performed entirely in
memory.
The yaml-merge
tool defaults to writing its merged results to STDOUT. In
order to direct the results to another file, you can set the --output
(-o
)
argument, or redirect output using the operators specific to your operating
system, like >
and >>
.
Not all merges are possible. There is no logical way to merge a Scalar or
Array into a Hash without specifying a key to receive the new data (say, by
using --mergeat
/-m
). Two documents with conflicting Anchors cannot be
merged unless you select one of the --anchors
(-a
) options other than
stop
(the default). When an impossible merge condition is met, the tool will
stop and emit an informative error message. Other conditions will be
coallesced, like merging a Hash or Scalar into an Array will result in merely
adding the new data as a new element of the Array.
With the --mergeat
(-m
) argument, you can direct all RHS content to one or
more LHS destinations indicated via YAML Path. This enables users to merge
together data fragments or even arbitrary data structure rather than premade,
otherwise complete documents. Specifying a YAML Path which matches zero nodes
however will result in an error message.
Document: LHS.yaml
---
deep:
hash:
structure:
key: value
There are a few ways to change value
to New Value
. You could just use the
yaml-set
command rather than yaml-merge
, like so:
yaml-set --change=/deep/hash/structure/key --value='New Value' LHS.yaml
But what if you don't want LHS.yaml to be modified, or you want the changed
document on STDOUT, say to feed into a subsequent piped command? This is where
yaml-merge
can help and there are multiple ways to solve these questions.
These include:
- Whole file merge where the RHS document contains the minimum data structure necessary to indicate where with the LHS document its data is to be merged.
- File fragment merge where only the desired RHS data is written and a
--mergeat
(-m
) indicates where within the LHS document this RHS data is to be merged. - CLI-supplied merge data where only the desired RHS data is fed to
yaml-merge
via STDIN and a--mergeat
(-m
) indicates where within the LHS document this RHS data is to be merged. The RHS data can be a proper YAML document, a proper JSON string, or a Python JSON-like string (without all the quoting of proper JSON).
The following sections demonstrate all three approaches.
You could create a complete RHS document as an entirely new YAML file, like this:
Document: RHS-FULL.yaml
---
deep:
hash:
structure:
key: New Value
To merge these two documents together, you'd simply execute:
yaml-merge LHS.yaml RHS-FULL.yaml
While this would generate the desired outcome, far more complex LHS structures could be not only tedious, but also error-prone to build up a sufficient RHS document to affect the desired alteration.
You could supply a document fragment for the RHS, like so:
Document: RHS-FRAGMENT.yaml
---
key: New Value
To merge the fragment into the whole, execute:
yaml-merge --mergeat=/deep/hash/structure LHS.yaml RHS-FRAGMENT.yaml
You could spare all versions of the RHS file and instead use STDIN to
emulate a yaml-set
call via yaml-merge
to get the same outcome:
echo 'New Value' | yaml-merge --mergeat=/deep/hash/structure/key LHS.yaml -
Notice that only the actual Scalar data was provided in this case because
for this example, we were only trying to change a single String value. You
could provide the key-value pair of the destination and shorten the merge
target path, like so:
echo '{key: New Value}' | yaml-merge --mergeat=/deep/hash/structure LHS.yaml -
And naturally, any amount of the RHS can be provided as long as the supplied YAML Path places it precisely where you want it to be merged. For example:
echo '{structure: {key: New Value}}' | \
yaml-merge --mergeat=/deep/hash LHS.yaml -`
And so on.