Files
bootstrap/lib/plugins.sh
Aditya Gupta 7f3ff45f05
Some checks failed
Lint / lint (push) Failing after 14s
Lint / lint (pull_request) Failing after 15s
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
2026-06-26 18:19:23 +05:30

181 lines
5.9 KiB
Bash

#!/usr/bin/env bash
# Parses a plugin manifest using jq and outputs bash array assignments
parse_plugin_manifest() {
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
ensure_sources_file() {
local sources_file="$BOOTSTRAP_DIR/plugin_sources.txt"
if [ ! -f "$sources_file" ]; then
mkdir -p "$BOOTSTRAP_DIR"
echo "# Add raw URLs to JSON plugin manifests here, one per line." > "$sources_file"
echo "# Official Bootstrap plugin repository" >> "$sources_file"
echo "https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/plugins.json" >> "$sources_file"
fi
}
# Fetches manifests from sources and generates the cache
update_plugin_cache() {
ensure_sources_file
local cache_file="$BOOTSTRAP_DIR/lib/plugin_cache.sh"
local sources_file="$BOOTSTRAP_DIR/plugin_sources.txt"
mkdir -p "$BOOTSTRAP_DIR/lib"
# Initialize cache file
cat << 'EOF' > "$cache_file"
# Auto-generated plugin cache. Do not edit manually.
declare -g -A PLUGIN_URLS
declare -g -A PLUGIN_VERSIONS
declare -g -A PLUGIN_BOOTSTRAP_VERSIONS
EOF
if [ -f "$sources_file" ]; then
local dl_args=()
local temp_manifests=()
while IFS= read -r url || [ -n "$url" ]; do
# Skip empty lines and comments
[[ -z "$url" || "$url" == \#* ]] && continue
local temp_file
temp_file=$(mktemp --suffix=".json" 2>/dev/null || mktemp)
dl_args+=("$url" "$temp_file")
temp_manifests+=("$temp_file")
done < "$sources_file"
if [ ${#dl_args[@]} -gt 0 ]; then
log_info "Fetching ${#temp_manifests[@]} plugin manifests in parallel..."
download_multiple_files_parallel "${dl_args[@]}"
for temp_file in "${temp_manifests[@]}"; do
if [ -s "$temp_file" ]; then
cat "$temp_file" | parse_plugin_manifest >> "$cache_file"
fi
rm -f "$temp_file"
done
fi
fi
# Clear downloaded scripts to force lazy re-download of the updated versions
rm -rf "$BOOTSTRAP_DIR/plugins" 2>/dev/null || true
log_success "Plugin cache updated successfully."
}
manage_plugin_sources() {
ensure_sources_file
local sources_file="$BOOTSTRAP_DIR/plugin_sources.txt"
local editor="${EDITOR:-}"
if [ -z "$editor" ]; then
if has_command nvim; then editor="nvim"
elif has_command vim; then editor="vim"
elif has_command nano; then editor="nano"
else editor="vi"
fi
fi
$editor "$sources_file"
# Update cache after editing
update_plugin_cache
}
handle_plugin() {
local subcmd="${1:-}"
case "$subcmd" in
sources)
manage_plugin_sources
;;
update)
update_plugin_cache
;;
*)
log_error "Unknown plugin command: $subcmd"
log_info "Available commands: b plugin sources, b plugin update"
exit 1
;;
esac
}
run_plugin() {
local plugin_name="$1"
shift
local is_ephemeral=false
local cmd_args=()
for arg in "$@"; do
if [ "$arg" = "-e" ] || [ "$arg" = "--ephemeral" ]; then
is_ephemeral=true
else
cmd_args+=("$arg")
fi
done
local url="${PLUGIN_URLS[$plugin_name]:-}"
if [ -z "$url" ]; then
log_error "Plugin '$plugin_name' not found in cache."
return 1
fi
# Check compatibility version
local compat_ver="${PLUGIN_BOOTSTRAP_VERSIONS[$plugin_name]:-}"
if [ -n "$compat_ver" ]; then
local current_ver="0.0.0"
if [ -f "$BOOTSTRAP_DIR/VERSION" ]; then
current_ver=$(cat "$BOOTSTRAP_DIR/VERSION" | tr -d '[:space:]')
fi
if version_lt "$compat_ver" "$current_ver"; then
log_warn "Plugin '$plugin_name' is only tested up to bootstrap version $compat_ver (current: $current_ver). It may be incompatible."
fi
fi
if [ "$is_ephemeral" = "true" ]; then
log_info "Downloading and running plugin '$plugin_name' (ephemeral)..."
local script_content
if ! script_content=$(curl -fsSL "$url"); then
log_error "Failed to download plugin '$plugin_name' from $url"
return 1
fi
# Execute the plugin directly in memory in a subshell
(
export BOOTSTRAP_DIR
# We use bash -c and pass the script content to keep stdin free for interactive plugins
# The "$0" arg for bash -c is set to the plugin name
bash -c "$script_content" "$plugin_name" "${cmd_args[@]}"
)
return $?
else
local plugin_dir="$BOOTSTRAP_DIR/plugins"
local local_plugin="$plugin_dir/${plugin_name}.sh"
if [ ! -f "$local_plugin" ]; then
log_info "Downloading plugin '$plugin_name'..."
mkdir -p "$plugin_dir"
if ! curl -fsSL "$url" -o "$local_plugin"; then
log_error "Failed to download plugin '$plugin_name' from $url"
rm -f "$local_plugin"
return 1
fi
chmod +x "$local_plugin"
fi
log_info "Running plugin '$plugin_name'..."
# Execute the plugin in a subshell, passing any additional arguments
(
export BOOTSTRAP_DIR
bash "$local_plugin" "${cmd_args[@]}"
)
return $?
fi
}