#!/bin/sh

# findex - (re)generate 'index.html' for some or all repos, except hidden ones.
# Permalink: https://kuu.se/fossil/nest.cgi/doc/tip/index.html

# If given as a list of repos from the command line, regenerate index.html, including only the repo list.
# If -a|--add flag is used, add repos list given from command line to index.html, sort list of repos, but do not modify existing repos list in index.html
# In both cases, -v|--verify flag may be used to check if the repos exist.
# If no repos are given as command line arguments, include all existing repos in index.html, using 'flist' and 'fhide'. Neither the --add nor the --verify flag make sense in this case.

# Normally, this script is called by 'fsetup' when adding (or hiding) a repos.
# In that case, the repos list has already been verified, so the '-v|--verify' flag is not used, to avoid executing the (slow) verification twice.

# Dir where this script is running
SCRIPT_NAME=`readlink -f "$0"`
SCRIPT_DIR=`dirname "${SCRIPT_NAME}"`

REPOS_LIST_CLI=
REPOS_LIST_SERVER=
REPOS_LIST_HIDDEN=
REPOS_LIST=
FLAG_ADD=
FLAG_VERIFY=
DO_NOTHING=0
ROOT_REPOS=nest

# Usage
usage()
{
cat << EOF

Usage:
  $0
  $0 [-a|--add] [-v|--verify] [<respository-name> [<respository-name2>] ...]
  $0 -h|--help
EOF
exit 1
}

# Returns an list of any existing repos, empty list if no repos exist.
check_for_non_existing_repos()
{
    MISSING_REPOS=
    for r_cli in $@; do
        printf "Verify: Check for existing repos '${r_cli}'...\t"
        echo "${REPOS_LIST_SERVER}" | grep -q "${r_cli}"
        if [ $? -eq 1 ];then
            MISSING_REPOS="${MISSING_REPOS} ${r_cli}"
            printf "ERROR\n"
        else
            printf "OK\n"
        fi
    done
    if [ -z "${MISSING_REPOS}" ];then
        return 0
    else
        printf "\nERROR: Missing repo(s): %s\n" "${MISSING_REPOS}"
        return 1
    fi
}

# Verify that repos exist
verify()
{
    printf "Verify repos:\n"
    printf "=============\n"
    printf "Verify: Fetch repos list from server...\t\t"
    REPOS_LIST_SERVER=`"${SCRIPT_DIR}/flist"`
    if [ -z "$REPOS_LIST_SERVER" ];then
        printf "\nERROR:\n"
        printf "Could not fetch repos list from server.\n"
        printf "Internet or server connection problem?\n"
        exit 1
    fi
    printf "OK\n"
    check_for_non_existing_repos ${REPOS_LIST_CLI}
    if [ $? -eq 1 ];then
        printf "\nTIP:\n"
        printf "Run 'flist' to see all existing repositories.\n"
        usage;exit 1
    fi
}

# Remove hidden repositories from list
exclude_hidden_repos_from_list()
{
    printf "Fetch repos list from server...\t\t"
    REPOS_LIST_SERVER=`"${SCRIPT_DIR}/flist"`
    num_repos=`echo "$REPOS_LIST_SERVER" | wc -w`
    if [ -z "$REPOS_LIST_SERVER" ];then
        printf "\nERROR:\n"
        printf "Could not fetch repos list from server.\n"
        printf "Internet or server connection problem?\n"
        exit 1
    fi
    printf "OK (%s repos)\n" "$num_repos"
    printf "Fetch hidden repos list...\t\t"
    REPOS_LIST_HIDDEN=`"${SCRIPT_DIR}/fhide"`
    num_hidden=`echo "$REPOS_LIST_HIDDEN" | wc -w`
    printf "OK (%s hidden repos)\n" "$num_hidden"
    REPOS_LIST=
    # Loop through repos
    for r in ${REPOS_LIST_SERVER}; do
        echo ${REPOS_LIST_HIDDEN} | grep -q ${r}
        if [ $? -ne 0 ];then
            REPOS_LIST="${REPOS_LIST} ${r}"
        fi
    done
}

# Remove 'nest' (this repository) from list
exclude_root_repos_from_list()
{
    REPOS_LIST_UPDATED=
    # Loop through repos
    for r in ${REPOS_LIST}; do
        if [ "${r}" != $ROOT_REPOS ];then
            REPOS_LIST_UPDATED="${REPOS_LIST_UPDATED} ${r}"
        fi
    done
    REPOS_LIST="$REPOS_LIST_UPDATED"
}

# Cleanup (temporary files)
cleanup()
{
    rm -f "${LOCAL_INDEX_FILE_BUP}"
}

# Check for command-line options
for arg in $@; do
    case "$arg" in
        -h|--help)
            usage
        ;;
        -a|--add)
            FLAG_ADD="$arg"
        ;;
        -v|--verify)
            FLAG_VERIFY="$arg"
        ;;
        -*)
            printf "\nERROR: Unknown option '$arg'.\n"; usage
        ;;
        *)
            REPOS_LIST_CLI="${REPOS_LIST_CLI} $1"
            ;;
    esac
    shift
done
set -- ${REPOS_LIST_CLI}

REMOTE_SERVER=redantig@kuu.se
REMOTE_PORT=7822
REMOTE_REPOS_DIR=/home/redantig/fossil/repos
REMOTE_HIDDEN_FILE="${REMOTE_REPOS_DIR}"/.hidden
SSH_COMMAND=ssh
if [ ${REMOTE_PORT} -ne 22 ];then
    SSH_COMMAND="ssh -p ${REMOTE_PORT}"
fi
LOCAL_BIN_DIR=`dirname \`readlink -f $0\``
LOCAL_REPOS_DIR=`dirname $LOCAL_BIN_DIR`
LOCAL_INDEX_FILE=$LOCAL_REPOS_DIR/index.html
LOCAL_INDEX_FILE_BUP=$LOCAL_REPOS_DIR/index.html.BUP
INDEX_BEGIN_TAG='<!-- fsetup list BEGIN -->'
INDEX_END_TAG='<!-- fsetup list END -->'

printf "Check for 'fossil' executable...\t"
which fossil > /dev/null 2>&1
RC=$?
if [ ${RC} -ne 0 ];then
    printf "ERROR\nCould not find 'fossil' executable, required by this script.\n"
    exit 1
fi
printf "OK\n"

printf "%s\n" "Run 'fossil update' to get latest 'index.html':"
### %%% TODO: fossil update --dry-run TO CHECK $? BEFORE GETTING LATEST VERSION OF index.html
fossil update

# Check for existing index.html
if [ ! -e "${LOCAL_INDEX_FILE}" ];then
    printf "\nERROR:\nMissing 'index.html' file.\nPlease create '$LOCAL_INDEX_FILE' and run this script again.\nTip:\nwget https://kuu.se/fossil/nest.cgi/doc/tip/index.html -o $LOCAL_INDEX_FILE\n"; exit 1
fi
# Check for existing start tag in index.html
grep -q "${INDEX_BEGIN_TAG}" "${LOCAL_INDEX_FILE}"
if [ $? -ne 0 ];then
    printf "\nERROR:\nMissing '${INDEX_BEGIN_TAG}' tag in '${LOCAL_INDEX_FILE}'.\nPlease insert this tag before the list of existing repos and run this script again.\n"; exit
fi
# Check for existing end tag in index.html
grep -q "${INDEX_END_TAG}" "${LOCAL_INDEX_FILE}"
if [ $? -ne 0 ];then
    printf "\nERROR:\nMissing '${INDEX_END_TAG}' tag in '${LOCAL_INDEX_FILE}'.\nPlease insert this tag after the list of existing repos and run this script again.\n"; exit
fi

# Check for add flag
if [ -n "${FLAG_ADD}" ]; then
    # If args were given but without repos names, exit with error
    if [ -z "${REPOS_LIST_CLI}" ]; then
        printf "\nERROR: Missing repository argument.\n"; usage
    fi
fi

# Check for verify flag
if [ -n "${FLAG_VERIFY}" ]; then
    # If args were given but without repos names, exit with error
    if [ -z "${REPOS_LIST_CLI}" ]; then
        printf "\nERROR: Missing repository argument.\n"; usage
    fi
    verify
fi

# If not given from command line, get repos list from server
if [ -n "${REPOS_LIST_CLI}" ];then
    REPOS_LIST="${REPOS_LIST_CLI}"
else
    exclude_hidden_repos_from_list
fi

# Exclude 'nest' (this repos) from list
exclude_root_repos_from_list

# Get repos list in existing index.html 
printf "Prepare HTML line template...\t\t"
###HTML_HREF_LIST=`sed -n '1h;1!H;${;g;s/.*\('"${INDEX_BEGIN_TAG}"'.*'"${INDEX_END_TAG}"'\).*/\1/p;}' $LOCAL_INDEX_FILE | grep -v "${INDEX_BEGIN_TAG}\|${INDEX_END_TAG}"`
HTML_BEFORE_HREF_LIST=`sed -n '1h;1!H;${;g;s/\(.*'"${INDEX_BEGIN_TAG}"'\).*/\1/p;}' $LOCAL_INDEX_FILE`
HTML_HREF_LIST=`sed -n '1h;1!H;${;g;s/.*'"${INDEX_BEGIN_TAG}"'\(.*\)'"${INDEX_END_TAG}"'.*/\1/p;}' $LOCAL_INDEX_FILE`
HTML_AFTER_HREF_LIST=`sed -n '1h;1!H;${;g;s/.*'"${INDEX_BEGIN_TAG}"'.*\(^[[:space:]]*'"${INDEX_END_TAG}"'.*\)/\1/p;}' $LOCAL_INDEX_FILE`
HTML_LINE_TMPL=`printf "%s\n" "${HTML_HREF_LIST}"|grep href | head -1`
HTML_LINE_TMPL=`printf "%s\n" "${HTML_LINE_TMPL}" | sed 's|\(href="\)\(.*\)\(">\)\(.*\)\(</a>\)|\1REPOS_HREF_CGI\3REPOS_NAME\5|'`
printf "OK\n"

# If '--add' flag, add command-line list to existing list
printf "Regenerate HTML list...\t\t\t"
if [ -n "${FLAG_ADD}" ]; then
    # Add new repo
    for r_cli in $REPOS_LIST; do
        HTML_LINE=`printf "%s\n" "${HTML_LINE_TMPL}"  | sed "s|REPOS_HREF_CGI\(.*\)REPOS_NAME|${r_cli}.cgi\1${r_cli}|"`
        HTML_HREF_LIST=`printf "%s\n%s\n" "${HTML_HREF_LIST}" "${HTML_LINE}"`
    done
else
    # Regenerate either from server list or from command line
    HTML_HREF_LIST=
    for r_cli in $REPOS_LIST; do
        HTML_LINE=`printf "%s\n" "${HTML_LINE_TMPL}"  | sed "s|REPOS_HREF_CGI\(.*\)REPOS_NAME|${r_cli}.cgi\1${r_cli}|"`
        if [ -z "${HTML_HREF_LIST}" ];then
            HTML_HREF_LIST=`printf "%s\n" "${HTML_LINE}"`
        else
            HTML_HREF_LIST=`printf "%s\n%s\n" "${HTML_HREF_LIST}" "${HTML_LINE}"`
        fi
    done
fi
printf "OK\n"
printf "Sort HTML list...\t\t\t"
HTML_HREF_LIST=`printf "%s" "${HTML_HREF_LIST}" | sort`
printf "OK\n"

# echo "$HTML_HREF_LIST" | while IFS= read -r line ; do echo "LINE=$line"; done

# Write generated file to index backup file.
printf "%s\n%s\n%s\n" "$HTML_BEFORE_HREF_LIST" "$HTML_HREF_LIST" "$HTML_AFTER_HREF_LIST" > "${LOCAL_INDEX_FILE_BUP}"

# If original and backup files do not differ, do nothing and exit.
# diff man page:
# Exit status is 0 if inputs are the same, 1 if different, 2 if trouble.
printf "Check if index file was modified...\t"

diff -q "${LOCAL_INDEX_FILE}" "${LOCAL_INDEX_FILE_BUP}" > /dev/null 2>&1
RC=$?

case ${RC} in
    0)
        printf "SKIP\n"
        printf "New and existing index files are identical, no need to update index file.\nBye\n";;
    1)
        cp "${LOCAL_INDEX_FILE_BUP}" "${LOCAL_INDEX_FILE}"
        printf "%s\n" "OK";;
    *)
        printf "ERROR %s\nAn unexpected error occurred when comparing new and existing index files.\nBye\n" "${RC}";;
esac
cleanup
if [ $RC -ne 1 ];then
    exit $RC
fi

printf "%s\n" "Index files has been updated, commit the changes:"
printf "%s\n" "-------------------------------------------------"
### %%% TODO: remove possible CRLF from index.html before commit
fossil commit -m "Updated index file"
printf "%s\n%s\n" "Updated index file successfully." "Bye"
exit 0
