#!/bin/bash
# aur-vercmp - check packages for AUR updates
[[ -v AUR_DEBUG ]] && set -o xtrace
set -o pipefail
argv0=vercmp
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

# default options
format=check target=aur all=0 quiet=0

args_csv() {
    # shellcheck disable=SC2155
    local str=$(printf '%s,' "$@")
    printf '%s' "${str%,}"
}

my_vercmp() {
    if [[ $1 == "$2" ]]; then
        printf '%d' 0 # common case
    else
        vercmp "$1" "$2"
    fi
}

cmp_equal_or_newer() {
    local pkg v_cmp v_in op

    while read -r pkg v_cmp v_in; do
        case $v_cmp in
            -) op=2 ;; # - on field 2
            *) op=$(my_vercmp "$v_in" "$v_cmp") ;;
        esac

        case $op in
           -1) plain >&2 '%s %s is newer than %s' "$pkg" "$v_cmp" "$v_in" >&2
               printf '%s\n' "$pkg" ;;
            0) printf '%s\n' "$pkg" ;;
            1) msg2 >&2 '%s %s -> %s' "$pkg" "$v_cmp" "$v_in" ;;
            2) msg2 >&2 '%s (none) -> %s' "$pkg" "$v_in" ;;
        esac
    done
}

cmp_checkupdates() {
    local pkg v_cmp v_in op

    while read -r pkg v_cmp v_in; do
        case $v_in in
            -) op=2 ;; # - on field 3
            *) op=$(my_vercmp "$v_in" "$v_cmp") ;;
        esac

        (( ! all )) && (( op > -1 )) && continue;
        (( quiet )) && { printf '%s\n' "$pkg"; continue; }

        case $op in
           -1) printf '%s %s -> %s\n' "$pkg" "$v_in" "$v_cmp" ;;
            0) printf '%s %s = %s\n'  "$pkg" "$v_in" "$v_cmp" ;;
            1) printf '%s %s <- %s\n' "$pkg" "$v_in" "$v_cmp" ;;
            2) printf '%s (none) -> %s\n' "$pkg" "$v_cmp"     ;;
        esac
    done
}

parse_aur() {
    aur query -t info - | aur format -f '%n\t%v\n'
}

trap_exit() {
    if [[ ! -v AUR_DEBUG ]]; then
        rm -rf -- "$tmp"
    else
        printf >&2 'AUR_DEBUG: %s: temporary files at %s\n' "$argv0" "$tmp"
    fi
}

usage() {
    plain >&2 'usage: %s [-acq] [-p path]' "$argv0"
    exit 1
}

source /usr/share/makepkg/util/message.sh

if [[ ! -v NO_COLOR ]] && [[ ! -v AUR_DEBUG ]]; then
    [[ -t 2 ]] && colorize
fi

opt_short='p:u:acq'
opt_long=('all' 'current' 'path:' 'quiet' 'upair:')
opt_hidden=('dump-options')

if opts=$(getopt -o "$opt_short" -l "$(args_csv "${opt_long[@]}" "${opt_hidden[@]}")" -n "$argv0" -- "$@"); then
    eval set -- "$opts"
else
    usage
fi

unset aux repo upair
while true; do
    case "$1" in
        -a|--all)
            all=1 ;;
        -c|--current)
            format=equal ;;
        -q|--quiet)
            quiet=1 ;;
        -p|--path)
            shift; aux=$1
            target='file' ;;
        -u|--upair)
            shift; upair=$1 ;;
        --dump-options)
            printf -- '--%s\n' "${opt_long[@]}" ${AUR_DEBUG+"${opt_hidden[@]}"}
            printf -- '%s' "${opt_short}" | sed 's/.:\?/-&\n/g'
            exit ;;
        --) shift; break ;;
    esac
    shift
done

# shellcheck disable=SC2174
mkdir -pm 0700 -- "${TMPDIR:-/tmp}/aurutils-$UID"
tmp=$(mktemp --tmpdir "aurutils-$UID/$argv0.XXXXXXXX") || exit
trap 'trap_exit' EXIT

# check for interactive terminal
if [[ -t 0 ]]; then
    cat >&2 <<EOF
Warning: Input is read from the terminal. You either know what you
Warning: are doing, or you forgot to pipe data into $argv0.
Warning: Press CTRL-D to exit.
EOF
fi
sort -k 1b,1 >"$tmp"

# set filters
case $format in
    check) cmp() { cmp_checkupdates; }
           upair=${upair-1} ;; # join unpaired of target
    equal) cmp() { cmp_equal_or_newer; }
           upair=${upair-2} ;; # join unpaired of input
esac

# pipeline
case $target in
     aur) awk '{print $1}' "$tmp" | parse_aur ;;
    file) awk '{print $0}' "$aux" ;;
esac | sort -k 1b,1 | join -a "$upair" -e - -o 0,1.2,2.2 - "$tmp" | cmp

# vim: set et sw=4 sts=4 ft=sh:
