#!/bin/bash
# aur-depends - retrieve package dependencies using AurJson
[[ -v AUR_DEBUG ]] && set -o xtrace
argv0=depends
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
max_request=30

# default options
mode=pkgname

count() {
    jq -r '.resultcount' "$1" | awk '{s += $1} END {print s}'
}

tabulate() {
    jq -r '.results[]
        | .Name         as $name
        | .PackageBase  as $base
        | .Version      as $ver
        | ([$name] + .Depends + .MakeDepends + .CheckDepends)[]?
        | [$name, ., $base, $ver] | @tsv' "$1"
}

tr_ver() {
    sed -r 's/[<>=].*$//g'
}

# shellcheck disable=SC2086
chain() {
    local a num sub

    printf '%s\n' "$@" | aur query -t info > json/0 || exit
    num=$(count json/0)

    if (( num < 1 )); then
        printf >&2 '%s: no packages found\n' "$argv0"
        exit 1
    fi

    for (( a = 1; a <= max_request; ++a )); do
        sub=$(( a - 1 ))
        tabulate json/$sub | tee -a tsv/n > tsv/$sub

        # Avoid querying duplicates (#4)
        cut -f1 tsv/$sub >> seen # pkgname
        cut -f2 tsv/$sub | tr_ver | grep -Fxvf seen | \
            aur query -t info > json/$a || exit # rpc error

        if [[ -s json/$a ]]; then
            num=$(count json/$a)
        else
            return $a # no unique results (seen \ tsv == [empty])
        fi

        if (( num >= 1 )); then
            cut -f2 tsv/$sub >> seen # depends
        else
            return $a # no results, recursion complete
        fi
    done

    # recursion limit exceeded
    return $max_request
}

order() {
    cut -f1,2 "$1" | tsort | tac
}

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() {
    printf >&2 'usage: %s [-abnt]\n' "$argv0"
    exit 1
}

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

opt_short='abnt'
opt_long=('table' 'pkgbase' 'pkgname' 'pkgname-all')
opt_hidden=('dump-options')

if ! parseopts "$opt_short" "${opt_long[@]}" "${opt_hidden[@]}" -- "$@"; then
    usage
fi
set -- "${OPTRET[@]}"

while true; do
    case "$1" in
        -a|--pkgname-all)
            mode=pkgname_all ;;
        -b|--pkgbase)
            mode=pkgbase ;;
        -n|--pkgname)
            mode=pkgname ;;
        -t|--table)
            mode=table ;;
        --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 -d --tmpdir "aurutils-$UID/$argv0.XXXXXXXX") || exit
trap 'trap_exit' EXIT

rings=0
if cd "$tmp" && mkdir json tsv; then
    chain "$@" || rings=$? # tsv/n: pkgname\tdepends\tpkgbase\pkgver

    # check iteration number
    case $rings in
        1) true # no dependencies
           ;;
        "$max_request")
            printf >&2 '%s: total requests: %d (out of range)\n' "$argv0" $(( max_request + 1 ))
            exit 34 ;;
    esac

    case $mode in
        # pkgbase (AUR, total order)
        pkgbase)
            # associate pkgname to pkgbase
            declare -A map map_seen

            while read -r pkgname pkgbase; do
                map[$pkgname]=$pkgbase
            done < <(cut -f1,3 tsv/n)

            # pkgbase is ignored for repo packages (as unknown)
            while read -r pkgname; do
                pkgbase=${map[$pkgname]}

                if [[ $pkgbase ]] && [[ ! ${map_seen[$pkgbase]} ]]; then
                    printf '%s\n' "${map[$pkgname]}"
                    map_seen[$pkgbase]=1
                fi
            done < <(order tsv/n)
            ;;
        # pkgname (AUR, total order)
        pkgname)
            grep -Fxf <(cut -f1 tsv/n) <(order tsv/n)
            ;;
        # pkgname (all, total order)
        pkgname_all)
            order tsv/n
            ;;
        # pkgname\tdepends\tpkgbase\tpkgver (AUR)
        table)
            cat tsv/n
            ;;
        *)
            printf >&2 '%s: invalid argument' "$argv0"
            exit 22 ;;
    esac
else
    exit      
fi

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