#!/bin/sh
#
# Copyright (C) 2017-2018, 2020  Etersoft
# Copyright (C) 2017-2018, 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_helper epm-sh-altlinux
load_helper epm-assure
load_helper epm-status

[ -n "$EPM_REPACK_SCRIPTS_DIR" ] || EPM_REPACK_SCRIPTS_DIR="$CONFIGDIR/repack.d"

__epm_have_repack_rule()
{
    # FIXME: use real way (for any archive)
    local pkgname="$(epm print name for package "$1" 2>/dev/null)"
    local repackcode="$EPM_REPACK_SCRIPTS_DIR/$pkgname.sh"
    [ -s "$repackcode" ]
}

__epm_check_repack_rule()
{
    # skip repacking on non ALT systems
    [ "$BASEDISTRNAME" = "alt" ] || return 1

    local i
    for i in $* ; do
        # skip for packages built with repack
        epm_status_repacked "$i" && return 1

        __epm_have_repack_rule "$i" || return 1
    done
    return 0
}

__epm_check_if_needed_repack()
{
    __epm_check_repack_rule "$@" || return
    local pkgname="$(epm print name for package "$1")"
    warning 'There is repack rule for $pkgname package. It is better install this package via epm install --repack or epm play.'
}

# make light and independent copy to target
# note: target file can be read only
# args: abs_source target
__epm_repack_copy()
{
    local abspkg="$1"
    local target="$2"

    # skip if source and target are the same file
    [ "$abspkg" -ef "$target" ] && return 0

    # if source file is not writable, try CoW or fallback to ordinal copy
    #if [ ! -w "$abspkg" ] ; then
    #    cp --reflink=auto $verbose $abspkg $target 2>/dev/null && return
    #    return
    #fi

    # If we can make symlink, we don't need CoW and hardlink
    ## firstly try CoW
    #cp --reflink=always $verbose $abspkg $target 2>/dev/null && return
    # after failed CoW remained empty file
    #rm $target
    ## next try create hardlink
    #cp -l $verbose $abspkg $target 2>/dev/null && return
    # next try create symlink
    cp -s $verbose $abspkg $target 2>/dev/null && return
    # just make copy as fallback
    cp $verbose $abspkg $target && return
    fatal "Can't copy $abspkg to $target"
}


# arg: rpm or deb
# fills split_replaced_pkgs with packages of that type
__epm_split_by_pkg_type()
{
    local type="$1"
    shift

    split_replaced_pkgs=''

    for pkg in "$@" ; do
        [ "$(get_package_type "$pkg")" = "$type" ] || return 1
        [ -e "$pkg" ] || fatal "Can't read $pkg"
        split_replaced_pkgs="$split_replaced_pkgs $pkg"
    done

    [ -n "$split_replaced_pkgs" ]
}


__check_stoplist()
{
    local pkg="$1"
    local alf="$CONFIGDIR/repackstoplist.list"
    [ -s "$alf" ] || return 1
    [ -n "$pkg" ] || return 1
    grep -E -q "^$1$" $alf
}

__convert_packrule_to_regexp()
{
    local tmpalf
    tmpalf="$(mktemp)" || fatal
    # copied from eget's filter_glob
    # check man glob
    # remove commentы and translate glob to regexp
    grep -v "^[[:space:]]*#" "$1" | grep -v "^[[:space:]]*$" | sed -e "s|\*|.*|g" -e "s|?|.|g" >$tmpalf
    echo "$tmpalf"
}

# fill __PACKRULE if $1 in packrules.list
__check_packrule()
{
    local pkg="$1"
    local alf="$CONFIGDIR/packrules.list"
    [ -s "$alf" ] || return 1
    [ -n "$pkg" ] || return 1

    local tmpalf=$(__convert_packrule_to_regexp "$alf")
    remove_on_exit $tmpalf
    __PACKRULE="$(awk -v s="$pkg" 'BEGIN{FS=" "} s ~ $2  {print $1}' "$tmpalf")"
    rm $tmpalf
    [ -n "${__PACKRULE}" ]
    return
}

# arg: <package file>
# sets:
#   alpkg      - resulted package file name in the current dir
#   SUBGENERIC - name of generic file's extension
__prepare_source_package()
{
    local pkg="$1"

    alpkg=$(basename $pkg)
    pkgversion="$2"

    # TODO: use func for get name from deb pkg
    # TODO: epm print name from deb package
    local pkgname="$(echo $alpkg | sed -e "s|_.*||")"

    # TODO: use stoplist only for deb?
    [ -z "$force" ] && __check_stoplist $pkgname && fatal 'Please use official package instead of $alpkg repacking (It is not recommended to use --force to skip this checking.'

    SUBGENERIC=''

    if rhas "$alpkg" "\.(rpm|deb)$" ; then
        # skip packing for supported directly: rpm and deb
        return
    fi

    # convert tarballs to tar (for alien)
    load_helper epm-pack

    # they will fill $returntarname

    if __check_packrule "$alpkg" ; then
        __epm_pack_run_handler ${__PACKRULE} "$pkg"
    elif rihas "$alpkg" "\.AppImage$" ; then
        # big hack with $pkg_urls_downloaded (it can be a list, not a single url)
        __epm_pack_run_handler generic-appimage "$pkg" "$pkgversion" "$pkg_urls_downloaded"
        SUBGENERIC='appimage'
    elif rhas "$alpkg" "\.snap$" ; then
        __epm_pack_run_handler generic-snap "$pkg" "$pkgversion"
        SUBGENERIC='snap'
    else
        __epm_pack_run_handler generic-tar "$pkg" "$pkgversion"
        SUBGENERIC='tar'
    fi

    # it is possible there are a few files, we don't support it
    [ -s "$returntarname" ] || fatal 'Can'\''t read result from pack: $returntarname is not a readable file.'

    alpkg=$(basename $returntarname)
    # FIXME: looks like a hack with current dir
    if [ "$(pwd)" != "$(dirname "$returntarname")" ] ; then
        cp $verbose $returntarname $alpkg
        [ -r "$returntarname.eepm.yaml" ] && cp $verbose $returntarname.eepm.yaml $alpkg.eepm.yaml
    fi
}



# used in epm install
__epm_repack_single()
{
    local pkg="$1"
    local packversion="$2"
    local packrelease="$3"
    case $PKGFORMAT in
        rpm)
            load_helper epm-repack-rpm
            if [ "$BASEDISTRNAME" = "alt" ] ; then
                if epm status --original "$pkg" ; then
                    fatal_warning "Repacking package $pkg from ALT repository is dangerous and forbidden (see https://bugzilla.altlinux.org/56355)."
                fi
                if epm status --repacked "$pkg" ; then
                    fatal_warning "Repacking already repacked package $pkg is uselessly."
                fi
            fi
            __epm_repack_to_rpm "$pkg" "$packversion" "$packrelease" || return
            ;;
        deb)
            # repack via rpm if source is not deb or we have rpm rule for the package
            if __epm_have_repack_rule "$pkg" || ! rhas "$pkg" "\.deb$" ; then
                # we have repack rules only for rpm, so use rpm step in any case
                load_helper epm-repack-rpm
                load_helper epm-repack-deb
                __epm_repack_to_rpm "$pkg" "$packversion" "$packrelease" || return
                [ -n "$repacked_pkg" ] || return
                __epm_repack_to_deb $repacked_pkg || return
            else
                load_helper epm-repack-deb
                __epm_repack_to_deb "$pkg" || return
            fi
            ;;
        pkg.tar.xz)
            load_helper epm-repack-arch
            __epm_repack_to_arch "$pkg" || return
            ;;
        *)
            fatal '$PKGFORMAT is not supported for repack yet'
            ;;
    esac

    return 0
}

# fill repacked_pkgs
__epm_repack()
{
    local pkg
    repacked_pkgs=''
    local packversion="${EPM_REPACK_VERSION:-}"
    local packrelease="${EPM_REPACK_RELEASE:-}"

    print_sha256sum $pkg_files

    for pkg in $* ; do
        __epm_repack_single "$pkg" "$packversion" "$packrelease" || fatal 'Error with $pkg repacking.'
        [ -n "$repacked_pkgs" ] && repacked_pkgs="$repacked_pkgs $repacked_pkg" || repacked_pkgs="$repacked_pkg"
    done
}


__epm_repack_if_needed()
{
    # return 1 if there is a package in host package format
    __epm_split_by_pkg_type $PKGFORMAT "$@" && return 1

    __epm_repack "$@"
    return 0
}

epm_repack()
{
    # if possible, it will put pkg_urls into pkg_files and reconstruct pkg_filenames
    if [ -n "$pkg_urls" ] ; then
        load_helper epm-download
        __download_pkg_urls
        pkg_urls=
    fi

    [ -n "$pkg_names" ] && warning 'Can'\''t find $pkg_names files'
    [ -z "$pkg_files" ] && info "Empty repack list was skipped" && return 22
    if __epm_repack $pkg_files && [ -n "$repacked_pkgs" ] ; then
        if [ -n "$install" ] ; then
            epm install $repacked_pkgs
            return
        fi

        cp $repacked_pkgs "$EPMCURDIR"
        if [ -z "$quiet" ] ; then
            echo
            message "Adapted packages:"
            for i in $repacked_pkgs ; do
                echo "    $EPMCURDIR/$(basename "$i")"
            done
        fi
    fi

}
