# dnf completion                                          -*- shell-script -*-
#
# This file is part of dnf.
#
# Copyright 2013 (C) Elad Alfassa <elad@fedoraproject.org>
# Copyright 2014-2015 (C) Igor Gnatenko <i.gnatenko.brain@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301  USA

__dnf_main_options="
    -4 -6 -b -c -C -d -e -h -q -R -v -x -y
    --advisory --advisories
    --allowerasing --assumeno
    --assumeyes
    --best --bugfix
    --bz
    --cacheonly --config
    --color --cve
    --debuglevel --debugsolver
    --disableexcludes --disableplugin
    --disableexcludepkgs --disablerepo
    --downloadonly --destdir
    --downloaddir
    --errorlevel --enableplugin
    --enablerepo --enhancement
    --exclude --excludepkgs
    --help --help-cmd
    --installroot
    --newpackage --nodocs
    --nogpgcheck --noplugins
    --noautoremove
    --obsoletes
    --quiet
    --randomwait --refresh
    --releasever --repofrompath
    --repo --repoid
    --rpmverbosity
    --sec-severity --secseverity
    --security --setopt
    --skip-broken --showduplicates
    --verbose --version
"

__dnf_history_subcmds="info list redo rollback undo userinstalled"

__dnf_secseverity_subcmds='Critical Important Low Moderate'

__dnf_clean_subcmds="all dbcache expire-cache metadata packages"

__dnf_module_subcmds="install remove update enable disable reset provides list info repoquery"

__dnf_repoquery_subcmds="
    -a -f -i -l -s
    --all --arch
    --archlist --available
    --alldeps
    --conflicts
    --deplist --duplicates
    --exactdeps --extras
    --envra --enhances
    --file
    --groupmember
    --installed --installonly
    --info
    --latest-limit --list
    --location
    --nevra  --nvr
    --provides
    --qf --queryformat
    --querytags
    --recent --requires-pre
    --recommends --requires
    --recursive --resolve
    --source --suggests
    --supplements --show-duplicates
    --srpm
    --tree
    --upgrades --unneeded
    --unsatisfied --userinstalled
    --whatconflicts --whatobsoletes
    --whatprovides --whatrequires
    --whatrecommends --whatenhances
    --whatsuggests --whatsupplements
"

__dnf_repopkgs_subcmds="
    check-update
    info install
    list
    move-to
    remove-or-reinstall remove-or-distro-sync
    reinstall reinstall-old
    upgrade upgrade-to
"

__dnf_cache_file="/var/cache/dnf/packages.db"

_dnf_query_db()
{
    local table=$1
    local prefix=$2
    local query="select pkg from $table where pkg like '$prefix%'"
    if [ "$table" = "available" ]; then
        # The available table contains both installed and non-installed
        # packages. Exclude the installed packages.
	query="$query and pkg not in (select pkg from installed)"
    fi
    sqlite3 -batch -init /dev/null "$__dnf_cache_file" "$query"
}

__dnf_python_exec=
_dnf_set_python_exec()
{
    if [[ "$( readlink /usr/bin/dnf )" == "dnf-2" ]]; then
        __dnf_python_exec="/usr/bin/python2"
    else
        if [ -x /usr/libexec/platform-python ]; then
            __dnf_python_exec="/usr/libexec/platform-python"
        else
            __dnf_python_exec="/usr/bin/python3"
        fi
    fi
}

_dnf_commands_helper()
{
    local helper_cmd="import sys; from dnf.cli import completion_helper as ch; ch.main(sys.argv[1:])"
    local helper_opts="-d 0 -q -C --assumeno --nogpgcheck"
    "${__dnf_python_exec}" -c "$helper_cmd" "$@" $helper_opts 2>/dev/null </dev/null
}

# decide "path-like?" per initial: dot (./f.rpm, ../b.rpm), / (full path) or ~
_dnf_is_path()
{
    [[ "$1" = \.* ]] || [[ "$1" = \/* ]] || [[ "$1" = \~* ]]
}

_dnf_show_packages()
{
    local args cmd=$1
    _count_args
    # do not print packages if command wasnt chosen yet
    # eg.: dnf inTAB
    [[ "$args" -eq 1 ]] && return

    # return when "-" follows command
    # eg.: dnf up -
    [[ "$cur" == -* ]] && return

    shift

    if ! _dnf_is_path "$cur"; then
        if [ -r "$__dnf_cache_file" ] && [ -x /usr/bin/sqlite3 ]; then
            case "$cmd$*" in
            listinstalled|listupdates|\
            dg|downgrade|\
            ri|rei|reinstall|\
            rm|remove*|erase*|\
            um|u-m|upgrade|upgrade-n*|\
            up|up-min|update|update-n*)
                COMPREPLY+=( $(_dnf_query_db installed "$cur") )
                ;;
            *)
                COMPREPLY+=( $(_dnf_query_db available "$cur") )
                ;;
            esac
        else
            COMPREPLY+=( $(compgen -W "$( _dnf_commands_helper $cmd "$@" "$cur" )") )
        fi
    fi

    [[ $COMPREPLY ]] && return

    COMPREPLY+=( $(compgen -o default -f -X "!*.@(rpm)" -- "$cur" ) )
}

_dnf_get_first_command()
{
    local cmd i

    for (( i=1; i < ${#COMP_WORDS[@]}; i++ )); do
        if [[ "$1"  == *${COMP_WORDS[i]}* ]]; then
            cmd=${COMP_WORDS[i]}
            break
        fi
    done

    echo "$cmd"
}

_dnf()
{
    _dnf_set_python_exec

    local complete_commands complete_options extra_options command cmd_list
    local cur prev words cword split
    _init_completion -s || return

    cmd_list="$( _dnf_commands_helper "_cmds" "" )"
    command="$( _dnf_get_first_command "$cmd_list" )"

    case $prev in
    --version)
       return ;;

    -h|--help|--help-cmd)
        [[ $cword -eq 3 ]] && return ;;

    -d|--debuglevel|-e|--errorlevel)
        COMPREPLY=( $( compgen -W '0 1 2 3 4 5 6 7 8 9 10' -- "$cur" ) )
        return
        ;;

    --installroot)
        _filedir -d
        return ;;

    --enablerepo)
        COMPREPLY=( $(compgen -W "$( _dnf_commands_helper repolist disabled "$cur" )" -- "$cur") )
        return ;;

    --disablerepo)
        COMPREPLY=( $(compgen -W "$( _dnf_commands_helper repolist enabled "$cur" )" -- "$cur") )
        return ;;

    --color)
        COMPREPLY=( $(compgen -W "yes no true false 0 1" -- "$cur" ) )
        return ;;

    --destdir|--downloaddir)
        _filedir -d
        return ;;

    --sec*severity)
        COMPREPLY=( $( compgen -W "$__dnf_secseverity_subcmds" -- "$cur" ) )
        return ;;
    *)
        ;;
    esac

    complete_commands=

    case "$command" in
    autoremove|autoremove-n*)
        _dnf_show_packages list installed
        ;;

    check)
        extra_options="--all --dependencies --duplicates --obsoleted --provides"
        complete_commands="all dependencies duplicates obsoleted provides"
        ;;

    check-update|check-upgrade)
        _dnf_show_packages list updates
        ;;

    clean)
        complete_commands="$__dnf_clean_subcmds"
        ;;

    dup|dist-upgrade|dsync|distro*sync|distribution-synchronization)
        _dnf_show_packages list installed
        ;;

    dg|downgrade)
        _dnf_show_packages $command
        ;;

    group|groups|grouperase|groupinfo|groupinstall|grouplist|groupremove|groupupdate)
        extra_options="--with-optional --hidden --installed --available"
        ;;

    help)
        [[ $cword -eq 3 ]] && return 0
        complete_commands="$cmd_list"
        ;;

    history)
        complete_commands="$__dnf_history_subcmds"
        ;;

    info|list)
        local subcmd="available installed updates upgrades
                      --available --installed --updates --upgrades"
        case "$( _dnf_get_first_command "$subcmd" )" in
            --installed|installed)
                _dnf_show_packages list installed ;;

            --available|available)
                _dnf_show_packages list available ;;

            --updates|--upgrades|updates|upgrades)
                _dnf_show_packages list updates ;;

            *)
                _dnf_show_packages list
            ;;

        esac

        extra_options="--all --available --installed --extras --updates
                       --upgrades --autoremove --recent"
        ;;

    info-*|list-*|updateinfo|summary-updateinfo)
        extra_options="--summary --list --info"
        complete_commands="summary list info"
        ;;

    in|install*|localinstall)
        _dnf_show_packages $command
        ;;

    mark)
        _dnf_show_packages list installed
        ;;

    mc|ref|makecache|refresh)
        [[ "$prev" == *"timer" ]] && return
        extra_options="--timer"
        complete_commands="timer"
        ;;

    module)
        extra_options="--enabled --disabled --installed --profile --available --all"
        complete_commands="$__dnf_module_subcmds"
        case $prev in
            info)
                extra_options="--profile"
                ;;
            remove)
                extra_options="--all"
                ;;
            list)
                extra_options="--all --enabled --disabled --installed"
                ;;
            repoquery)
                extra_options="--available --installed"
                ;;
        esac
        ;;

    provides)
        ;;

    ri|rei|reinstall)
        _dnf_show_packages $command
        ;;

    rm|remove*|erase*)
        _dnf_show_packages $command
        extra_options="--oldinstallonly --duplicates --duplicated"
        ;;

    repoinfo|repolist)
        extra_options="--all --enabled --disabled"
        case $prev in
        enabled|--enabled)
            complete_commands="$( _dnf_commands_helper $command enabled "$cur" )"
            ;;
        disabled|--disabled)
            complete_commands="$( _dnf_commands_helper $command disabled "$cur" )"
            ;;
        all|--all|*)
            complete_commands="$( _dnf_commands_helper $command all "$cur" )"
        esac
        ;;

    repoquery*)
        extra_options="$__dnf_repoquery_subcmds"
        ;;

    repo*-pkgs|repo*-packages)
        complete_commands="$__dnf_repopkgs_subcmds"
        ;;

    se|search)
        [[ "$prev" == *"all" ]] && return
        extra_options="--all"
        complete_commands="all"
        ;;

    sh|shell) ;;

    swap) ;;

    um|u-m|upgrade|upgrade-n*)
        _dnf_show_packages $command
        ;;

    up|up-min|update|update-n*)
        _dnf_show_packages $command
        ;;

    whatprovides) ;;

    *)
        complete_commands="$cmd_list"
        ;;
    esac

    $split && return

    case $cur in
    -*)
        complete_options="$__dnf_main_options $extra_options"
        COMPREPLY=( $(compgen -W "$complete_options" -- "$cur" ))
        ;;
    *)
        if [[ $cur == $command ]]; then
            complete_commands="$cmd_list"
        fi

        if [[ "$complete_commands" ]]; then
            COMPREPLY=( $(compgen -W "$complete_commands" -- "$cur" ))
        fi
    esac

    [[ $COMPREPLY == *= ]] && compopt -o nospace
    return 0
}

complete_cmds="dnf-2 dnf-3 dnf4"
dnf_target=$(readlink -f "/usr/bin/dnf")

if [ "$dnf_target" = "/usr/bin/dnf-3" ]; then
    complete_cmds+=" dnf"
fi

complete -F _dnf $complete_cmds
