#!/bin/bash
# *******************************************************************
# **  @file eisman_update.sh - update local package database
# **
# **  Creation:     2013-01-12 dv
# **  Last update:  $Id: eisman_update.sh 44605 2017-01-19 18:25:32Z hbfl $
# **
# **  Copyright (c) 2013-2017 the eisfair team, team(at)eisfair(dot)org
# **
# **  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.
# *******************************************************************

. /var/install/include/eislib
. /var/install/include/eismanlib


# *******************************************************************
# **  show help on arguments and possible options
# **  @param  n/a
# **  @return n/a
# *******************************************************************

show_help()
{
cat <<EOF

Update local package database

usage:
    eisman update [OPTIONS]

options:
    --help            show this help screen
    --no-progress     don't show progress information and show
                      messages in [mecho --file] format
                      default is [mecho --tty]

EOF
}


# *******************************************************************
# **  show current progress in percent
# **  @param  $1 progress in percent
# **  @return n/a
# *******************************************************************

show_progress()
{
    echo -en "\033[7D"
    printf "[%3d%%] completed!" "${1}"
    echo -en "\033[10D"
}


# *******************************************************************
# **  read index file line by line, check if package meets current system
# **  and fetch the info header file if it is't already in the local cache.
# **  The files are converted into record format!
# **  Further an entry for every package is added to the package database
# **  (without any respect to the fact if it is a new entry or not). Before
# **  doing that, the contents of the package database is cleared.
# **  @param  n/a
# **  @return n/a
# *******************************************************************

update_record_files()
{
    local version
    local invalid_base='no'
    local linecount='0'
    local progress='0'
    local linetotal
    local idx2='0'

    # show what we are doing
    mecho ${output} --info '(Re)building package database ...'

    # init progress display
    if [ "${output}" = "--tty" ]
    then
        echo -n "       "
        show_progress 0
    fi

    # get total number of lines in index
    linetotal=$(wc -l < /tmp/index.txt)

    # overwrite existing database
    > "${EISMAN_PATH}/packages.db.tmp"

    # read index line by line
    while read -r
    do
        local line=${REPLY}

        linecount=$((${linecount} + 1))

        if [ "${line:0:1}" != "#" ]
        then
            local idx=0
            local package=""
            local version=""
            local status=""
            local url=""
            local system=""
            local file=""
            local success=0

            for word in ${line}
            do
                case ${idx} in
                0)  package="${word}"
                    ;;
                1)  version="${word}"
                    ;;
                2)  status="${word}"
                    ;;
                3)  url="${word}"
                    file="${word:0:$((${#word} - 5))}"
                    ;;
                4)  system="${word}"
                    ;;
                esac

                idx=$((${idx} + 1))
            done

            # handle entries missing system tag
            if [ -z "${system}" ]
            then
                system='eisfair-1'
            fi

            if [ "${idx}" -ge 3 ]
            then
                # if base version is invalid, only accept base packages
                if [ "${invalid_base}" = "no" ] ||
                   [ "${package}" = "base" ]
                then
                    # if package name is "base", do not accept "update-"
                    # archives, since they belong to base update installer
                    if [ "${package}" != "base" ] ||
                       [ -z "$(basename ${file} | grep -E "^update-")" ]
                    then
                        if [ $(expr match "${system}" "[a-zA-Z0-9\;-]*${EISMAN_SYSTEM}") -gt 0 ]
                        then
                            local recfile="${EISMAN_PATH}/info/${package}/${version}/$(basename ${file}).rec"

                            if [ ! -d "${EISMAN_PATH}/info/${package}/${version}" -o \
                                 ! -f "${recfile}" ]
                            then
                                if [ "${output}" = "--file" ]
                                then
                                    nonewline='-n'
                                fi
                                echo ${nonewline} "=> Fetching ${package} (${version}) ..."

                                success=0

                                # first download files into temporary locations
                                rm -f /tmp/tmpinfofile$$

                                /usr/local/bin/wget.sh -q -O /tmp/tmpinfofile$$ "${url}"
                                if [ "$?" = "0" ]
                                then
                                    success=1
                                fi

                                # if successful, copy files to correct destination
                                if [ "${success}" = "1" ]
                                then
                                    mkdir -p "${EISMAN_PATH}/info/${package}/${version}"

                                    "${EISMAN_BIN_PATH}/eisman_info_to_db.sh" \
                                        --url     "${file}" \
                                        --name    "${package}" \
                                        /tmp/tmpinfofile$$ \
                                        "${EISMAN_PATH}/info/${package}/${version}/$(basename ${file}).rec"
                                fi

                                rm -f /tmp/tmpinfofile$$

                                # show result ${output} --tty or --file
                                if [ "${success}" = "1" ]
                                then
                                    mecho ${output} --ok
                                else
                                    mecho ${output} --fail
                                fi

                                # show progress of last file fetched
                                if [ "${output}" = "--tty" ]
                                then
                                    progress=$((${linecount} * 100 / ${linetotal}))
                                    show_progress "${progress}"
                                    idx2=0
                                fi
                            else
                                # update file date of recfile
                                touch "${recfile}"

                                # every 25th loop update progress
                                if [ "${output}" = "--tty" ] &&
                                   [ ${idx2} -eq 25 ]
                                then
                                    progress=$((${linecount} * 100 / ${linetotal}))
                                    show_progress "${progress}"
                                    idx2=0
                                fi
                                idx2=$((${idx2} + 1))
                            fi

                            # add file to package database. Make sure that url
                            # is correct even for existing record files
                            if [ -f "${recfile}" ]
                            then
                               local base_url="$(get_base_url ${file})"

                               local iversion=$(sed -n -e "s|.*]version [ ]*\(.*\)|\1|p" \
                                                < "${recfile}")

                                if [ "${iversion}" = "${version}" ]
                                then
                                    sed -e "s|url        .*|url        ${file}|g" \
                                        -e "s|\[[^][]*\]|\[${base_url}]|5"        \
                                        -e "s|\r||g"                              \
                                         < "${recfile}" >> "${EISMAN_PATH}/packages.db.tmp"
                                else
                                    echo "warning: version mismatch! \"${package}\" (${version}) ignored!"
                                fi
                            fi
                        fi
                    fi
                fi
            fi
        elif [ "${line:0:17}" = "# required_base: " ]
        then
            # get eisfair base version
            version=$(cat /etc/version)

            # compare required base version with current version
            if [ "$(${EISMAN_BIN_PATH}/eisman_check_version.sh \
                 --diff "${version}" "${line:17}")" = "old" ]
            then
                # if old, set invalid_base flag
                invalid_base='yes'
            fi
        fi
    done < /tmp/index.txt

    # when done, rename database
    rm -f "${EISMAN_PATH}/packages.db"
    mv "${EISMAN_PATH}/packages.db.tmp" "${EISMAN_PATH}/packages.db"

    # we are done !
    # ${output} --tty
    if [ "${output}" = "--tty" ]
    then
        show_progress 100
        echo
    fi
    mecho ${output} --info 'Done!'
}


# *******************************************************************
# **  clean up all info files older than 90 days. Since the mtime of
# **  all info files existing in the index is set to the current time
# **  upon update, only thme mtime of old info files becomes more and
# **  more out of date.
# **  @param  n/a
# **  @return n/a
# *******************************************************************

clean_up_info_cache()
{
    local files=$(find ${EISMAN_PATH}/info -mtime +90 -name "*.rec")
    local OLDIFS=${IFS}

    IFS="
"
    for file in ${files}
    do
        rm    -f "${file}"
        rmdir -p "$(dirname ${file})" 2> /dev/tmp
    done

    IFS="${OLDIFS}"
}


# *******************************************************************
# **  process replaces entries. Transfer them to outdated.db
# **  @param  n/a
# **  @return n/a
# *******************************************************************

update_outdated_packages()
{
    local name;
    local version;
    local label;
    local value1;
    local value2;
    local status;

    # show what we are doing
    mecho ${output} --info '(Re)building outdated database ...'
    mecho "please wait!"

    # first copy fixed part of outdated.db
    cp  "${EISMAN_PATH}/outdated.inc.db"  "${EISMAN_PATH}/outdated.db"

    # now process replaces entries
    {
        query_package_db      \
            ""                \
            ""                \
            ""                \
            ""                \
            ""                \
            ""                \
            "name|version|status|replaces|-------"   \
            "${EISMAN_PATH}/packages.db" |
                sed -e ":a;N;\$!ba;s/\\n/||/g"  \
                    -e "s/||${EISMAN_SEPARATOR}||/||${EISMAN_SEPARATOR}\\n/g" |
                grep   "||replaces   "                                        |
                sort                                                          |
                sed 's/||/\n/g'                                               |
        while read label value1 value2
        do
            if [ "${label}" = "name" ]
            then
                name="${value1}"

            elif [ "${label}" = "version" ]
            then
                version="${value1}"

            elif [ "${label}" = "status" ]
            then
                if [ "${value1}" = "stable" ]
                then
                    status="s"
                else
                    status="u"
                fi

            elif [ "${label}" = "replaces" ]
            then
                if [ -z "${value2}" ]
                then
                    value2="0.0.0"
                fi

                echo "[outdated][${value1}][${version}][${status}][]name       ${value1}"
                echo "[outdated][${value1}][${version}][${status}][]version    ${value2}"
                echo "[outdated][${value1}][${version}][${status}][]hint       replaced by or included in ${name}"
                echo "[outdated][${value1}][${version}][${status}][]substitude ${name} ${version}"
                echo "[outdated][${value1}][${version}][${status}][]${EISMAN_SEPARATOR}"
            fi
        done
    } >> "${EISMAN_PATH}/outdated.db"

    mecho ${output} --info 'Done!'
}


# *******************************************************************
# **  main script
# **  @param  n/a
# **  @return n/a
# *******************************************************************

main()
{
    # output shows messages in [--tty or--file] format
    # --file ist set with --quiet
    output='--tty'

    while [ "${1:0:2}" = "--" ]
    do
        case ${1} in
        --help)
            show_help
            exit 0
            ;;
        --no-progress|--quiet)
            output='--file'
            shift
            ;;
        *)
            echo "error: unknown option \"${1}\"!" >&2
            echo
            show_help
            exit 1
        esac
    done

    if [ "$#" -gt 0 ]
    then
        echo 'error: invalid number of arguments!' >&2
        echo
        show_help
        exit 1
    fi

    # get index according to configured package sources
    /var/install/bin/get-index --clear

    # create info file path
    mkdir -p "${EISMAN_PATH}/info"

    # read index line by line and fetch new info files
    update_record_files

    # remove info files older than 90 days
    clean_up_info_cache

    # update outdated.db
    update_outdated_packages
}

main "${@}"
