#!/usr/bin/env bash

# shellcheck source=/dev/null
source /etc/os-release

conf_file=/etc/dnf/plugins/local.conf
# Do not enable unless explicitly instructed to enable.
main_enabled="false"
main_archdirs="false"
main_repodir=""
createrepo_enabled="false"
refresh_file=/run/dnf-plugin-local.refresh

exec 4>&1
exec 5>&2

set -eEuo pipefail

log() {
    logger -t dnf-local-cache-actions "$*"
}

log "Invoked with options: $*"

temp="$(getopt -o h --long action:,arch:,help,location:,repository: -n dnf-local-cache-actions -- "$@")" || {
    log "Error processing options: $?"
    exit 1
}

eval set -- "${temp}"

usage="dnf-local-cache-actions [-h|--help] <command>"

while [[ $# -ne 0 ]] ; do
    case "${1}" in
        -h|--help)
            log "${usage}"
            exit 0
            ;;
        --action)
            shift
            action="${1}"
            ;;
        --arch)
            shift
            arch="${1}"
            ;;
        --location)
            shift
            location="${1}"
            ;;
        --repository)
            shift
            repository="${1}"
            ;;
        --)
            shift
            break
            ;;
        *)
            log "Invalid option: ${1}"
            log "${usage}"
            exit 1
            ;;
    esac
    shift
done

process_conf() {
    conf=$(awk -F= '/^[[:space:]]*(#.*)?$/{next};/^[[:space:]]*\[/{prefix=gensub(/\[([^\]]*)\]/, "\\1_", 1, $0);next};{gsub(/[ \t]+$/, "", $1);gsub(/[ \t]+/, "", $2);print prefix $1 "=" $2}' "${conf_file}") || {
        log "Error $? processing configuration file ${conf_file}"
        exit 1
    }
    eval "${conf}"
}

process_package() {
    if [[ "${main_enabled}" != "true" ]] ; then
        log "Not processing package ${location}, main_enabled=${main_enabled}"
        return 0
    fi

    if [[ "${main_archdirs}" == "true" ]] ; then
        cache_dir="${local_dir}"/"${arch}"
        refresh_file="${refresh_file}.${arch}"
    else
        cache_dir="${local_dir}"
    fi

    case "${action}" in
        I|U|D|R)
            if [[ "${location}" = /* ]] ; then
                # RPM file is local to the system, and therefore is not in
                # the DNF cache.  Use the local path.
                path="${location}"
            else
	            path_array=(/var/cache/libdnf5/"${repository}"-*/packages/"$(basename "${location}")")
                if [[ ${#path_array[@]} -eq 0 ]] ; then
                    log "Error: $(basename "${location}") not found in DNF cache"
                elif [[ ${#path_array[@]} -ne 1 ]] ; then
                    log "Error: $(basename "${location}") found in multiple paths: ${path_array[*]}"
                else
                    path="${path_array[0]}"
                fi
            fi
            if [[ "${repository}" = _dnf-local* ]] ; then
                log "Not archiving ${location} from repository ${repository}"
            elif [[ -n "${path:-}" ]] ; then
	            if ! mkdir -p "${cache_dir}" ; then
	                log "Error creating directory ${cache_dir}"
	            else
	                if ! cp "${path}" "${cache_dir}" ; then
		                log "Failed to cache ${path} due to ${action}, error: $?"
	                else
                        log "Cached ${path} due to ${action}"
		                touch "${refresh_file}"
	                fi
	            fi
            fi
	        ;;
    esac
}

repo_config() {
    log "Configuring local repository."
    if [[ "${main_archdirs}" == "true" ]] ; then
        local arch
        arch="$(uname -m)"
        echo "conf._dnf-local-noarch.enabled=1" >&4
        echo "conf._dnf-local-noarch.baseurl=file://${local_dir}/noarch" >&4
        echo "conf._dnf-local-arch.name=DNF Local Cache - ${arch}" >&4
        echo "conf._dnf-local-arch.enabled=1" >&4
        echo "conf._dnf-local-arch.baseurl=file://${local_dir}/${arch}" >&4
        # Hack to make i686 work for x86_64.
        if [[ "${arch}" == "x86_64" ]] ; then
            echo "conf._dnf-local-subarch.name=DNF Local Cache - i686" >&4
            echo "conf._dnf-local-subarch.enabled=1" >&4
            echo "conf._dnf-local-subarch.baseurl=file://${local_dir}/i686" >&4
        fi
    else
        echo "conf._dnf-local.enabled=1" >&4
        echo "conf._dnf-local.baseurl=file://${local_dir}" >&4
    fi
    log "Local repositories configured."
}

update_repos() {
    local output
    if [[ "${main_enabled,,}" != "true" ]] || [[ "${createrepo_enabled,,}" != "true" ]] ; then
        log "Not running createrepo_c.  main_enabled=${main_enabled}, createrepo_enabled=${createrepo_enabled}"
    else
        if [[ "${main_archdirs}" == "true" ]] ; then
            for file in /run/dnf-plugin-local.refresh.* ; do
                refresh_arch="${file##*.}"
                log "Updating ${refresh_arch} repository"
                output="$(createrepo_c --update --unique-md-filenames "${local_dir}/${refresh_arch}")"
                log "${output}"
                rm -f "${file}"
            done
        elif [[ -f /run/dnf-plugin-local.refresh ]] ; then
            log "Updating local repository"
            output="$(createrepo_c --update --unique-md-filenames "${local_dir}")"
            log "${output}"
            rm -f "${refresh_file}"
        fi
    fi
}

if [[ -z "${1:-}" ]] ; then
    log "Error: must specify command."
    log "${usage}"
    exit 1
fi

process_conf
local_dir="${main_repodir}"
if [[ -z "${local_dir}" ]] ; then
    log "Error: local_dir has no value.  Please correctly set configuration."
    exit 1
fi

case "${1}" in
    "repo-config")
        repo_config
        ;;
    "process")
        process_package
        ;;
    "update-repos")
        update_repos
        ;;
    *)
        log "Invalid command: ${1}"
        ;;
esac
