#!/bin/sh
#
# Copyright (c) Aaron LI <aly@aaronly.me>
# MIT License
#
# Tool to update a DragonFly BSD system using binary
# releases or snapshot builds.
#

set -e

DEBUG=        # Disable debug
DEBUG=true    # Enable debug

NAME="dfly-update"
VERSION="0.?.?"
PROGRAM="${0##*/}"
TOOLDIR="${0%/*}"
PREFIX="${PREFIX:-${TOOLDIR}}"
CONFIGFILE="${PREFIX}/${NAME}.conf"

#
# Error Codes
#

EC_OS=5
EC_CONFIGFILE=10
EC_CONFIG=11


#
# Default Configurations
#

# Base URL to Remote DragonFly BSD images
URL_BASE="https://mirror-master.dragonflybsd.org"
URL_DEVELOPMENT="${URL_BASE}/snapshots/x86_64/images"
URL_RELEASE="${URL_BASE}/iso-images"

# Default to track the same branch as the installed system
UPDATE_BRANCH=


#
# Helper Functions
#

error() {
    echo "ERROR: $@" >&2
}

check_os() {
    local os
    os=$(uname -s)
    if [ "${os}" != "DragonFly" ]; then
        error "Not a DragonFly BSD system!"
        exit ${EC_OS}
    fi
}

# Load configurations from file
load_config() {
    local configfile tmpcfg
    configfile="$1"
    if [ ! -r "${configfile}" ]; then
        error "Cannot read configuration file: ${configfile}"
        exit ${EC_CONFIGFILE}
    fi
    # Filter out only valid configurations to be secure
    tmpcfg=$(mktemp)
    egrep '^[^ ]*=[^;&]*' ${configfile} > ${tmpcfg}
    . ${tmpcfg}
    rm ${tmpcfg}
}

# Get the branch of the installed system
# * DEVELOPMENT
# * RELEASE
get_local_branch() {
    check_os || exit $?
    uname -r | awk -F'-' '{ print $2 }'
}

# Get the version of local installed system
get_local_version() {
    local version
    check_os
    version=$(uname -v | awk '{ print $2 }')
    echo "${version}" | awk -F'-' '{ print $1 }' | tr -d 'v'
}

# Get the latest remote system image
# Returns:
# "_filename=<latest.iso/img>; _md5=<md5/of/latest.iso/img>"
get_latest_image() {
    local branch local url_checksum tmpchecksum
    local latest_filename latest_md5 line
    branch="$1"
    if [ "${branch}" = "DEVELOPMENT" ]; then
        url_checksum="${URL_DEVELOPMENT}/CHECKSUM.MD5"
    else
        url_checksum="${URL_RELEASE}/md5.txt"
    fi
    tmpchecksum=$(mktemp)
    echo "Fetch remote systems checksum: ${url_checksum}" >&2
    fetch -o ${tmpchecksum} "${url_checksum}"
    if [ "${branch}" = "DEVELOPMENT" ]; then
        line=$(fgrep '.img.bz2' ${tmpchecksum} | tail -n 1)
    else
        line=$(fgrep '.img.bz2' ${tmpchecksum} | \
               fgrep -v 'gui-' | tail -n 1)
    fi
    latest_filename=$(echo "${line}" | awk -F'[()]' '{ print $2 }')
    latest_md5=$(echo "${line}" | awk '{ print $5 }')
    rm ${tmpchecksum}
    echo "_filename='${latest_filename}'; _md5='${latest_md5}'"
}

# Extract the version from image filename
get_version_filename() {
    local branch filename version
    branch="$1"
    filename="$2"
    if [ "${branch}" = "DEVELOPMENT" ]; then
        version=$(echo "${filename}" | cut -d'-' -f5 | cut -d'.' -f1-5)
    else
        version=$(echo "${filename}" | cut -d'-' -f3 | cut -d'_' -f1)
        version=${version#v}
    fi
    echo ${version}
}

# Compare between two version strings
# Parameters: ver1 ver2
# Returns values:
# * 0 : ver1 = ver2
# * 1 : ver1 < ver2
# * 2 : ver1 > ver2
compare_version() {
    lcal ver1 ver2 ver_low
    ver1="$1"
    ver2="$2"
    ver_low=$(echo -e "${ver1}\n${ver2}" | sort -V | head -n 1)
    if [ "${ver1}" = "${ver2}" ]; then
        echo 0
    elif [ "${ver1}" = "${ver_low}" ]; then
        echo 1
    else
        echo 2
    fi
}


#
# Sub-command functions
#

cmd_version() {
    cat <<_EOF_
v${VERSION}
Aaron LI <aly@aaronly.me>
https://github.com/liweitianux/dfly-update
_EOF_
}

cmd_usage() {
    cat <<_EOF_
dfly-update - DragonFly BSD update tool using binary release/snapshots

Usage:
    help
        Show this help.
    version
        Show version information of this tool.
    status
        Show local installed system version and remote available version.
_EOF_
    echo
    cmd_version
}

cmd_status() {
    local branch version branch_remote version_remote has_update
    branch=$(get_local_branch)
    version=$(get_local_version)
    if [ -z "${UPDATE_BRANCH}" ]; then
        branch_remote=${branch}
    else
        branch_remote=${UPDATE_BRANCH}
    fi
    eval $(get_latest_image ${branch_remote}) || exit $?
    version_remote=$(get_version_filename ${branch_remote} ${_filename})
    cat <<_EOF_
Local installed system:
    branch: ${branch}
    version: ${version}

Remote available system:
    branch: ${branch_remote}
    version: ${version_remote}

_EOF_

    has_update=$(compare_version ${version} ${version_remote})
    if [ ${has_update} -eq 0 ]; then
        echo "^_^ Your DragonFly is up-to-date ^_^"
    elif [ ${has_update} -eq 1 ]; then
        echo "!!! Your DragonFly needs update !!!"
    else
        echo "??? Your DragonFly is newer than remote ???"
    fi
}

cmd_extension_or_status() {
    case "$1" in
        "")
            cmd_status
            ;;
        *)
            echo "TODO..."
            ;;
    esac
}

#
# Main
#

# Load configurations
[ -r "${CONFIGFILE}" ] && load_config ${CONFIGFILE}

COMMAND="$1"
case "${COMMAND}" in
    help|--help|-h)
        shift
        cmd_usage
        ;;
    version|--version|-V)
        shift
        cmd_version
        ;;
    status)
        shift
        cmd_status "$@"
        ;;
    *)
        cmd_extension_or_status "$@"
        ;;
esac

exit 0