From 7f3ff45f0504d45e204fa4ef27bc72da4522b9da Mon Sep 17 00:00:00 2001 From: Aditya Gupta Date: Fri, 26 Jun 2026 18:19:23 +0530 Subject: [PATCH] refactor: Use jq instead of custom posix complient json.sh While json.sh worked decently for reading json files, I didn't want to implement writing to json files as well and make it completely unreadable due to the added complexity. So, I think its better to just use jq and keep things relatively simple with the tradeoff of a lightweight dependency --- bootstrap.sh | 8 +++-- installers/install_agy.sh | 13 ++------ lib/json.sh | 68 --------------------------------------- lib/plugins.sh | 51 ++++------------------------- 4 files changed, 16 insertions(+), 124 deletions(-) delete mode 100644 lib/json.sh diff --git a/bootstrap.sh b/bootstrap.sh index 8aac6c8..26c6d0c 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -41,7 +41,7 @@ else BOOTSTRAP_SOURCE_DIR="$BOOTSTRAP_TMP_DIR" _BASE_URL="https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master" - _LIBS=("lib/common.sh" "lib/rollback.sh" "lib/platform.sh" "lib/shell_config.sh" "lib/json.sh" "lib/plugins.sh") + _LIBS=("lib/common.sh" "lib/rollback.sh" "lib/platform.sh" "lib/shell_config.sh" "lib/plugins.sh") _curl_args=() for _lib in "${_LIBS[@]}"; do @@ -82,7 +82,6 @@ install_bootstrap() { "lib/rollback.sh" "lib/platform.sh" "lib/shell_config.sh" - "lib/json.sh" "lib/plugins.sh" "commands/help.sh" "commands/con.sh" @@ -90,6 +89,11 @@ install_bootstrap() { "commands/up.sh" ) + if ! pkg_check jq >/dev/null 2>&1; then + log_info "jq is missing. Installing jq..." + pkg_install jq + fi + if [ -f "$_SCRIPT_DIR/b.sh" ] && [ -f "$_SCRIPT_DIR/lib/routes.sh" ]; then log_info "Using local files from repository..." for file in "${files[@]}"; do diff --git a/installers/install_agy.sh b/installers/install_agy.sh index 4ee8aab..8eef314 100644 --- a/installers/install_agy.sh +++ b/installers/install_agy.sh @@ -55,19 +55,12 @@ install_agy() { exit 1 fi - # POSIX-compliant JSON parser (no jq dependencies) - parse_json_key() { - local payload="$1" - local key="$2" - echo "$payload" | sed -n 's/.*"'"$key"'"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' - } - local version local url local sha512 - version=$(parse_json_key "$manifest_json" "version") - url=$(parse_json_key "$manifest_json" "url") - sha512=$(parse_json_key "$manifest_json" "sha512") + version=$(echo "$manifest_json" | jq -r '.version // empty') + url=$(echo "$manifest_json" | jq -r '.url // empty') + sha512=$(echo "$manifest_json" | jq -r '.sha512 // empty') if [ -z "$url" ] || [ -z "$sha512" ]; then log_error "Failed to parse release manifest." diff --git a/lib/json.sh b/lib/json.sh deleted file mode 100644 index fa85bb8..0000000 --- a/lib/json.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash - -# generic JSON parser in pure bash and awk. -# reads JSON from stdin and outputs a flattened list of key-value pairs. -# example input: {"plugins": {"my_plugin": {"version": "1.0", "arr": [1, 2]}}} -# example output: - # plugins.my_plugin.version="1.0" - # plugins.my_plugin.arr[0]=1 - # plugins.my_plugin.arr[1]=2 - -# pardon my french -parse_json() { - # Tokenize the JSON using grep - grep -oE '"([^"\\]|\\.)*"|true|false|null|[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?|[][}{:,]' | \ - awk ' - BEGIN { - depth=0; - key="" - } - { - token = $0 - if (token == "{") { - depth++ - is_key[depth] = 1 - array_idx[depth] = "" - } else if (token == "}") { - delete path[depth] - delete array_idx[depth] - depth-- - } else if (token == "[") { - depth++ - is_key[depth] = 0 - array_idx[depth] = 0 - } else if (token == "]") { - delete array_idx[depth] - delete path[depth] - depth-- - } else if (token == ":") { - is_key[depth] = 0 - } else if (token == ",") { - if (array_idx[depth] != "") { - array_idx[depth]++ - } else { - is_key[depth] = 1 - } - } else { - if (is_key[depth] == 1) { - # Remove quotes from the key - gsub(/^"|"$/, "", token) - path[depth] = token - } else { - # It is a value - p = "" - for (i=1; i<=depth; i++) { - if (array_idx[i] != "") { - p = p "[" array_idx[i] "]" - } else if (path[i] != "") { - p = p "." path[i] - } - } - # Remove leading dot - sub(/^\./, "", p) - print p "=" token - } - } - } - ' -} diff --git a/lib/plugins.sh b/lib/plugins.sh index c19400e..bd44d6d 100644 --- a/lib/plugins.sh +++ b/lib/plugins.sh @@ -1,50 +1,13 @@ #!/usr/bin/env bash -if [ -f "$BOOTSTRAP_DIR/lib/json.sh" ]; then - . "$BOOTSTRAP_DIR/lib/json.sh" -fi - -# Parses a plugin manifest using the generic json parser and outputs bash array assignments +# Parses a plugin manifest using jq and outputs bash array assignments parse_plugin_manifest() { - # The generic parser outputs lines like: - # plugins.myplugin.version="1.0" - # plugins.myplugin.url="https://..." - # We want to extract myplugin and the keys to build: - # PLUGIN_VERSIONS["myplugin"]="1.0" - # PLUGIN_URLS["myplugin"]="https://..." - - parse_json | awk -F'=' ' - { - path = $1 - val = $2 - - # Remove quotes around value for bash array assignment - gsub(/^"|"$/, "", val) - - # Match paths starting with "plugins." - if (match(path, /^plugins\./)) { - rest = substr(path, RLENGTH + 1) - # Find the last dot to separate plugin name from the property key - last_dot = 0 - for (i=length(rest); i>0; i--) { - if (substr(rest, i, 1) == ".") { - last_dot = i - break - } - } - if (last_dot > 0) { - plugin_name = substr(rest, 1, last_dot - 1) - prop = substr(rest, last_dot + 1) - if (prop == "version") { - print "PLUGIN_VERSIONS[\"" plugin_name "\"]=\"" val "\"" - } else if (prop == "url") { - print "PLUGIN_URLS[\"" plugin_name "\"]=\"" val "\"" - } else if (prop == "bootstrap") { - print "PLUGIN_BOOTSTRAP_VERSIONS[\"" plugin_name "\"]=\"" val "\"" - } - } - } - }' + jq -r ' + .plugins | to_entries[] | + (if .value.version then "PLUGIN_VERSIONS[\"" + .key + "\"]=\"" + .value.version + "\"" else empty end), + (if .value.url then "PLUGIN_URLS[\"" + .key + "\"]=\"" + .value.url + "\"" else empty end), + (if .value.bootstrap then "PLUGIN_BOOTSTRAP_VERSIONS[\"" + .key + "\"]=\"" + .value.bootstrap + "\"" else empty end) + ' } # Ensures that the plugin sources file exists, initializing it with the official repository by default