rcl patch¶
rcl patch [-i | --in-place] [--] [<file>] <path> <replacement>
Description¶
The patch
command edits an RCL document, to replace the expression identified by <path>
with the given <replacement>
. This can be used to make automation edit a configuration that is otherwise written by hand. This command formats the new document in standard style, like rcl format
would.
When <file>
is -
, this command reads from stdin. When no file is specified, the input defaults to stdin. In the default mode, the patched and formatted result is printed to stdout. With --output
the output can be written to a file instead, and with --in-place
, rcl patch
rewrites the input file.
Use good judgment when integrating rcl patch
into your automation: it may be simpler to import
separate files managed by automation, than to have a single file be managed by humans and automation. See also the alternatives below.
Example¶
Consider the file example.rcl
:
let app = { version = "1.33.7" };
app
The following command:
rcl patch --in-place example.rcl app.version '"1.42.0"'
Would rewrite the file to:
let app = { version = "1.42.0" };
app
Note that we use single quotes around the replacement value, to ensure that the shell passes "1.42.0"
to RCL, including the double quotes.
Options¶
--check
¶
Report whether the target file would be changed. If so, exit with exit code 1. When the patch operation is a no-op, and the file is already formatted correctly, exit with code 0.
This option is incompatible with --in-place
and --output
.
-i
--in-place
¶
Instead of printing to stdout, rewrite files in-place.
This option is incompatible with --check
and --output
.
-o
--output <outfile>
¶
Write the output to the given file instead of stdout. When --directory
is set, the output path is relative to that directory.
This option is incompatible with --check
and --in-place
.
-w
--width <width>
¶
Target width in columns for formatting. Must be an integer. Defaults to 80. Note that the formatter is not always able to stay within the desired width limit.
Path matching¶
The path identifies the place in the document to patch. It consists of a list of identifiers separated by dots. Every identifier can match either:
- A let-binding.
- A key in a dictionary, when that key is using record form, i.e.
key = value
rather than"key": value
.
Matching is greedy: when an identifier matches, we try to match the remainder of the path inside the matching expression. If that fails, that’s an error, even if the path could still match later in the document.
Let’s look at an artificial example:
let alpha = {
let bravo = {
charlie = 1,
"delta": 2,
};
echo = 3,
};
{
alpha = { bravo = { foxtrot = 4 } },
zulu = alpha,
}
In this document, we can match the following paths:
alpha.bravo.charlie
matches 1
: alpha
and bravo
match the first two let-bindings, while charlie
matches the dict key.
alpha.bravo.delta
does not match: we can only match dict keys that use record notation, but "delta"
is using json form.
alpha.bravo.foxtrot
does not match: matching is greedy, so alpha
and bravo
match the first two let-bindings, and inside the matching dict, there is no key foxtrot
.
zulu
matches the final dict entry.
zulu.echo
does not match: patching acts on the syntax tree, before any evaluation.
While these limitations mean that paths cannot reference arbitrary locations in an RCL document, it is always possible introduce a let-binding earlier in the document, that can be matched.
Use cases and alternatives¶
The goal of rcl patch
is to enable automation to edit files that are primarily maintained by humans. For example, to bump a version number, or to update a pinned commit hash. RCL already features a more general way to enable automation to update a configuration: write the automation-managed parts to separate files, and import them with import
or std.read_file_utf8
. Automation can rewrite those entire files, which is simpler than safely editing a syntax tree. The downside though, is that this may create a sprawl of files, which can make it difficult to understand the configuration at a glance. For those cases, rcl patch
can be a solution.
A more general approach to patching files, is of course sed
. rcl patch
is safer, because it operates on syntax trees rather than text streams. It can locate the value to edit by path rather than regex, it can edit values that span multiple lines, and in general it ensures that the output is syntactically valid, which sed
cannot guarantee.