I have the following json file named CMakePresets.json
that is a cmake-preset file:
{
"configurePresets": [
{
"name": "default",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/_build/${presetName}",
"cacheVariables": {
"YIO_DEV": "1",
"BUILD_TESTING": "1"
}
},
{
"name": "debug",
"inherits": "default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"inherits": "default",
"binaryDir": "${sourceDir}/_build/Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "arm",
"inherits": "debug",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/Toolchain/arm-none-eabi-gcc.cmake"
}
}
]
}
I want recursively merge with *
the configurePresets
elements that inherit themselves for a specific entry name
. I have example a node with name arm
and want to have resulting json object with resolved inheritance. The parent has the name stored inside .inherits
of each element. arm
inherits over debug
which inherits over default
.
I could write a bash shell loop that I believe works, with the help of Remove a key:value from an JSON object using jq and this answer:
input=arm
# extract one element
g() { jq --arg name "$1" '.configurePresets[] | select(.name == $name)' CMakePresets.json; };
# get arm element
acc=$(g "$input");
# If .inherits field exists
while i=$(<<<"$acc" jq -r .inherits) && [[ -n "$i" && "$i" != "null" ]]; do
# remove it from input
a=$(<<<"$acc" jq 'del(.inherits)');
# get parent element
b=$(g "$i");
# merge parent with current
acc=$(printf "%s\n" "$b" "$a" | jq -s 'reduce .[] as $item ({}; . * $item)');
done;
echo "$acc"
outputs, which I believe is the expected output for arm
:
{
"name": "arm",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/_build/${presetName}",
"cacheVariables": {
"YIO_DEV": "1",
"BUILD_TESTING": "1",
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/Toolchain/arm-none-eabi-gcc.cmake"
}
}
But I want to write it in jq
. I tried and jq
language is not intuitive for me. I can do it for example for two (ie. countable) elements:
< CMakePresets.json jq --arg name "arm" '
def g(n): .configurePresets[] | select(.name == n);
g($name) * (g($name) | .inherits) as $name2 | g($name2)
'
But I do not know how to do reduce .[] as $item ({}; . * $item)
when the $item
is really g($name)
that depends on the last g($name) | .inherits
. I tried reading jq manual and learning about variables and loops, but jq
has a very different syntax. I tried to use while
, but that's just syntax error that I do not understand and do not know how to fix. I guess while
and until
might not be right here, as they operate on previous loop output, while the elements are always from root.
$ < CMakePresets.json jq --arg name "arm" 'def g(n): .configurePresets[] | select(.name == n);
while(g($name) | .inherits as $name; g($name))
'
jq: error: syntax error, unexpected ';', expecting '|' (Unix shell quoting issues?) at <top-level>, line 2:
while(g($name) | .inherits as $name; g($name))
jq: 1 compile error
How to write such loop in jq
language?
input[] | select(.name == n)
vs having a lookup table; (b) in jq it is generally preferable to avoid having functions of arity greater than 0 calling themselves directly. – Dosia