#!/usr/bin/env bash set -euo pipefail default_socket="/run/uce/cli.sock" if [[ -z "${UCE_CLI_SOCKET:-}" && -r /etc/uce/settings.cfg ]]; then configured_socket=$(awk -F= '/^[[:space:]]*CLI_SOCKET_PATH[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' /etc/uce/settings.cfg) if [[ -n "${configured_socket:-}" ]]; then default_socket="$configured_socket" fi fi socket_path="${UCE_CLI_SOCKET:-$default_socket}" method="auto" raw_json="" usage() { cat <<'USAGE' Usage: scripts/uce-cli [options] [key=value ...] Options: --socket PATH Unix socket path (default: CLI_SOCKET_PATH from /etc/uce/settings.cfg, UCE_CLI_SOCKET, or /run/uce/cli.sock) --get Send key=value parameters as a query string --post Send key=value parameters as a JSON POST (default when params exist) --json JSON Send raw JSON as POST body -h, --help Show this help Examples: scripts/uce-cli /ping scripts/uce-cli /tests/cli.uce action=echo message=hello scripts/uce-cli --json '{"action":"echo","message":"hello"}' /tests/cli.uce scripts/uce-cli --get /tests/cli.uce action=echo message=hello USAGE } while [[ $# -gt 0 ]]; do case "$1" in --socket) [[ $# -ge 2 ]] || { echo "--socket requires a path" >&2; exit 2; } socket_path="$2" shift 2 ;; --get) method="get" shift ;; --post) method="post" shift ;; --json) [[ $# -ge 2 ]] || { echo "--json requires a JSON value" >&2; exit 2; } raw_json="$2" method="post" shift 2 ;; -h|--help) usage exit 0 ;; --) shift break ;; -*) echo "unknown option: $1" >&2 usage >&2 exit 2 ;; *) break ;; esac done [[ $# -ge 1 ]] || { usage >&2; exit 2; } path="$1" shift if [[ "$path" != /* ]]; then path="/$path" fi if [[ ! -S "$socket_path" ]]; then echo "UCE CLI socket not found: $socket_path" >&2 exit 1 fi if [[ "$method" == "auto" ]]; then if [[ $# -gt 0 || -n "$raw_json" ]]; then method="post" else method="get" fi fi if [[ -n "$raw_json" ]]; then printf '%s' "$raw_json" | python3 -m json.tool >/dev/null curl -sS --fail-with-body --unix-socket "$socket_path" \ -X POST \ -H 'Content-Type: application/json' \ --data-binary "$raw_json" \ "http://localhost$path" exit $? fi if [[ "$method" == "get" ]]; then url="http://localhost$path" if [[ $# -gt 0 ]]; then query=$(python3 - "$@" <<'PY' import sys, urllib.parse pairs = [] for arg in sys.argv[1:]: if '=' not in arg: raise SystemExit(f"argument is not key=value: {arg}") key, value = arg.split('=', 1) pairs.append((key, value)) print(urllib.parse.urlencode(pairs)) PY ) url="$url?$query" fi curl -sS --fail-with-body --unix-socket "$socket_path" "$url" else json=$(python3 - "$@" <<'PY' import json, sys payload = {} for arg in sys.argv[1:]: if '=' not in arg: raise SystemExit(f"argument is not key=value: {arg}") key, value = arg.split('=', 1) lowered = value.lower() if lowered == 'true': parsed = True elif lowered == 'false': parsed = False elif lowered in ('null', 'none'): parsed = None else: try: parsed = int(value) except ValueError: try: parsed = float(value) except ValueError: parsed = value payload[key] = parsed print(json.dumps(payload, separators=(',', ':'))) PY ) curl -sS --fail-with-body --unix-socket "$socket_path" \ -X POST \ -H 'Content-Type: application/json' \ --data-binary "$json" \ "http://localhost$path" fi