#!/bin/sh
#
# Copyright (C) 2012-2020  Etersoft
# Copyright (C) 2012-2020  Vitaly Lipatov <lav@etersoft.ru>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

# Load use_local_repo from environment variable if set
[ -n "$EPM_USE_LOCAL_REPO" ] && use_local_repo="$EPM_USE_LOCAL_REPO"

# Enable local repo for ALT Atomic systems
[ "$FULLDISTRNAME" = "ALT Atomic" ] && use_local_repo=1

epm_install_files_alt_via_repo()
{
    local files="$*"
    [ -n "$files" ] || return

    local repodir="$epm_vardir/local-repo"

    # create repo and put packages to it
    [ -d "$repodir" ] || sudocmd epm repo create $repodir
    sudocmd epm repo pkgadd $repodir $files
    sudocmd epm repo index $repodir

    #docmd epm repo save

    docmd epm repo add --name "local-repo" $repodir
    docmd epm update

    # install with name=version
    # TODO: improve
    st=''
    for i in $files ; do
        st="$st $(epm print name for package $i)=$(epm print version for package $i)"
    done
    docmd epm install $st

    # the repo will used in epm image s supply
    #docmd epm repo restore
}

epm_install_files_alt()
{
    local files="$*"
    [ -z "$files" ] && return

    # TODO: check read permissions
    # sudo test -r FILE
    # do not fallback to install_names if we have no permissions

    __epm_print_warning_for_nonalt_packages $files

    if [ -n "$save_only" ] ; then
        echo
        cp -v $files "$EPMCURDIR"
        return
    fi

    # install packages via local repo if enabled (apt only: it uses name=version install)
    if [ -n "$use_local_repo" ] && [ "$PMTYPE" = "apt-rpm" ] ; then
        [ -n "$nodeps" ] && warning "Option --nodeps is not supported with local repo, ignored"
        epm_install_files_alt_via_repo $files
        return
    fi

    if [ -n "$put_to_repo" ] ; then
        load_helper epm-repopkg
        epm_put_to_repo $files
        return
    fi

    __epm_check_if_src_rpm $files

    __epm_check_vendor $files
    epm repack --check-repack-rule $files

    # --replacepkgs: Install the Package Even If Already Installed
    local replacepkgs="$(__epm_get_replacepkgs $files)"
    sudocmd rpm -Uvh $replacepkgs $(subst_option dryrun --test) $force $noscripts $nodeps $files && save_installed_packages $files && return
    local RES=$?
    # TODO: check rpm result code and convert it to compatible format if possible
    __epm_check_if_rpm_already_installed $force $replacepkgs $noscripts $nodeps $files && return

    # if run with --nodeps, do not fallback on hi level
    [ -n "$nodeps" ] && return $RES

    # separate second output
    info

    # Workround for https://bugzilla.altlinux.org/56327
    # TODO: check apt version
    if is_file_greater_2gb $files ; then
        direct="--direct"
    fi

    # TODO: check rpm version
    if is_file_greater_4gb $files ; then
        fatal "Only RPM 6 can install packages larger than 4 GB"
    fi

    # try install via apt/dnf if we could't install package file via rpm (we guess we need install requirements firsly)
    if [ -z "$direct" ] && [ -z "$noscripts" ] ; then
        case "$PMTYPE" in
            apt-rpm|dnf-rpm|dnf5-rpm)
                epm_install_names $files
                return
                ;;
        esac
    fi

    # TODO: use it always (apt can install version from repo instead of a file package)
    [ "$PMTYPE" = "apt-rpm" ] && info "Workaround for install packages via apt with --noscripts (see https://bugzilla.altlinux.org/44670)"
    info "Firstly install package requrements …"
    # names of packages to be installed
    local fl="$(epm print name for package $files)"
    local req="$(docmd epm req --short $files)" || return
    # exclude package names from requires (req - fl)
    req="$(estrlist exclude "$fl" "$req")"
    # TODO: can we install only requires via apt?
    docmd epm install --skip-installed $req || return

    # retry with rpm
    # --replacepkgs: Install the Package Even If Already Installed
    local replacepkgs="$(__epm_get_replacepkgs $files)"
    sudocmd rpm -Uvh $replacepkgs $(subst_option dryrun --test) $force $noscripts $nodeps $files && save_installed_packages $files
}

get_current_kernel_flavour()
{
    rrel=$(uname -r)
    rflv=${rrel#*-}
    rflv=${rflv%-*}
    echo "$rflv"
}

# print "module flavour" for kernel-modules-<module>[-<flavour>]
__epm_alt_kernel_module_flavour()
{
    local n="${1#kernel-modules-}" f
    for f in "$(echo "$n" | sed -n 's|.*-\([0-9]\+\.[0-9]\+\)$|\1|p')" "$(echo "$n" | sed -n 's|.*-\([a-z]\+-def\)$|\1|p')" "${n##*-}" ; do
        [ -n "$f" ] && [ "$f" != "$n" ] || continue
        if echo "$f" | grep -q -E '^([0-9]+\.[0-9]+|[a-z]+-def)$' || a='' rpm -q "kernel-image-$f" >/dev/null 2>&1 ; then
            echo "${n%-"$f"} $f"
            return
        fi
    done
    echo "$n $(get_current_kernel_flavour)"
}

# install kernel-modules-<module>[-<flavour>] with the latest kernel via update-kernel logic
epm_install_alt_kernel_module()
{
    [ -n "$1" ] || return 0

    local list='' kmf flavour module
    for kmf in "$@" ; do
        list="$list
$(__epm_alt_kernel_module_flavour "$kmf")"
    done

    load_helper epm-kernel_update
    for flavour in $(echo "$list" | cut -d' ' -f2 | grep . | sort -u) ; do
        local addopts=''
        for module in $(echo "$list" | grep " $flavour\$" | cut -d' ' -f1) ; do
            addopts="$addopts -A $module"
        done
        epm_kernel_update -t "$flavour" $addopts || return
    done
}


epm_install_alt_names()
{
    [ -z "$1" ] && return

    # check repo/package syntax (p10/pkg, sisyphus/pkg)
    if __has_repo_syntax "$@" ; then
        __process_repo_arguments epm_install_alt_names "$@"
        return
    fi

    local kmlist=''
    local kilist=''
    local installnames=''

    while [ -n "$1" ] ; do
        local pkgname
        pkgname="$1"
        if echo "$pkgname" | grep -q "^kernel-image-" && ! echo "$pkgname" | grep -q -- "-debuginfo" ; then
            # kernel-image-6.12, kernel-image-std-def or kernel-image-6.12-6.12.10-alt1
            kilist="$kilist $pkgname"
        elif echo "$pkgname" | grep -q -E -- '[#=]|-[0-9][^-]*-alt[^-]*$' ; then
            # pass install with full pkgnames (with version)
            installnames="$installnames $pkgname"
        elif echo "$pkgname" | grep -q "^kernel-modules-" ; then
            # virtualbox[-6.12]
            kmlist="$kmlist $pkgname"
        else
            installnames="$installnames $pkgname"
        fi
        shift
    done

    epm_install_names $installnames || return
    epm_install_alt_kernel_module $kmlist || return

    # install kernel images via update-kernel logic (handles modules automatically)
    if [ -n "$kilist" ] ; then
        load_helper epm-kernel_update
        local kpkg
        for kpkg in $kilist ; do
            if echo "$kpkg" | grep -q -E -- '[#=]|-[0-9][^-]*-alt[^-]*$' ; then
                epm_kernel_update -r "$kpkg" || return
            else
                epm_kernel_update -t "${kpkg#kernel-image-}" || return
            fi
        done
    fi
}

# Unused hack for apt-repo
# apt-repo with non_interactive support
apt_repo_prepare()
{
    assure_exists apt-repo
    [ -n "$non_interactive" ] || return

    set_sudo
    trap "$SUDO rm /etc/apt/apt.conf.d/eepm-apt-noninteractive.conf 2>/dev/null" EXIT
    echo 'APT::Get::Assume-Yes "true";' | $SUDO tee /etc/apt/apt.conf.d/eepm-apt-noninteractive.conf >/dev/null
}

apt_repo_after()
{
    [ -n "$non_interactive" ] || return

    $SUDO rm /etc/apt/apt.conf.d/eepm-apt-noninteractive.conf 2>/dev/null
}

# Process arguments in TASK or TASK/package format
prepare_task_packages()
{
    # Sets global vars:
    #   installlist             — final list of packages to install
    #   requested_task_packages — packages explicitly requested from a task
    #   unique_tasks            — unique task names from args

    installlist=""
    requested_task_packages=""
    unique_tasks=""
    local seen_tasks=""
    local task_packages=""

    for arg in "$@"; do
        # Parse argument: 123456, 123456/pkg, task/123456, task/123456/pkg
        local task="$(get_tasknumber_from_arg "$arg")"
        local pkg="$(get_pkgname_from_taskarg "$arg")"

        [ -n "$task" ] || continue

        # Fetch task packages once per unique task
        if ! echo " $seen_tasks " | grep -q " $task "; then
            unique_tasks="$unique_tasks $task"
            task_packages=$(get_task_packages "$task")
            seen_tasks="$seen_tasks $task"
        fi

        # Add specific package or all task packages to install list
        if [ -n "$pkg" ]; then
            installlist="$installlist $pkg"
            requested_task_packages="$requested_task_packages $pkg"
        else
            installlist="$installlist $task_packages"
        fi
    done
}

# copied from epm_upgrade_alt_tasks()
# dnf can't use apt task repos: download task packages and install them as files
# args: <package names> <task numbers...>
# download rpms with names from list $1 from task(s) to a temp dir, set task_files
# (for non apt backends: task repos have no rpm-md)
__epm_download_alt_task_files()
{
    local names="$1"
    shift
    load_helper epm-repopkg
    local tmpdir
    tmpdir="$(mktemp -d)" || fatal
    remove_on_exit "$tmpdir"
    __download_task_rpms "$tmpdir" "$@"
    local f
    task_files=''
    for f in "$tmpdir"/*.rpm ; do
        [ -e "$f" ] || continue
        estrlist contains "$(epm print name for package "$f")" "$names" || continue
        task_files="$task_files $f"
    done
    [ -n "$task_files" ] || fatal "No packages downloaded from task(s)"
}

__epm_install_alt_task_files()
{
    load_helper epm-install
    __epm_download_alt_task_files "$@"
    epm_install_files $task_files
}

epm_install_alt_tasks()
{
    load_helper epm-install

    prepare_task_packages "$@"

    [ -n "$verbose" ] && info "Packages from task(s): $installlist"

    if [ -n "$full" ] ; then
        installlist="$(estrlist reg_exclude ".*-checkinstall .*-debuginfo" "$installlist")"
    else
        # hack: drop -devel packages to avoid package provided by multiple packages
        installlist="$(estrlist reg_exclude ".*-devel .*-devel-static .*-checkinstall .*-debuginfo" "$installlist")"
        # Keep packages explicitly requested as task/PACKAGE.  In particular,
        # a task may be used to install a -devel subpackage.
        installlist="$(estrlist union "$installlist $requested_task_packages")"
    fi

    # TODO: need we this option?
    #if [ -z "$force" ] ; then
    #    # skip i586- on install
    installlist="$(estrlist reg_exclude "i586-.*" "$installlist")"
    #fi

    [ -n "$verbose" ] && info "Packages to install: $installlist"

    if [ -z "$installlist" ] ; then
        warning 'No packages available for install from task(s)' "$*"
        return 22
    fi

    if [ "$PMTYPE" != "apt-rpm" ] ; then
        __epm_install_alt_task_files "$installlist" $unique_tasks
        return
    fi

    local res
    __use_tmp_apt_for_tasks $unique_tasks || return 1
    (pkg_names="$installlist" epm_install)
    res=$?
    return $res
}
