-
-
Save crshnbrn66/850b1c963c6710b8f7042fc12689de64 to your computer and use it in GitHub Desktop.
use a json file for shell vars
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
CORTEX_CRYPTO="aes-256-cbc" | |
_cortex_logger() { printf '{%s}[%s](%s):%s\t%s\n' "$(date -u '+%FT%TZ')" "${1}" "$(caller)" "${2}" "${@:3}" 1>&2; } | |
_cortex_io() { | |
case "${CORTEX_FILE}" in | |
"") _cortex_logger "$(caller)" ERR "CORTEX_FILE environment variable is empty/unset" && return 127 ;; | |
*) | |
if [[ -v CORTEX_KEY ]]; then | |
case "${1}" in | |
load) openssl enc -"${CORTEX_CRYPTO}" -pass env:CORTEX_KEY -pbkdf2 -d -in "${CORTEX_FILE}" ;; | |
save) openssl enc -"${CORTEX_CRYPTO}" -pass env:CORTEX_KEY -pbkdf2 -e -out "${CORTEX_FILE}" ;; | |
test) touch "${CORTEX_FILE}" && [[ -s ${CORTEX_FILE} ]] ;; | |
esac | |
else | |
case "${1}" in | |
load) cat "${CORTEX_FILE}" ;; | |
save) cat >"${CORTEX_FILE}" ;; | |
test) touch "${CORTEX_FILE}" && [[ -s ${CORTEX_FILE} ]] ;; | |
*) return 127 ;; | |
esac | |
fi | |
;; | |
esac | |
} | |
_cortex_setup() { | |
declare -x CORTEX_FILE | |
if [[ -z ${CORTEX_FILE} ]]; then CORTEX_FILE=$(mktemp); fi | |
if ! _cortex_io test; then printf '{}' | _cortex_io save || { | |
_cortex_logger "$(caller)" ERR "cannot read/write ${CORTEX_FILE}, exiting" && return 2 | |
}; else | |
_cortex_logger "$(caller)" ERR "${CORTEX_FILE}, already exists and is not empty, exiting" | |
fi | |
} | |
_cortex_man() { | |
printf ' | |
[cortex] | |
jq wrapper for shell env values with file-based persistence | |
[cmd] [desc] [example] | |
export print key="value" for matched path cortex export .path.to.ipinfo | |
find find keys cortex find hostname | |
init initialize/reset json cortex init my-idenfitier | |
list list path cortex list .path.to.ipinfo | |
read read key cortex read path to ipinfo | |
rm remove keys cortex rm $(cortex find hostname) | |
write write value (${@:2} or stdin) to key ($1) curl ipinfo.io | cortex write .path.to.ipinfo | |
[opt] [desc] [example] | |
-f specify json target curl ipinfo.io | cortex -f /dev/stdin ls | |
-e (export mode only) type of export (array or full) cortex -e array export path to ipinfo | |
' 1>&2 | |
} | |
_cortex_jq_path() { | |
local _path _num | |
for i in "${@}"; do | |
_num=$(awk '{if ($1 == $1 + 0) print}' <<<"${i}") | |
case "${i}" in | |
"") continue ;; | |
"${_num}") printf -v _path '%s[%s]' "${_path}" "${_num}" ;; | |
*) printf -v _path '%s.%s' "${_path}" "${i}" ;; | |
esac | |
done | |
printf '%s' "${_path}" | |
} | |
_cortex_modify_json() { | |
local _json_val _jq_arg="arg" _verb="=" _v='$v' | |
if [[ -z ${1} ]]; then return 127; fi | |
local _key="${2}" | |
if [[ -z ${_key} ]]; then _cortex_logger "$(caller)" ERR "cannot set value with empty key" && return 127; fi | |
local _val="${3}" | |
if [[ -z ${_val} ]]; then | |
if [[ -t 0 ]]; then _cortex_logger "$(caller)" ERR "empty value and no readable input" && return 128; else | |
_val="$(tee)" | |
if [[ -z ${_val} ]]; then | |
_cortex_logger "$(caller)" ERR "empty value and no readable input" | |
return 128 | |
fi | |
fi | |
fi | |
if [[ ${1} == a* ]]; then _verb='+' _v='[$v]'; fi | |
_json_val=$(jq -cMrn --argjson v "${_val}" '{ v: $v } | .v' 2>/dev/null || true) | |
if [[ -n ${_json_val} ]]; then _jq_arg="argjson"; fi | |
case "${_key}" in | |
"") return 127 ;; | |
"."* | "["*) | |
case "${_json_val}" in | |
"null") jq -cM --arg k "${_key}" "del(${_key})" ;; | |
"") jq -cM --"${_jq_arg}" v "${_val}" "${_key} ${_verb} ${_v}" ;; | |
*) jq -cM --"${_jq_arg}" v "${_json_val}" "${_key} ${_verb} ${_v}" ;; | |
esac | |
;; | |
*) | |
case "${_json_val}" in | |
"null") jq -cM --arg k "${_key}" 'del(.[$k])' ;; | |
"") jq -cM --arg k "${_key}" --"${_jq_arg}" v "${_val}" ".[\$k] ${_verb} ${_v}" ;; | |
*) jq -cM --arg k "${_key}" --"${_jq_arg}" v "${_json_val}" ".[\$k] ${_verb} ${_v}" ;; | |
esac | |
;; | |
esac <<<"$(_cortex_io load || printf '{}')" | |
} | |
cortex() { | |
local OPTIND _dump _export_type | |
while getopts ":e:f:" _opt; do | |
case "${_opt}" in | |
e) _export_type="${OPTARG}" ;; | |
f) CORTEX_FILE="${OPTARG}" ;; | |
*) _cortex_man && return 127 ;; | |
esac | |
done | |
shift $((OPTIND - 1)) | |
case "${1}" in | |
"help" | h*) _cortex_man ;; | |
"export" | e*) | |
case "${_export_type}" in | |
"array" | a*) cortex get "${@:2}" | jq -cMr 'to_entries | map("[\(.key|@sh)]=\(.value|tostring|@sh)") | .[]' ;; | |
"full" | f*) cortex get "${@:2}" | jq -cMr 'paths(scalars) as $p | [([$p[]|tostring]|join("_")), (getpath($p)|tostring|@sh)] | join("=")' ;; | |
*) cortex get "${@:2}" | jq -cMr 'to_entries | map("\(.key)=\(.value|tostring|@sh)") | .[]' ;; | |
esac | |
;; | |
"find" | f*) | |
if [[ ${#@} -gt 1 ]]; then | |
_dump="$(_cortex_io load)" | |
for i in "${@:2}"; do | |
jq -cMr 'paths | select(.[-1] == "'"${i}"'") | @tsv' <<<"${_dump}" | while read -r line; do printf '%s\n' "$(_cortex_jq_path ${line})"; done | |
done | |
else | |
_cortex_io load | jq -cMr 'paths | @tsv' | while read -r line; do printf '%s\n' "$(_cortex_jq_path ${line})"; done | |
fi | |
;; | |
"init") | |
if _cortex_setup; then | |
jq -cMrn --arg id "${2:-"${0}"}" --arg ts "$(date -u '+%FT%TZ')" '{"id":$id,"timestamp":$ts}' | _cortex_io save | |
fi | |
;; | |
"list" | "ls" | l*) | |
case ${#@} in | |
1) _cortex_io load | jq -rS 'keys[]' ;; | |
2) | |
case "${2}" in | |
"") _cortex_logger "$(caller)" ERR "cannot list value with empty key" && return 127 ;; | |
"."* | "["*) _cortex_io load | jq -rS "${2} | keys[]" ;; | |
*) _cortex_io load | jq -rS --arg k "${2}" '.[$k] | keys[]' ;; | |
esac | |
;; | |
*) _cortex_io load | jq -cMrS "$(_cortex_jq_path "${@:2}") | keys[]" ;; | |
esac | |
;; | |
"read" | "get" | g*) | |
case ${#@} in | |
1) _cortex_io load | jq -cMrS . ;; | |
2) | |
case "${2}" in | |
"") _cortex_logger "$(caller)" ERR "cannot get value with empty key" && return 127 ;; | |
"."* | "["*) _cortex_io load | jq -cMrS "${2}" ;; | |
*) _cortex_io load | jq -cMrS --arg k "${2}" '.[$k]' ;; | |
esac | |
;; | |
*) _cortex_io load | jq -rcMS "$(_cortex_jq_path "${@:2}")" ;; | |
esac | |
;; | |
"rm") | |
case ${#@} in | |
1) _cortex_logger "$(caller)" ERR "must explicitly delete '.' to reset the entire json" && return 127 ;; | |
2) cortex set "${2}" null ;; | |
*) cortex set "$(_cortex_jq_path "${@:2}")" null ;; | |
esac | |
;; | |
"write" | w* | "set" | s*) | |
read -r -s _dump < <(_cortex_modify_json "${@}") | |
if [[ -n ${_dump} ]]; then _cortex_io save <<<"${_dump}"; else return $?; fi | |
;; | |
"") : ;; | |
*) _cortex_man && return 127 ;; | |
esac | |
} | |
_cortex_compgen() { | |
COMPREPLY=() | |
local cur subcommand i x _x | |
cur=${COMP_WORDS[COMP_CWORD]} | |
subcommand=$(cut -d ' ' -f "${COMP_CWORD}" <<<"${COMP_LINE}") | |
case "${subcommand}" in | |
"cortex" | "array" | "full") COMPREPLY=($(compgen -W "export find list ls read init get rm write set -e -f" -- "${cur}")) ;; | |
"-e") COMPREPLY=($(compgen -W "array full" -- "${cur}")) ;; | |
"-f") COMPREPLY=($(compgen -o plusdirs -f -- "${cur}")) ;; | |
"export" | "ls" | "list" | "read" | "get" | "rm" | "write" | "set") COMPREPLY=($(compgen -W "$(cortex list 2>/dev/null)" -- "${cur}")) ;; | |
*) | |
i=0 | |
while [[ ${i} -le ${COMP_CWORD} ]]; do | |
i=$((i + 1)) | |
case "${COMP_WORDS[@]: -i:1}" in | |
"cortex" | "array" | "full" | "-e" | "-f" | "export" | "ls" | "list" | "read" | "get" | "rm" | "write" | "set") | |
i=$((i - 1)) | |
break | |
;; | |
esac | |
_x=$(cortex list "${COMP_WORDS[@]: -i:i}" 2>/dev/null) | |
if [[ -n ${_x} ]]; then | |
COMPREPLY=($(compgen -W "${_x}" -- "${cur}")) | |
return | |
fi | |
done | |
x="${i}" | |
while [[ ${x} -ge 1 ]]; do | |
x=$((x - 1)) | |
_x=$(cortex list "${COMP_WORDS[@]: -i:x}" 2>/dev/null) | |
if [[ -n ${_x} ]]; then | |
COMPREPLY=($(compgen -W "${_x}" -- "${cur}")) | |
return | |
fi | |
done | |
COMPREPLY=($(compgen -W "export find list ls read init get rm write set -e -f" -- "${cur}")) | |
;; | |
esac | |
} | |
_cortex_setup | |
if (return 0 2>/dev/null); then | |
declare -xf _cortex_man _cortex_io _cortex_jq_path _cortex_logger _cortex_modify_json _cortex_setup _cortex_compgen cortex | |
complete -o filenames -F _cortex_compgen cortex | |
elif [[ ${#@} -gt 0 ]]; then | |
cortex "${@}" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment