Loading...
No commits yet
Not committed History
Blame
yq_wrapper.sh • 6.5 KB
#!/bin/bash
# Universal yq wrapper - handles both Python and Go versions
# Provides consistent interface regardless of which yq is installed

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log_error() {
    echo -e "${RED}[ERROR]${NC} $1" >&2
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1" >&2
}

log_debug() {
    if [[ "${YQ_DEBUG:-}" == "1" ]]; then
        echo -e "${GREEN}[DEBUG]${NC} $1" >&2
    fi
}

detect_yq_type() {
    if ! command -v yq &> /dev/null; then
        log_error "yq not found. Please install yq first."
        log_error "  Go version: https://github.com/mikefarah/yq"
        log_error "  Or run: requirements/install.sh --yq-only"
        return 2
    fi

    # Check version string
    local version_output
    version_output=$(yq --version 2>&1)

    if echo "$version_output" | grep -q "mikefarah"; then
        echo "go"
        return 0
    elif echo "$version_output" | grep -qi "kislyuk\|jq"; then
        echo "python"
        return 0
    else
        # Feature detection fallback
        if echo 'test: value' | yq eval '.test = "new"' - &>/dev/null 2>&1; then
            echo "go"
            return 0
        elif echo 'test: value' | yq -y '.test = "new"' - &>/dev/null 2>&1; then
            echo "python"
            return 0
        else
            log_error "Unknown yq version. Cannot determine type."
            return 1
        fi
    fi
}

yq_set() {
    local file="$1"
    local path="$2"
    local value="$3"

    if [[ -z "$file" ]] || [[ -z "$path" ]] || [[ -z "$value" ]]; then
        log_error "Usage: yq_set <file> <path> <value>"
        return 1
    fi

    if [[ ! -f "$file" ]]; then
        log_error "File not found: $file"
        return 1
    fi

    local yq_type
    yq_type=$(detect_yq_type) || return $?

    log_debug "Detected yq type: $yq_type"
    log_debug "Setting $path = \"$value\" in $file"

    case "$yq_type" in
        go)
            yq eval -i "${path} = \"${value}\"" "$file"
            ;;
        python)
            local temp_file="${file}.tmp.$$"
            yq -y "${path} = \"${value}\"" "$file" > "$temp_file"
            mv "$temp_file" "$file"
            ;;
        *)
            log_error "Unknown yq type: $yq_type"
            return 1
            ;;
    esac
}

yq_get() {
    local file="$1"
    local path="$2"

    if [[ -z "$file" ]] || [[ -z "$path" ]]; then
        log_error "Usage: yq_get <file> <path>"
        return 1
    fi

    if [[ ! -f "$file" ]]; then
        log_error "File not found: $file"
        return 1
    fi

    local yq_type
    yq_type=$(detect_yq_type) || return $?

    log_debug "Detected yq type: $yq_type"
    log_debug "Getting $path from $file"

    case "$yq_type" in
        go)
            yq eval "$path" "$file"
            ;;
        python)
            yq -r "$path" "$file"
            ;;
        *)
            log_error "Unknown yq type: $yq_type"
            return 1
            ;;
    esac
}

yq_delete() {
    local file="$1"
    local path="$2"

    if [[ -z "$file" ]] || [[ -z "$path" ]]; then
        log_error "Usage: yq_delete <file> <path>"
        return 1
    fi

    if [[ ! -f "$file" ]]; then
        log_error "File not found: $file"
        return 1
    fi

    local yq_type
    yq_type=$(detect_yq_type) || return $?

    log_debug "Detected yq type: $yq_type"
    log_debug "Deleting $path from $file"

    case "$yq_type" in
        go)
            yq eval -i "del(${path})" "$file"
            ;;
        python)
            local temp_file="${file}.tmp.$$"
            yq -y "del(${path})" "$file" > "$temp_file"
            mv "$temp_file" "$file"
            ;;
        *)
            log_error "Unknown yq type: $yq_type"
            return 1
            ;;
    esac
}

yq_merge() {
    local file1="$1"
    local file2="$2"
    local output="$3"

    if [[ -z "$file1" ]] || [[ -z "$file2" ]]; then
        log_error "Usage: yq_merge <file1> <file2> [output_file]"
        return 1
    fi

    if [[ ! -f "$file1" ]] || [[ ! -f "$file2" ]]; then
        log_error "Input files not found"
        return 1
    fi

    local yq_type
    yq_type=$(detect_yq_type) || return $?

    log_debug "Detected yq type: $yq_type"
    log_debug "Merging $file1 and $file2"

    case "$yq_type" in
        go)
            if [[ -n "$output" ]]; then
                yq eval-all '. as $item ireduce ({}; . * $item)' "$file1" "$file2" > "$output"
            else
                yq eval-all '. as $item ireduce ({}; . * $item)' "$file1" "$file2"
            fi
            ;;
        python)
            log_warn "Merge operation not fully supported with Python yq"
            log_warn "Consider installing Go-based yq: requirements/install.sh --yq-only"
            if [[ -n "$output" ]]; then
                yq -y -s '.[0] * .[1]' "$file1" "$file2" > "$output"
            else
                yq -y -s '.[0] * .[1]' "$file1" "$file2"
            fi
            ;;
        *)
            log_error "Unknown yq type: $yq_type"
            return 1
            ;;
    esac
}

show_usage() {
    cat << EOF
Usage: $0 <command> <args...>

Universal yq wrapper - works with both Python and Go versions of yq

COMMANDS:
    set <file> <path> <value>     Set a value in YAML file
    get <file> <path>              Get a value from YAML file
    delete <file> <path>           Delete a key from YAML file
    merge <file1> <file2> [out]    Merge two YAML files
    detect                         Detect which yq version is installed

EXAMPLES:
    $0 set config.yaml '.citation.style' 'unsrtnat'
    $0 get config.yaml '.citation.style'
    $0 delete config.yaml '.old_key'
    $0 merge base.yaml override.yaml output.yaml
    $0 detect

ENVIRONMENT:
    YQ_DEBUG=1    Enable debug output

EOF
}

main() {
    case "${1:-}" in
        set)
            shift
            yq_set "$@"
            ;;
        get)
            shift
            yq_get "$@"
            ;;
        delete|del)
            shift
            yq_delete "$@"
            ;;
        merge)
            shift
            yq_merge "$@"
            ;;
        detect)
            local yq_type
            yq_type=$(detect_yq_type) || exit $?
            echo "Detected yq type: $yq_type"
            yq --version
            ;;
        -h|--help|help)
            show_usage
            exit 0
            ;;
        "")
            log_error "No command specified"
            show_usage
            exit 1
            ;;
        *)
            log_error "Unknown command: $1"
            show_usage
            exit 1
            ;;
    esac
}

main "$@"