#!/bin/bash
# aur-repo - manage local repositories
[[ -v AUR_DEBUG ]] && set -o xtrace
argv0=repo
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

# default options
db_query=local table_format=0 list_path=0

# default arguments
conf_args=()

db_table() {
    # do not extract an empty database (#727)
    (( $(bsdtar -tf "$2" | wc -l) )) || return 0
    
    bsdtar -Oxf "$2" '*/desc' | awk -v table="$1" '
    function print_previous() {
        table ? format = "%s\t%s\t%s\t%s\n" : format = "%1$s\t%4$s\n"

        if (table && length(dependencies) > 0) {
            for (i in dependencies) {
                printf format, pkgname, dependencies[i], pkgbase, pkgver
            }
        } else {
            printf format, pkgname, pkgname, pkgbase, pkgver
        }
    }

    BEGIN {
        pkgname = pkgbase = pkgver = "-"
    }

    /^%FILENAME%$/ && FNR > 1 {
        print_previous()
        pkgname = pkgbase = pkgver = "-"
        delete dependencies
    }

    /^%NAME%$/ {
        getline
        pkgname = $1
    }

    /^%BASE%$/ {
        getline
        pkgbase = $1
    }

    /^%VERSION%$/ {
        getline
        pkgver = $1
    }

    /^%(MAKE|CHECK)?DEPENDS%$/ {
        while (table && getline && $0 != "") {
            dependencies[i++] = $1
        }
    }

    END {
        print_previous()
    }'
}

usage() {
    printf >&2 'usage: %s [-d repo] [-r path] [-alpqtuS]\n' "$argv0"
    exit 1
}

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

## option parsing
opt_short='c:d:r:alpqtuS'
opt_long=('database:' 'repo:' 'config:' 'root:' 'path' 'all' 'list'
          'repo-list' 'sync' 'upgrades' 'table' 'quiet' 'path-list')
opt_hidden=('dump-options' 'status-file:')

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

unset mode db_name db_root status_file pacman_conf vercmp_args
while true; do
    case $1 in
        -d|--database|--repo)
            shift; db_name=$1 ;;
        -r|--root)
            shift; db_root=$1 ;;
        -c|--config)
            shift; pacman_conf=$1 ;;
        -l|--list)
            mode=packages ;;
        -t|--table)
            mode=packages; table_format=1 ;;
        -p|--path)
            mode=path ;;
        -a|--all)
            mode=upgrades; vercmp_args+=(-a) ;;
        -q|--quiet)
            mode=upgrades; vercmp_args+=(-q) ;;
        -u|--upgrades)
            mode=upgrades ;;
        --repo-list)
            mode=repo_list ;;
        --path-list)
            mode=repo_list; list_path=1 ;;
        -S|--sync)
            db_query=sync ;;
        --status-file)
            shift; status_file=$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

if [[ -v pacman_conf ]]; then
    conf_args+=(--config "$pacman_conf")
fi

# assign environment variables
: "${db_name=$AUR_REPO}"
: "${db_root=$AUR_DBROOT}"

unset conf_file_repo conf_file_serv server

while read -r key _ value; do
    case $key=$value in
        \[*\]*)
            section=${key:1:-1}
            ;;
        DBPath=*)
            pacman_dbpath=$value
            ;;
        Server=file://*)
            server=${value#file://}
            conf_file_serv+=("$server")
            conf_file_repo+=("$section")

            if [[ $section == "$db_name" ]]; then
                if ! [[ $db_root ]]; then
                    db_root=$server
                elif [[ $db_root != "$server" ]]; then
                    printf >&2 '%s: warning: --root and pacman.conf mismatch (%s)\n' "$argv0" "$db_name"
                fi
            fi
            ;;
        Server=*://*)
            if [[ $section == "$db_name" ]] && ! [[ $db_root ]]; then
                db_root=$value
            fi
            ;;
    esac
done < <(pacman-conf "${conf_args[@]}")

# exclusive modes
case $mode in
    repo_list)
        if ! [[ ${conf_file_repo[*]} ]]; then
            printf >&2 '%s: no file:// repository configured\n' "$argv0"
            exit 2
        fi

        if (( list_path )); then
            paths=()
            for i in "${!conf_file_repo[@]}"; do
                paths+=("${conf_file_serv[$i]}/${conf_file_repo[$i]}".db)
            done

            readlink -f -- "${paths[@]}"
        else
            printf '%q\n' "${conf_file_repo[@]}"
        fi

        exit 0 ;;
esac

# other modes
if ! [[ $db_name ]]; then
    case ${#conf_file_repo[@]} in
        1) db_root=${conf_file_serv[0]}
           db_name=${conf_file_repo[0]}
           ;;
        0) printf >&2 '%s: no file:// repository configured\n' "$argv0"
           exit 2
           ;;
        *) printf >&2 '%s: repository choice is ambiguous (use -d to specify)\n' "$argv0"
           for i in "${!conf_file_repo[@]}"; do
               printf '%q\t%q\n' "${conf_file_repo[$i]}" "${conf_file_serv[$i]}"
           done | column -t >&2
           exit 1
           ;;
    esac
fi

if [[ -v status_file ]]; then
    { printf 'repo:%s\n' "$db_name"
      printf 'root:%s\n' "$db_root"
      printf 'conf:%s\n' "$pacman_conf"
    } > "$status_file"
fi

case $db_query in
    local)
        if ! [[ $db_root ]]; then
            printf >&2 '%s: %s: repository path not found\n' "$argv0" "$db_name"
            exit 2
        elif [[ $db_root == *://* ]]; then
            printf >&2 '%s: %s: object is remote (use -S to query)\n' "$argv0" "$db_root"
            exit 66
        elif ! [[ -d $db_root ]]; then
            printf >&2 '%s: %s: not a directory\n' "$argv0" "$db_root"
            exit 20
        fi
        db_path=$db_root/$db_name.db
        ;;
    sync)
        db_path=$pacman_dbpath/sync/$db_name.db
        ;;
esac

case $mode in
    upgrades)
        db_table "$table_format" "$db_path" | aur vercmp "${vercmp_args[@]}"
        ;;
    packages)
        db_table "$table_format" "$db_path"
        ;;
    path)
        readlink -f -- "$db_root/$db_name".db
        ;;
    *)
        usage
        ;;
esac

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