#!/bin/bash
# *******************************************************************
# **  @file eisman_init.sh - build installed package database
# **
# **  Creation:     2013-01-12 dv
# **  Last update:  $Id: eisman_init.sh 44252 2016-12-30 23:14:30Z dv $
# **
# **  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

(Re)build installed package database
Normally this is run only once right after installation of eisman!

usage:
    eisman init [OPTIONS]

options:
    --help      show this help screen

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 all package info files found in /var/install/packages and
# **  add it's contents to the installed database. This process is
# **  normally done once right after installation.
# **  @param  n/a
# **  @return n/a
# *******************************************************************

add_record_files()
{
    # show what we are doing
    mecho --info '(Re)building installed packages database ...'

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

    # search package files and loop over result
    local files=$(ls /var/install/packages/*)
    for file in ${files}
    do
        local package="$(basename "${file}")"
        if [ "${package:$((${#package} - 1)):1}" != "~" ]
        then
            echo "=> Adding ${file} ..."

            success="1"

            # lookup version form package info file
            version=$(grep "<version>" "${file}" |
                      sed -ne 's#[ \t]*</*version>[ \t]*##gp')

            # try to locate a record file already present in info path
            recfile=$(find "/var/lib/eisman/info/${package}/${version}/" \
                      -name "*.rec"                                      \
                      -type f 2> /dev/null |                            \
                      head -n 1)

            # if record file has been found, copy it to installed.db
            if [ -n "${version}" ] && [ -n "${recfile}" ]
            then
                cat "${recfile}" >> "${EISMAN_PATH}/installed.db"
                if [ "$?" != "0" ]
                then
                    success="0"
                fi
            else
                # copy to temporary file
                "${EISMAN_BIN_PATH}/eisman_info_to_db.sh" \
                    --url     "taken_from_${file}" \
                    "${file}" \
                    "/tmp/tmprec$$"
                if [ "$?" != "0" ]
                then
                    success="0"
                fi

                # add entry to package db
                if [ "${success}" = "1" ]
                then
                    cat "/tmp/tmprec$$" >> "${EISMAN_PATH}/installed.db"
                    if [ "$?" != "0" ]
                    then
                        success="0"
                    fi
                fi

                # remove temporary file
                rm -f "/tmp/tmprec$$"
            fi

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

    # we are ready !
    mecho --info "Done!"
}


# *******************************************************************
# **  read all package info files found in /var/install/packages and
# **  check if the package in question is already part of the
# **  installed packages database. If not, it is added
# **  @param  n/a
# **  @return n/a
# *******************************************************************

update_record_files()
{
    # show what we are doing
    mecho --info 'Synchronizing installed packages database ...'

    echo -n "       "
    show_progress 0

    # search package files and loop over result
    local files=$(ls /var/install/packages/*)
    local linetotal=$(echo "${files}" | wc -l)
    local lineidx=0
    local linecount=0
    local progress=0

    for file in ${files}
    do
        lineidx=$((${lineidx} + 1))

        local package="$(basename "${file}")"
        if [ "${package:$((${#package} - 1)):1}" != "~" ]
        then
            local status="$(${EISMAN_BIN_PATH}/eisman_check_version.sh "${package}")"
            if [ "${status}" = "not-installed" ]
            then
                echo "=> Adding ${file} ..."

                success="1"

                # lookup version form package info file
                version=$(grep "<version>" "${file}" |
                          sed -ne 's#[ \t]*</*version>[ \t]*##gp')

                # try to locate a record file already present in info path
                recfile=$(find "/var/lib/eisman/info/${package}/${version}/" \
                          -name "*.rec"                                      \
                          -type f 2> /dev/null |                            \
                          head -n 1)

                # if record file has been found, copy it to installed.db
                if [ -n "${version}" ] && [ -n "${recfile}" ]
                then
                    cat "${recfile}" >> "${EISMAN_PATH}/installed.db"
                    if [ "$?" != "0" ]
                    then
                        success="0"
                    fi
                else
                    # copy to temporary file
                    "${EISMAN_BIN_PATH}/eisman_info_to_db.sh" \
                        --url     "taken_from_${file}" \
                        "${file}" \
                        "/tmp/tmprec$$"
                    if [ "$?" != "0" ]
                    then
                        success="0"
                    fi

                    # add entry to package db
                    if [ "${success}" = "1" ]
                    then
                        cat "/tmp/tmprec$$" >> "${EISMAN_PATH}/installed.db"
                        if [ "$?" != "0" ]
                        then
                            success="0"
                        fi
                    fi

                    # remove temporary file
                    rm -f "/tmp/tmprec$$"
                fi

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

                echo -n "       "
                show_progress "${progress}"
            fi
        fi

        # every 25th loop update progress
        if [ ${lineidx} -eq 25 ]
        then
            linecount=$((${linecount} + 25))

            progress=$((${linecount} * 100 / ${linetotal}))
            show_progress "${progress}"
            lineidx=0
        fi
    done

    show_progress 100
    echo

    # we are ready !
    mecho --info "Done!"
}


# *******************************************************************
# **  perform format update from version 1.0 to 1.1
# **  @param  $1  current version
# **  @return n/a
# *******************************************************************

update_format_from_1_0_to_1_1()
{
    echo "* Update database from version 1.0 to 1.1..."

    # create path if it does not exist
    mkdir -p "${EISMAN_PATH}/installed"

    sed -i -e 's#taken from /var/install#taken_from_/var/install/packages#1' \
       "${EISMAN_PATH}/installed.db"                                                    && \
    sed -i -e 's# #   #1' "${EISMAN_PATH}/installed.db"                                 && \
    sed -i -e 's# #   #1' "${EISMAN_PATH}/packages.db"                                  && \
    find "${EISMAN_PATH}/info" -name "*.rec" -exec sed -i -e 's# #   #1' {} \;          && \
    find "${EISMAN_PATH}/installed" -name "*.rec" -exec                                    \
        sed -i -e 's#taken from /var/install#taken_from_/var/install/packages#1' {} \;  && \
    find "${EISMAN_PATH}/installed" -name "*.rec" -exec sed -i -e 's# #   #1' {} \;

    if [ "$?" -eq "0" ]
    then
        echo "1.1" > "${EISMAN_PATH}/dbversion"

        mecho --ok
    else
        mecho --fail
        exit 1
    fi
}


# *******************************************************************
# **  perform format update from version 1.1 to 1.2
# **  @param  $1  current version
# **  @return n/a
# *******************************************************************

update_format_from_1_1_to_1_2()
{
    echo "* Update database from version 1.1 to 1.2..."

    # remove installed rec files directory, no longer needed
    if [ -d "${EISMAN_PATH}/installed" ]
    then
        rm -rf "${EISMAN_PATH}/installed"
    fi

    if [ "$?" -eq "0" ]
    then
        echo "1.2" > "${EISMAN_PATH}/dbversion"

        mecho --ok
    else
        mecho --fail
        exit 1
    fi
}


# *******************************************************************
# **  update database format. Stay in a loop and perform incremental
# **  updates until the database is in the correct format version
# **  @param  $1  current version
# **  @return n/a
# *******************************************************************

update_database_format()
{
    local version="${1}"

    while true
    do
        case "${version}" in
        "1.0")
            update_format_from_1_0_to_1_1
            ;;
        "1.1")
            update_format_from_1_1_to_1_2
            ;;
        "${EISMAN_DB_VERSION}")
            exit 0
            ;;
        *)
            echo "error: unknown database format \"${version}\"!" >&2
            exit 1
            ;;
        esac

        version=$(cat ${EISMAN_PATH}/dbversion)
    done
}


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

main()
{
    while [ "${1:0:2}" = "--" ]
    do
        case $1 in
        --help)
            show_help
            exit 0
            ;;
        *)
            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

    # make sure packages.db exists!
    touch "${EISMAN_PATH}/packages.db"

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

    # check if database already exists
    if [ ! -f "${EISMAN_PATH}/installed.db" ] ||
       [ ! -f "${EISMAN_PATH}/dbversion" ]
    then
        if [ ! -f "${EISMAN_PATH}/dbversion" ]
        then
            # remove all info files if database doesn't exist
            rm -rf "${EISMAN_PATH}/info"
        else
            # get version from version file
            version=$(cat ${EISMAN_PATH}/dbversion)
            if [ "${version}" != "${EISMAN_DB_VERSION}" ]
            then
                rm -rf "${EISMAN_PATH}/info"
            fi
        fi

        # read files in packages and add them to the database
        add_record_files

        # write version to directory for later version checks
        echo "${EISMAN_DB_VERSION}" > "${EISMAN_PATH}/dbversion"
    else
        # get version from version file
        version=$(cat ${EISMAN_PATH}/dbversion)

        # check if version is valid
        if [ "${version}" = "${EISMAN_DB_VERSION}" ]
        then
            echo 'database is up to date!'
            update_record_files
            exit 0
        else
            # convert database format
            update_database_format "${version}"
            update_record_files
        fi
    fi
}

main "${@}"
