2👍
✅
The task can be solved using jq.
The version is robust against settings that do not match a path in the document.
Variables
SETTINGS__APIS__PAYMENT__BASE_URL=https://example2.com
SETTINGS__AVAILABLELOCALES__0=cs
SETTINGS__UNAVAILABLE__PATH=1
Code
jq 'def settings:
def prepareVariables:
[$ENV | to_entries[] | select(.key | startswith("SETTINGS__"))] # select all variables that starts with "SETTINGS__"
| map(.key |= (. / "__" | map(tonumber? // .))[1:]); # convert variable names to path arrays
[paths(scalars) | [., map(ascii_upcase? // .)]] | # collect all leaf paths from input file and add uppercase path
reduce .[] as $leafPath # add leaf paths to corresponding settings
(prepareVariables; map(select($leafPath[1] == .key) |= . + {path: $leafPath[0]})) |
map(select(has("path"))); # drop settings for unknown paths
. as $input |
reduce settings[] as $setting # apply new settings from variables to input file
($input; . | setpath($setting["path"]; $setting["value"]))
' input.json
Output
{
"apis": {
"payment": {
"base_url": "https://example2.com"
},
"order": {
"base_url": "https://example.com/"
}
},
"features": {
"authentication": {
"authProviders": true,
"registration": false
}
},
"availableLocales": [
"cs",
"es"
]
}
2👍
I’m a jq
novice, and I’d be very interested in a better jq
script, but here’s one way to use environment variables to modify a settings.json
file.
$ cat settings.json
{
"apis": {
"payment": {
"base_url": "https://example.com/"
},
"order": {
"base_url": "https://example.com/"
}
},
"features": {
"authentication": {
"authProviders": true,
"registration": false
}
},
"availableLocales": [
"en",
"es"
]
}
$ printenv|grep SETTINGS__
SETTINGS__APIS__PAYMENT__BASE_URL=https://example2.com
SETTINGS__AVAILABLELOCALES__0=cs
$ jq -n '
inputs as $i
| [ $i
| ..
| keys_unsorted?
| .[]
| strings
]
| unique as $allKeys
|
def fixCase:
. as $w
| reduce ($allKeys[]|select(length == ($w|length))) as $k
("";. + $k|match($w;"i").string)
;
def envpaths:
[
$ENV
| to_entries[]
| select(.key | startswith("SETTINGS__"))
| [[ (.key|split("__"))[1:][]
| if test("^[0-9]+$") then tonumber else fixCase end
],
.value
]
]
;
reduce envpaths[] as $p ($i; .|setpath($p[0];$p[1]))' settings.json
# the output
{
"apis": {
"payment": {
"base_url": "https://example2.com"
},
"order": {
"base_url": "https://example.com/"
}
},
"features": {
"authentication": {
"authProviders": true,
"registration": false
}
},
"availableLocales": [
"cs",
"es"
]
}
See it work on jqplay.org.
Source:stackexchange.com