#!/bin/bash
# -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4

# Note:
# This script is sourced by the mpbb wrapper script.
# Do not execute this directly!

install-port-usage() {
    # "prog" is defined in mpbb-help.
    # shellcheck disable=SC2154
    cat <<EOF
usage: $prog [<global opts>] install-port [--source] <port>

Build and install the given port.

Options:

  --source
    Build the port from source, ignoring binary archives.

Run \`$prog help' for global options and a list of other subcommands.
EOF
}

install-port() {
    local args
    parseopt source,mirrordb-url:,mirrordb-credentials-file: "$@" || return
    # $option_source is set by parseopt
    # shellcheck disable=SC2154
    : "${option_source=0}"
    set -- ${args+"${args[@]}"}
    local source_flag
    [[ "${option_source}" -eq 1 ]] && source_flag=s
    local port=${1-}
    if [[ -z "$port" ]]; then
        err "Must specify a port"
        return 1
    fi
    # $option_log_dir is set in mpbb
    # shellcheck disable=SC2154
    local log_port_contents="${option_log_dir}/port-contents.txt"
    local log_port_stats="${option_log_dir}/port-statistics.txt"
    local log_port_main="${option_log_dir}/main.log"
    local log_subports_progress="${option_log_dir}/ports-progress.txt"

    # prepare the log files and make sure to start with empty ones
    mkdir -p "${option_log_dir}"
    #> "$log_port_contents"
    > "$log_port_stats"

    rm -f "${option_work_dir}/requested_port"

    # $option_prefix and $thisdir are set in mpbb
    # shellcheck disable=SC2154
    local imagepath=$("${option_prefix}/bin/port-tclsh" "${thisdir}/tools/archive-path.tcl" "$@")
    if [[ -f "$imagepath" || -d "${imagepath%.*}" ]]; then
        echo "$* already installed, nothing to do"
        # log: summary for the portwatcher
        echo "Building '$port' ... [OK]" >> "$log_subports_progress"
        echo "$@" >> "${option_work_dir}/requested_port"
        return 0
    elif [[ -n "$("${option_prefix}/bin/port" -q installed "$@")" ]]; then
        # archive name differs, supported_archs probably changed
        "${option_prefix}/bin/port" -fv uninstall "$@"
    fi

    local time_start
    local time_stop
    time_start=$(date +%s)
    FETCHFAILED=0
    # $option_prefix is set in mpbb
    # shellcheck disable=SC2154
    if ! "${option_prefix}/bin/port" -d fetch "$@"; then
        echo "Fetch of '$port' failed."
        if [ -n "$option_mirrordb_url" ]; then
            echo "Waiting for '$port' to be mirrored."
            if "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/wait-for-mirror.tcl" \
                    "$option_mirrordb_url" "$option_mirrordb_credentials_file" "$port"; then
                echo "Mirroring of '$port' done. Retrying fetch."
                if ! "${option_prefix}/bin/port" -d fetch "$@"; then
                    echo "Second fetch of '$port' failed."
                    FETCHFAILED=1
                fi
            else
                echo "Timed out waiting for '$port' to be mirrored."
                FETCHFAILED=1
            fi
        else
            FETCHFAILED=1
        fi
        if [ "$FETCHFAILED" -eq 1 ]; then
            # log: summary for the portwatcher
            echo "Fetching '$port' ... [ERROR] maintainers: $(get-maintainers "$port")." >> "$log_subports_progress"
            # Do not add to failcache. This could be a temporary problem that will
            # be resolved once the file appears on mirrors.
            return 1
        fi
    fi
    # $option_prefix is set in mpbb
    # shellcheck disable=SC2154
    if ! "${option_prefix}/bin/port" -d checksum "$@"; then
        echo "Checksum of '$port' failed."
        # log: summary for the portwatcher
        echo "Checksum '$port' ... [ERROR] maintainers: $(get-maintainers "$port")." >> "$log_subports_progress"
        # Do not add to failcache. This could be a temporary network or server problem.
        # Delete the files so they will be re-fetched next time (hopefully correctly).
        "${option_prefix}/bin/port" -d clean --dist "$@"
        return 1
    fi
    # $option_prefix is set in mpbb
    # shellcheck disable=SC2154
    if "${option_prefix}/bin/port" "-dkn${source_flag}" install --unrequested "$@"; then
        # Remove failcache if it exists
        failcache_success "$@"
        if [ $? -ne 0 ]; then
            err "failcache_success" "$@" "failed."
            return 1
        fi
    else
        echo "Build of '$port' failed."
        # log: summary for the portwatcher
        echo "Building '$port' ... [ERROR] maintainers: $(get-maintainers "$port")." >> "$log_subports_progress"
        # update failcache
        failcache_failure "$@"
        if [ $? -ne 0 ]; then
            err "failcache_failure" "$@" "failed."
            return 1
        fi
        return 1
    fi
    time_stop=$(date +%s)

    # log: summary for the portwatcher
    echo "Building '$port' ... [OK]" >> "$log_subports_progress"

    # log: contents
    "${option_prefix}/bin/port" -q contents "$port" > "$log_port_contents"

    # log: statistics
    echo "time:    $((time_stop - time_start))s" >> "$log_port_stats"

    local port_workdir
    local port_workdir_size=""
    local port_destdir_size=""
    local print_arg_workdir="ERROR"
    local print_arg_destdir="ERROR"
    # First, compute port_workdir_size and port_destdir_size
    port_workdir=$("${option_prefix}/bin/port" work "$port")
    if [ -n "$port_workdir" ]; then
        port_workdir_size=$(du -ks "$port_workdir" | sed 's/^ *//' | tr '\t' '\n' | head -n 1)
        if [ $? -eq 0 ] && [ -n "$port_workdir_size" ]; then
            print_arg_workdir="${port_workdir_size}k"
        fi

        local port_destdir="$port_workdir/destroot"
        # if we arrive here, 'port work $port' was successful, so we're
        # at least going to print 'destdir: -'
        print_arg_destdir="-"
        if [ -d "$port_destdir" ]; then
            port_destdir_size=$(du -ks "$port_destdir" | sed 's/^ *//' | tr '\t' '\n' | head -n 1)
            if [ $? -eq 0 ] && [ -n "$port_destdir_size" ]; then
                print_arg_destdir="${port_destdir_size}k"
            fi
        fi
    fi
    # Then print them, or on error (or if destdir doesn't exist), print the
    # appropriate message
    echo "workdir: $print_arg_workdir" >> "$log_port_stats"
    echo "destdir: $print_arg_destdir" >> "$log_port_stats"

    # log: main.log
    local port_mainlog
    port_mainlog=$("${option_prefix}/bin/port" logfile "$port")
    if [ $? -eq 0 ] && [ -f "$port_mainlog" ]; then
        cp -f "$port_mainlog" "$log_port_main"
    fi

    echo "$@" >> "${option_work_dir}/requested_port"
}
