#!/bin/sh
#
# Copyright (C) 2012, 2017, 2019  Etersoft
# Copyright (C) 2012, 2017, 2019  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_helper epm-sh-altlinux

ETERSOFTPUBURL=http://download.etersoft.ru/pub
ALTLINUXPUBURL=http://ftp.altlinux.org/pub/distributions

__epm_addrepo_rhel()
{
    local repo="$*"
    if [ -z "$repo" ] ; then
        message 'Add repo.
                 1. Use with repository URL, f.i. http://www.example.com/example.repo
                 2. Use with epel to add EPEL repository
                 3. Use with powertools to add PowerTools repository
                 4. Use with crb to add Rocky Linux CRB repository'
        return 1
    fi
    case "$1" in
        epel)
            # dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
            epm install epel-release
            return 1
            ;;
        powertools)
            # https://serverfault.com/questions/997896/how-to-enable-powertools-repository-in-centos-8
            assure_exists dnf-plugins-core
            sudocmd dnf config-manager --set-enabled powertools
            return 1
            ;;
        crb)
            # https://wiki.rockylinux.org/rocky/repo/
            assure_exists dnf-plugins-core
            sudocmd dnf config-manager --set-enabled crb
            return 1
            ;;
    esac
    return 0
}

__get_sign()
{
    local repo="$1"
    rhas "$repo" "^c[0-9]" && echo "[cert8]" && return
    [ "$repo" = "sisyphus" ] && repo="alt"
    # alt c* distr has no alt vendor
    rhas "$DISTRVERSION" "^c[0-9]" && return
    [ -n "$repo" ] && echo "[$repo]"
}

get_archlist()
{
    echo "noarch"
    echo "$DISTRARCH"
    case $DISTRARCH in
        x86_64)
            echo "x86_64-i586"
            ;;
    esac
}

normalize_date()
{
    echo "$1" | sed -e 's|-|/|g' | grep -E "^20[0-3][0-9]/[01][0-9]/[0-3][0-9]$" || fatal "use follow date format: 2017/01/31 or 2017-01-31"
}

# arg: $branch "URL ALTLinux/$repo" "classic"
__epm_addrepo_add_alt_repo()
{
    local branch="$1"
    local repourl="$2"
    local comp="$3"
    local sign="$4"

    [ -n "$sign" ] || sign="$(__get_sign $branch)"
    [ -n "$comp" ] || comp="classic"

    local i
    for i in $(get_archlist) ; do
        epm repo add "rpm $sign $repourl/$i $comp"
    done

}


__epm_addrepo_etersoft_addon()
{
    epm install --skip-installed apt-conf-etersoft-common apt-conf-etersoft-hold || fatal
    # TODO: ignore only error code 22 (skipped) || fatal

    local repo="$1"
    local repopart
    [ "$repo" = "sisyphus" ] && repopart="Sisyphus" || repopart="$repo/branch"

    __epm_addrepo_add_alt_repo "$repo" "$ETERSOFTPUBURL/Etersoft LINUX@Etersoft/$repopart" "addon"
}

# args: p10|c10f1|sisyphus
__epm_addrepo_main_alt_repo()
{
    local repo="$1"

    local baseurl="http://ftp.basealt.ru/pub/distributions"

    local repopart
    [ "$repo" = "sisyphus" ] && repopart="Sisyphus" || repopart="$repo/branch"

    __epm_addrepo_add_alt_repo "$repo" "$baseurl ALTLinux/$repopart" "classic"
}


# 'rpm protocol:/path/to/repo component'
__epm_addrepo_altlinux_short()
{
    [ "$1" = "rpm" ] || fatal "only for rpm repo"
    local url="$2"
    local repo="$3"
    local arch

    arch="$(basename "$url")"
    url="$(dirname "$url")"
    docmd epm repo add "rpm $url $arch $repo"
}


__epm_addrepo_altlinux_url()
{
    local url="$1"
    local arch
    local base
    local repo

    # apt supports 302 redirect only since apt 0.7.21 (14th April 2009)
    url="$(eget --get-real-url $url)"

    # URL to path/RPMS.addon
    base="$(basename "$url")"
    if echo "$base" | grep -q "^RPMS\." ; then
        repo="$(echo $base | sed -e 's|.*\.||')"
        url="$(dirname $url)"
        __epm_addrepo_altlinux_short rpm "$url" "$repo"
        return
    fi

    # TODO: add to eget file:/ support and use here
    # URL to path (where RPMS.addon is exists)
    local baseurl="$(eget --list "$url/RPMS.*")"
    base="$(basename "$baseurl")"
    if echo "$base" | grep -q "^RPMS\." ; then
        REPO_NAME="$(echo "$base" | sed -e 's|.*\.||')"
        __epm_addrepo_altlinux_short rpm "$url" "$REPO_NAME"
        return
    fi

    # Initial hack for https://altlinux.space/ and forgejo rpm repo
    # https://docs.altlinux.space/alt-repo/
    # apt-repo add rpm https://altlinux.space/api/packages/rirusha/alt/group/libapi-base.repo _arch_ classic
    arch=$DISTRARCH
    REPO_NAME="classic"
    if eget --check-url $url/$arch/base/pkglist.$REPO_NAME ; then
        docmd epm repo add "rpm $url $arch $REPO_NAME"
        return
    fi

    # URL to {i586,x86_64,noarch}/RPMS.addon
    local res=''
    for arch in $(get_archlist) ; do
        eget --check-url $url/$arch/base/ || continue
        local rd="$(eget --list $url/$arch/RPMS.*)"
        [ -n "$rd" ] || continue
        local REPO_NAME="$(echo "$rd" | sed -e 's|/*$||' -e 's|.*\.||')"
        [ "$REPO_NAME" = "*" ] && continue
        docmd epm repo add "rpm $url $arch $REPO_NAME"
        res='1'
    done
    [ -n "$res" ] || warning "There is no arch repos in $url"
}


__epm_addrepo_altlinux_help()
{
message '

epm repo add - add branch repo. Use follow params:
    basealt                  - for BaseALT repo
    altsp                    - add ALT SP repo
    yandex                   - for BaseALT repo mirror hosted by Yandex (recommended)
    autoimports              - for BaseALT autoimports repo
    autoports                - for Autoports repo (with packages from Sisyphus rebuilt to the branch)
    altlinuxclub             - for altlinuxclub repo (http://altlinuxclub.ru/)
    deferred                 - for Etersoft Sisyphus Deferred repo
    deferred.org             - for Etersoft Sisyphus Deferred repo (at mirror.eterfund.org)
    etersoft                 - for LINUX@Etersoft repo
    korinf                   - for Korinf repo
    ximper                   - for Ximper Linux repo
    <task number>            - add task repo
    archive 2018/02/09       - add archive of the repo from that date
    /dir/to/repo [component] - add repo dir generated with epm repo index --init
    URL [arch] [component]   - add repo by URL

Examples:
    # epm repo add yandex
    # epm repo add "rpm http://somesite/pub/product x86_64 addon
    # epm repo add /var/ftp/pub/altlinux/p10

'
    return
}

__add_line_to_file()
{
    local file="$1"
    local line="$2"
    local sc="sudocmd"
    [ -n "$verbose" ] || sc="sudorun"
    set_sudo
    # ensure file ends with newline (check last byte)
    [ -n "$(tail -c1 "$file")" ] && echo "" | $sc tee -a "$file" >/dev/null
    echo "$line" | $sc tee -a "$file" >/dev/null
}


# like apt-add-repository on deb systems
__epm_addrepo_to_file()
{
    local file="$1"
    shift
    local repo="$*"

    if [ -z "$force" ] ; then
        # skip if repo is already in the list
        epm --quiet repo list "$repo" >/dev/null && return
    fi

    if [ -n "$dryrun" ] ; then
        echo "$repo"
        return
    fi

    __add_line_to_file "$file" "$repo"

}

__epm_addrepo_altlinux()
{
    local repo="$*"

    if [ -z "$repo" ] || [ "$repo" = "-h" ] || [ "$repo" = "--list" ] || [ "$repo" = "--help" ] ; then
        __epm_addrepo_altlinux_help
        return
    fi

    # 'rpm protocol:/path/to/repo/arch component' (no sign, arch in the URL)
    if [ "$1" = "rpm" ] && is_url "$2" && [ -n "$3" ] && [ -z "$4" ] ; then
        __epm_addrepo_altlinux_short "$@"
        return
    fi

    # /path/to/repo
    if [ -d "$1" ] ; then
        __epm_addrepo_altlinux_url "file:$1"
        return
    fi

    # file:/path/to/repo or http://path/to/repo
    if is_url "$1" ; then
        __epm_addrepo_altlinux_url "$1"
        return
    fi

    local branch="$(echo "$DISTRVERSION" | tr "[:upper:]" "[:lower:]")"
    [ -n "$branch" ] || fatal "Empty DISTRVERSION"

    case "$1" in
        etersoft)
            # TODO: return when Etersoft improved its repos
            #info "add Etersoft's addon repo"
            #__epm_addrepo_etersoft_addon $branch
            epm repo add $branch
            epm repo change etersoft
            return 0
            ;;
        basealt|alt|altsp)
            repo="$branch"
            ;;
        yandex)
            epm repo add $branch
            epm repo change yandex
            return 0
            ;;
        autoimports)
            repo="autoimports.$branch"
            ;;
        autoports)
            local http="http"
            epm installed apt-https && http="https"
            case $branch in
                p10|p9|p8)
                    ;;
                *)
                    fatal "Autoports is not supported for $DISTRNAME $branch. Check https://www.altlinux.org/Autoports ."
                    ;;
            esac
            epm repo addkey cronbuild "DE73F3444C163CCD751AC483B584C633278EB305" "Cronbuild Service <cronbuild@altlinux.org>"
            for i in $DISTRARCH noarch ; do
                epm repo add "rpm [cronbuild] $http://autoports.altlinux.org/pub ALTLinux/autoports/$branch/$i autoports"
            done
            return 0
            ;;
        altlinuxclub)
            repo="altlinuxclub.$branch"
            ;;
        autoimports.*|altlinuxclub.*)
            repo="$1"
            ;;
        korinf)
            local http="http"
            epm installed apt-https && http="https"
            epm repo add "rpm $http://download.etersoft.ru/pub Korinf/$DISTRARCH/$DISTRNAME/$DISTRVERSION main"
            return 0
            ;;
        ximper|ximperlinux)
            [ "$DISTRVERSION" = "Sisyphus" ] || fatal "Ximper Linux repo is applicable to Sisyphus only"
            epm install --scripts "https://download.etersoft.ru/pub/Etersoft/XimperLinux/Current/Additives/$DISTRARCH/RPMS.addon/ximper-repos-[0-9]*.$DISTRARCH.rpm"
            return 0
            ;;
        deferred)
            [ "$DISTRVERSION" = "Sisyphus" ] || fatal "Etersoft Sisyphus Deferred supported only for ALT Sisyphus based systems."
            __epm_addrepo_add_alt_repo "$branch" "https://download.etersoft.ru/pub Etersoft/Sisyphus/Deferred" "classic"
            return 0
            ;;
        deferred.org)
            [ "$DISTRVERSION" = "Sisyphus" ] || fatal "Etersoft Sisyphus Deferred supported only for ALT Sisyphus based systems."
            __epm_addrepo_add_alt_repo "$branch" "http://mirror.eterfund.org/pub Etersoft/Sisyphus/Deferred" "classic"
            return 0
            ;;
        deferred-devel)
            [ "$DISTRVERSION" = "Sisyphus" ] || fatal "Etersoft Sisyphus Deferred supported only for ALT Sisyphus based systems."
            __epm_addrepo_add_alt_repo "$branch" "https://download.etersoft.ru/pub/ Etersoft/Sisyphus/Deferred_DEVEL" "classic"
            return 0
            ;;
        deferred-beta)
            [ "$DISTRVERSION" = "Sisyphus" ] || fatal "Etersoft Sisyphus Deferred supported only for ALT Sisyphus based systems."
            __epm_addrepo_add_alt_repo "$branch" "https://download.etersoft.ru/pub/ Etersoft/Sisyphus/Deferred_BETA" "classic"
            return 0
            ;; 
        archive)
            if [ "$2" = "sisyphus" ] ; then
                branch="$2"
                shift
            fi
            datestr="$(normalize_date $2)"
    
            __epm_addrepo_add_alt_repo "$branch" "$ALTLINUXPUBURL archive/$branch/date/$datestr" "classic"

            return 0
            ;;
        deffered)
            warning "Did you mean 'deferred'?"
            return 1
            ;;
    esac

    if tasknumber "$repo" >/dev/null ; then
        for i in $repo ; do
            epm repo add "https://git.altlinux.org/tasks/$i/build/repo"
        done
        return
    fi

    case "$repo" in
        c10f*|c9f*|c9)
            __epm_addrepo_main_alt_repo "$repo"
            return
            ;;
        p11|p10|p9|p8)
            __epm_addrepo_main_alt_repo "$repo"
            return
            ;;
        sisyphus|Sisyphus)
            __epm_addrepo_main_alt_repo "$(echo $repo | tr "[:upper:]" "[:lower:]")"
            return
            ;;
    esac

    if echo "$repo" | grep -q "https://" ; then
        local mh="$(echo /usr/lib*/apt/methods/https)"
        assure_exists $mh apt-https
    fi

    # when add correct sources.list string
    if echo "$repo" | grep -q "^rpm " ; then
        __epm_addrepo_to_file /etc/apt/sources.list "$repo"
        return
    fi

    # TODO: rewrite this fallback
    assure_exists apt-repo
    sudocmd apt-repo $dryrun add "$repo"
}


__epm_addrepo_astra()
{
    local repo="$*"

    if [ -z "$repo" ] || [ "$repo" = "--help" ]; then
        message 'Add repo. You can use follow params:
                    distribution component name
                    full sources list line
                    URL version component'
        return
    fi

    local reponame="$(epm print info --repo-name)"

    # keywords
    # https://wiki.astralinux.ru/pages/viewpage.action?pageId=3276859
    case "$1-$reponame" in
        astra-1.7_x86-64)
            # TODO epm repo change http / https
            epm install --skip-installed apt-transport-https ca-certificates || fatal
            if epm repo list "dl.astralinux.ru/astra/stable/1.7_x86-64" ; then
                fatal "Astra repo is already in the list"
            fi
            # https://wiki.astralinux.ru/pages/viewpage.action?pageId=158598882
            epm repo add "deb [arch-=i386] https://dl.astralinux.ru/astra/stable/1.7_x86-64/repository-main/     1.7_x86-64 main contrib non-free"
            epm repo add "deb [arch-=i386] https://dl.astralinux.ru/astra/stable/1.7_x86-64/repository-update/   1.7_x86-64 main contrib non-free"
            epm repo add "deb [arch-=i386] https://dl.astralinux.ru/astra/stable/1.7_x86-64/repository-base/     1.7_x86-64 main contrib non-free"
            epm repo add "deb [arch-=i386] https://dl.astralinux.ru/astra/stable/1.7_x86-64/repository-extended/ 1.7_x86-64 main contrib non-free"
            epm repo add "deb [arch-=i386] https://dl.astralinux.ru/astra/stable/1.7_x86-64/repository-extended/ 1.7_x86-64 astra-ce"
            return
            ;;
        astra-1.8_x86-64)
            # TODO epm repo change http / https
            epm install --skip-installed apt-transport-https ca-certificates || fatal
            if epm repo list "dl.astralinux.ru/astra/stable/$reponame" ; then
                fatal "Astra repo is already in the list"
            fi
            epm repo add "deb [arch-=i386] https://dl.astralinux.ru/astra/stable/$reponame/main-repository/     $reponame main contrib non-free non-free-firmware"
            epm repo add "deb [arch-=i386] https://dl.astralinux.ru/astra/stable/$reponame/extended-repository/ $reponame main contrib non-free non-free-firmware"
            return
            ;;
        astra-orel)
            # TODO epm repo change http / https
            epm install --skip-installed apt-transport-https ca-certificates || fatal
            # https://wiki.astralinux.ru/pages/viewpage.action?pageId=158605543
            epm repo add "deb [arch=amd64] https://dl.astralinux.ru/astra/frozen/$(epm print info -v)_x86-64/$(epm print info --full-version)/repository stable main contrib non-free"
            #epm repo add "deb https://download.astralinux.ru/astra/stable/orel/repository/ orel main contrib non-free"
            return
            ;;
        astra-*)
            fatal 'Unsupported distro version $1-$reponame, see # epm print info output.'
            ;;
    esac

    __epm_addrepo_to_file /etc/apt/sources.list "$repo"
    return
}

__epm_addrepo_alpine()
{
    local repo="$1"
    is_url "$repo" || fatal "Only URL is supported"
    __epm_addrepo_to_file /etc/apk/repositories "$repo"
}

__epm_addrepo_deb()
{
    assure_exists apt-add-repository software-properties-common
    local ad="$DISTRARCH"
    # TODO: move to distro_info
    local nd="$(a= lsb_release -cs)"
    local repo="$*"

    if [ -z "$repo" ] || [ "$repo" = "--help" ]; then
        message 'Add repo. You can use follow params:
                  docker - add official docker repo
                  ppa:<user>/<ppa-name> - add PPA repo
                  distribution component name
                  full sources list line
                  URL version component'
        return
    fi

    # keywords
    case "$1" in
        docker)
            __epm_addkey_deb https://download.docker.com/linux/$PKGVENDOR/gpg "9DC858229FC7DD38854AE2D88D81803C0EBFCD88"
            repo="https://download.docker.com/linux/$PKGVENDOR $nd stable"
            ;;
    esac

    # if started from url, use heroistic
    if echo "$repo" | grep -E -q "^https?://" ; then
        repo="deb [arch=$ad] $repo"
    fi

    if echo "$repo" | grep -q "https://" ; then
        assure_exists /usr/share/doc/apt-transport-https apt-transport-https
        assure_exists /usr/sbin/update-ca-certificates ca-certificates 
    fi

    if [ -d "$repo" ] ; then
        epm repo add "deb file:$repo ./"
        return
    fi

    if is_command apt-add-repository ; then
        # FIXME: quotes in showcmd/sudocmd
        showcmd apt-add-repository "$repo"
        sudorun apt-add-repository "$repo"
        info "Check file /etc/apt/sources.list if needed"
        return
    else
        warning "apt-add-repository is not installed, use file /etc/apt/sources.list directly"
        __epm_addrepo_to_file /etc/apt/sources.list "$repo"
    fi  

}

epm_addrepo()
{
local repo="$*"

case $PMTYPE in
    stplr)
        sudocmd stplr repo add "$@"
        return
        ;;
esac

case $BASEDISTRNAME in
    "alt")
        __epm_addrepo_altlinux "$@"
        return
        ;;
    "astra")
        __epm_addrepo_astra "$@"
        return
        ;;
    "apk")
        __epm_addrepo_alpine "$repo" || return
        ;;
esac

case $PMTYPE in
    apt-dpkg)
        __epm_addrepo_deb "$@"
        ;;
    aptitude-dpkg)
        info "You need manually add repo to /etc/apt/sources.list (TODO)"
        ;;
    yum-rpm)
        assure_exists yum-utils
        __epm_addrepo_rhel "$repo" || return
        sudocmd yum-config-manager --add-repo "$repo"
        ;;
    dnf-rpm)
        __epm_addrepo_rhel "$repo" || return
        sudocmd dnf config-manager --add-repo "$repo"
        ;;
    dnf5-rpm)
        __epm_addrepo_rhel "$repo" || return
        sudocmd dnf config-manager addrepo --from-repofile "$repo"
        ;;
    urpm-rpm)
        sudocmd urpmi.addmedia "$@"
        ;;
    zypper-rpm)
        sudocmd zypper ar "$repo"
        ;;
    emerge)
        sudocmd layman -a "$repo"
        ;;
    pacman)
        info "You need manually add repo to /etc/pacman.conf"
        # Only for alone packages:
        #sudocmd repo-add $pkg_filenames
        ;;
    pisi)
        sudocmd pisi add-repo "$repo"
        ;;
    npackd)
        sudocmd npackdcl add-repo --url="$repo"
        ;;
    winget)
        sudocmd winget source add "$repo"
        ;;
    nix)
        sudocmd nix-channel --add "$repo"
        ;;
    termux-pkg)
        sudocmd pkg install "$repo"
        ;;
    slackpkg)
        info "You need manually add repo to /etc/slackpkg/mirrors"
        ;;
    *)
        fatal 'Have no suitable command for $PMTYPE in epm_addrepo()'
        ;;
esac

}
