#!/usr/bin/env bash
# Copyright Argent Linux Authors 2015-2026
# License: GPLv2

if [[ -d "/etc/portage/make.conf" ]]; then
    [[ -e "/etc/portage/make.conf/main.conf" ]] \
        && export MAKECONF_PATH="/etc/portage/make.conf/main.conf" \
        || export MAKECONF_PATH="/etc/portage/make.conf/00-argent.conf"
else
    export MAKECONF_PATH="/etc/portage/make.conf"
fi

source "${MAKECONF_PATH}"

if [[ -e "/etc/portage/make.conf.local" ]]; then
    source "/etc/portage/make.conf.local"
else
    touch "/etc/portage/make.conf.local"
fi

# generic Argent variables
export ADD_OPTS="${ADD_OPTS:-}"

# export function for other gentoo distributions to use
export EPKG_DISTRO_SET="argent"

export ENABLE_COLOR="\e[1;49;34m"
export DISABLE_COLOR="\e[0m"

export PORTAGE_DIR="${PORTDIR}"
export ARGENT_OVERLAY="/var/db/repos/argent-ws"

# import gentoo functions, this has not been ported to lib64 yet
source /lib/gentoo/functions.sh

# generic gentoo variables
export PORTAGE_GROUP="${PORTAGE_GROUP:-portage}"

checkroot() {
	if [[ "$(whoami)" != root ]] ; then
		eerror "You're not root?...No cookies for you, go away !!!"
		exit 1
	fi
}

checksystemmode() {
	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-srcmode" ]] ; then
		eerror "The system is set to SRCMODE (full Gentoo mode), cowardly refusing to run!"
		exit 1
	fi
}

checkportageconfig() {
	# running update on argent specific gentoo settings

	pushd /opt/argentws-build > /dev/null 2>&1 || return

	if [[ ! -e .git ]] ; then
		echo -e ""
		eerror "You do not have any connection with the Argent main server"
		eerror "Establish a .git connection to the main Argent EPKG server"
		# shellcheck disable=SC2027
		eerror "Or use ""$ENABLE_COLOR""avasile""$DISABLE_COLOR"" to switch stance"
		eerror "Ignoring local changes."
		echo -e ""
		popd > /dev/null 2>&1
		return
	fi

	git remote update > /dev/null 2>&1

	CONFHASH=$(git rev-parse @)
	RCONFHASH=$(git rev-parse @{u})

	if [ "${CONFHASH}" != "${RCONFHASH}" ] ; then
		eerror "portage config is out of date, run "epkg update" first"
	fi
	popd > /dev/null 2>&1
}

checkportagetree() {
	# running update on gentoo snapshotted overlay

	pushd "${PORTAGE_DIR}" > /dev/null 2>&1 || return
	git remote update > /dev/null 2>&1

	export TREEHASH=$(git rev-parse @)
	export RTREEHASH=$(git rev-parse @{u})

	if [ "${TREEHASH}" != "${RTREEHASH}" ] ; then
		eerror "Argent portage tree is out of date, run "epkg update" first"
	fi
	popd > /dev/null 2>&1 || return
}

checkargentoverlay() {
	# running update on argent gentoo overlay

	pushd "${ARGENT_OVERLAY}" > /dev/null 2>&1 || return
	git remote update > /dev/null 2>&1
	export OVERLAYHASH=$(git rev-parse @)
	export ROVERLAYHASH=$(git rev-parse @{u})
	if [  "${OVERLAYHASH}" != "${ROVERLAYHASH}" ] ; then
		eerror "Overlay argent-ws is out of date, run "epkg update" first"
	fi

	popd > /dev/null 2>&1 || return
}

checkmakeconf() {
	# function checking the existence and validity of make.conf
	# in accordance wih gentoo and argentws-build standard

        if [ -e "${MAKECONF_PATH}" ] ; then
                . "${MAKECONF_PATH}"
		unset PKGDIR
		export PKGDIR="${PKGDIR:-$(portageq pkgdir 2>/dev/null)}"
		export PKGDIR="${PKGDIR:-/var/cache/binpkgs}"
	else
                eerror "The file does not match the pattern of environment script"
                echo "Please consider using avasile to change to one of the modes"
                echo "avasile --help"
        fi
}

checkportdir() {
	# function to check the existence of portage and argent/portage.git independent dirs:
	# distfiles and packages
	# the unconventional way here: we import /etc/portage/make.conf into current local function
	checkmakeconf

        # check if ${PORTDIR} exists

        if [ ! -d "${PORTDIR}" ] ; then
                eerror "No such directory: ${PORTDIR}"
                echo "Consider running: epkg update"
                exit 1
        fi

        # check if distfiles exist. Again, we might never know what Gentoo users are up to

        if [ ! -d "${DISTDIR}" ] ; then
                eerror "No such directory: ${DISTDIR}"
                echo "Consider creating the directory with the right ownership:"
                echo "i.e.: chgrp portage ${DISTDIR}"
                exit 1
        fi

        # check if ${PKGDIR} exists

        if [ ! -d "${PKGDIR}" ] ; then
                eerror "No such directory: ${PKGDIR}/"
                echo "Consider creating the directory with the right ownership:"
                echo "i.e.: chgrp portage ${PKGDIR}/"
                exit 1
        fi
}

checksync() {
    if [[ "${EPKG_DISTRO_SET}" == "argent" ]]; then
        if [ -d "${PORTAGE_DIR}/.git" ]; then
            checkportagetree
        else
		ewarn "No portage tree found, you should fetch minimal portage tree via epkg update"
	fi
        if [ -d "$ARGENT_OVERLAY/.git" ]; then
            checkargentoverlay
        else
		ewarn "No argent overlay found, you must eselect enable argent-ws or git clone it in:"
		ewarn "either /var/lib/layman/ or /var/db/repos/"
		ewarn "You also have the alternative to use the distro-reset command avasile --help"
	fi
        checkportageconfig
    fi
}

syncrepos() {
	if [[ -e "/etc/portage/repos.conf/layman.conf" ]] && grep -q 'argent-ws' /etc/portage/repos.conf/layman.conf ; then
		sed -i 's|auto-sync = No|auto-sync = yes|g' /etc/portage/repos.conf/layman.conf
	fi

	if ! emerge --sync ; then
		echo -e "${ENABLE_COLOR}Warning: 'emerge --sync' failed (possibly due to a broken third-party repository). Falling back to syncing Argent-specific repositories only.${DISABLE_COLOR}"
		emerge --sync gentoo
		emerge --sync argent-ws
	fi
}

set_var_cache_dir() {
    export COLOR_ON="\e[1;49;34m"
    export COLOR_OFF="\e[0m"

    if [ -e "${MAKECONF_PATH}" ] ; then
        . "${MAKECONF_PATH}"
        if [ -z "${PKGDIR}" ]; then
            export PKGDIR="$(portageq pkgdir 2>/dev/null)"
        fi
        if [ -z "${PKGDIR}" ]; then
            export PKGDIR="/var/cache/binpkgs"
        fi
        if [ -z "${DISTDIR}" ]; then
            export DISTDIR="$(portageq distdir 2>/dev/null)"
        fi
        if [ -z "${DISTDIR}" ]; then
            export DISTDIR="/var/cache/distfiles"
        fi
        if [ -z "${PORTAGE_GROUP}" ]; then
            export PORTAGE_GROUP="portage"
        fi
        else
        eerror "The file does not match the pattern of environment script"
        echo "Please consider using avasile to change to one of the modes"
        echo "avasile --help"
    fi

	echo " "


	if grep -q 'PKGDIR=' "${MAKECONF_PATH}" 2>/dev/null; then
		if [ ! -e "${PKGDIR}" ] ; then
			mkdir -p "${PKGDIR}"
			if [ "$( stat -c "%G" "${PKGDIR}" )" != "${PORTAGE_GROUP}" ] ; then
				eerror "Please make sure you set $PKGDIR ownership to $PORTAGE_GROUP"
				echo " "
				eerror "Run command: "$COLOR_ON"chgrp $PORTAGE_GROUP {${PKGDIR},${DISTDIR}} "$COLOR_OFF""
				echo " "
				eerror "You can safely cancel now, and run the blue command from above"
				echo " "
			fi
		fi
	fi


	if grep -q 'DISTDIR=' "${MAKECONF_PATH}" 2>/dev/null; then
		if [ ! -e "${DISTDIR}" ] ; then
			mkdir -p "${DISTDIR}"
			if [ "$( stat -c "%G" "${DISTDIR}" )" != "${PORTAGE_GROUP}" ] ; then
				eerror "Please make sure you set $DISTDIR ownership to $PORTAGE_GROUP"
				echo " "
				eerror "Run command: "$COLOR_ON"chgrp $PORTAGE_GROUP {${PKGDIR},${DISTDIR}} "$COLOR_OFF""
				echo " "
			fi
		fi
	fi
}

forcesync() {
	# Full update, everything caught in history
	pushd "${PORTAGE_DIR}" > /dev/null 2>&1 || return
	git pull --unshallow
	popd || return

	pushd "${ARGENT_OVERLAY}" > /dev/null 2>&1 || return
	git pull --unshallow
	popd || return

	pushd /opt/argentws-build > /dev/null 2>&1 || return
	git pull --unshallow
	popd || return
}

refresh_pkg_keys() {
	if command -v getuto > /dev/null 2>&1 ; then
		getuto || ewarn "getuto could not refresh the binpkg signature keyring"
	fi
}

regen_pkg_keys() {
	einfo "Regenerating /etc/portage/gnupg (binpkg signature keyring)"
	rm -rf /etc/portage/gnupg
	if command -v getuto > /dev/null 2>&1 ; then
		getuto -v
	else
		eerror "app-portage/getuto not found; cannot regenerate keyring"
		return 1
	fi
}

fetchminimalsync() {
        # fetch minimal portage tree
        # in usermode we don't want the whole tree of gentoo ebuilds
        # but we need portage profiles portage metadata && portage eclasses
        # so make a sparse-checkout, to fetch only what we need
        if [[ ! -d "${PORTAGE_DIR}"/.git ]] ; then
                einfo "Injecting usermode (minimal) gentoo portage tree"
                cd "${PORTAGE_DIR}" && git init > /dev/null 2>&1
                git remote add origin https://gitlab.com/argent/portage.git
                git config core.sparsecheckout true
                git config core.sparseCheckoutCone false
                echo "profiles/*" > .git/info/sparse-checkout
                echo "metadata/*" >> .git/info/sparse-checkout
                echo "eclass/*" >> .git/info/sparse-checkout
                echo ".gitignore" >> .git/info/sparse-checkout
                git pull --depth=1 origin master
                git branch -u origin/master master
                rm -rf "${PORTAGE_DIR}/profiles/updates"
        else
        # We need minimal git pull if the folder really exists
        pushd "${PORTAGE_DIR}" > /dev/null 2>&1 || return
            git fetch --depth=1 origin master
            git reset --hard origin/master
            git clean -fd
            git gc --prune=now
        popd || return
    fi

    if [[ ! -d "${ARGENT_OVERLAY}/.git" ]] ; then
        einfo "Injecting usermode argent-ws overlay"
        cd "${ARGENT_OVERLAY}" && git init > /dev/null 2>&1
        git remote add origin https://gitlab.com/argent/argent-ws.git
        git config core.sparsecheckout true
        git config core.sparseCheckoutCone false
                echo "profiles/*" > .git/info/sparse-checkout
                echo "metadata/*" >> .git/info/sparse-checkout
                echo "eclass/*" >> .git/info/sparse-checkout
                echo ".gitignore" >> .git/info/sparse-checkout
                git pull --depth=1 origin master
                git branch -u origin/master master
                git submodule update --init --recursive --depth=1
                rm -rf ""${PORTAGE_DIR}"/profiles/updates"
    else
        pushd "${ARGENT_OVERLAY}" > /dev/null 2>&1 || return
            git fetch --depth=1 origin master
            git reset --hard origin/master
            git clean -fd
            git submodule update --init --recursive --depth=1
            git submodule foreach --recursive git clean -fd
            git gc --prune=now
        popd || return
    fi

    pushd /opt/argentws-build/ > /dev/null 2>&1 || return
        git fetch --depth=1 origin master
        git reset --hard origin/master
        git clean -fd
        git gc --prune=now
    popd || return

    refresh_pkg_keys
}

git_clean_history() {
    # cleanup git history when called
    if [[ -d "${PORTAGE_DIR}"/.git ]] ; then
        pushd "${PORTAGE_DIR}" > /dev/null 2>&1 || return
            git reflog expire --expire=now --all
            git gc --prune=now --aggressive
            git repack -ad
        popd || return
    fi

    if [[ -d "${ARGENT_OVERLAY}"/.git ]] ; then
        pushd "${ARGENT_OVERLAY}" > /dev/null 2>&1 || return
            git reflog expire --expire=now --all
            git gc --prune=now --aggressive
            git repack -ad
            git submodule foreach --recursive 'git reflog expire --expire=now --all && git gc --prune=now --aggressive'
        popd || return
    fi

    if [[ -d "/opt/argentws-build"/.git ]] ; then
        pushd /opt/argentws-build/ > /dev/null 2>&1 || return
            git reflog expire --expire=now --all
            git gc --prune=now --aggressive
            git repack -ad
        popd || return
    fi
}


backuppkg() {
	# function to provide backup packages with own configurations

	# a forenote: although if you run usermode or devmode, the installing packages will already be saved
	# but if you run epkg cleanlocalpkg, you can start all over and save what packages you already configured
	# like saving apache with own configs for example, for future use

	# the unconventional way here: we import /etc/portage/make.conf into current local function
	checkmakeconf

	if [[ $# -eq 0 ]] ; then
		eerror "You have not specified any package to backup"
		echo " "
		exit 1
	fi

	# checking if ${PKGDIR} exists
	# usually it's /usr/portage/ if you're on avasile --usermode or --devmode
	if [ -d "${PKGDIR}" ] ; then
		quickpkg --include-config y --include-unmodified-config y "$@"
		echo ""
		echo "All packages were saved in ${PKGDIR} by category"
		echo "Please make sure these files will not be overwritten!"
		echo "If you consider further backup on the same package"
		echo "consider copying packages from ${PKGDIR} into customized directories"
		echo "Although, not recommended, you can epkg install them by path (from customized directories)"
		echo "To customize directory, you can use variable PKGDIR as: PKGDIR='/location/' epkg backuppkg"
		echo " "
	else
		echo "  "
		eerror "No such directory: ${PKGDIR}"
		echo "Please consider creating the $PKGDIR directory"
		echo "And set $PKGDIR GID to portage!"
		echo " "
		exit 1
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

backupallpkg() {
	# function to *backup all packages in the system* for future use

	# the unconventional way here: we import /etc/portage/make.conf into current local function
	if [[ $# -eq 0 ]] ; then
		eerror "You have not specified any package to backup"
		echo " "
    	exit 1
    fi

	checkportdir

	eerror "Warning: If you backup everything, make sure you keep the packages safe :)"
	eerror "We cannot take responsibility of safe-guarding the newly backed-up system"

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		eerror "If you continue, you continue at your own risk!"
		eerror "Make sure you keep the backup safe!"
		sleep 3
		if [[ ! -e "/tmp/temporary_list_backup" ]] ; then
			# shellcheck disable=SC2283
			for i in $( qlist -IvC ) ; do echo =$i >> /tmp/temporary_list_backup ; done
			quickpkg --include-config y --include-unmodified-config y $( cat /tmp/temporary_list_backup ) "$@"
		else
			rm -f /tmp/temporary_list_backup
			# shellcheck disable=SC2283
			for i in $( qlist -IvC ) ; do echo =$i >> /tmp/temporary_list_backup ; done
			quickpkg --include-config y --include-unmodified-config y $( cat /tmp/temporary_list_backup ) "$@"
		fi
	else
		if [[ ! -e "/tmp/temporary_list_backup" ]] ; then
			# shellcheck disable=SC2283
			for i in $( qlist -IvC ) ; do echo =$i >> /tmp/temporary_list_backup ; done
			quickpkg --include-config y --include-unmodified-config y $( cat /tmp/temporary_list_backup ) "$@"
		else
			rm -f /tmp/temporary_list_backup
			# shellcheck disable=SC2283
			for i in $( qlist -IvC ) ; do echo =$i >> /tmp/temporary_list_backup ; done
			quickpkg --include-config y --include-unmodified-config y $( cat /tmp/temporary_list_backup ) "$@"
		fi
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

cleanoutdated() {
	# function designed to clearout any outdated package using gentoolkit
	# the unconventional way here: we import /etc/portage/make.conf into current local function
	# we have 2 checks here: if usr/portage and usr/portage/packages really exist
	# we may never know what users do to their portage dirs in Gentoo system 
	checkmakeconf

	if [ -d "${PKGDIR}" ] ; then
		/usr/bin/eclean-pkg
		echo "Note: remote binary package cache at /var/cache/binhost/ is managed by portage and is not cleaned here."
	else
		eerror "No such directory ${PKGDIR}"
		echo "Please consider: mkdir ${PKGDIR}/"
		echo "chgrp portage ${PKGDIR}"
		exit 1
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

cleanlocalpkg() {
    # function to cleanup all local packages in /var/cache/binpkgs
    # it also includes deletion of /var/cache/binpkgs
    # if we do not have any /usr/portage, there is no reason we should continue

	checkmakeconf

	if [ -d "${PKGDIR}" ] ; then
		rm -rf "${PKGDIR}"/* || exit 1
		echo "Note: remote binary package cache at /var/cache/binhost/ is managed by portage and is not affected by this command."
	else
		eerror "No such directory ${PKGDIR}"
		echo "Make sure you have this directory"
		echo "Also make sure you have the right GID:"
		echo "i.e.: chgrp portage ${PKGDIR}"
		exit 1
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

src_newuse() {
	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		eerror "If you continue, you continue at your own risk!"
		sleep 3
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -va --newuse --changed-use "$@"
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -va --newuse --changed-use "$@"
	fi
}

compilepkg() {
	# function to call a recompile of a package and save it to ${PKGDIR}"

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		eerror "If you continue, you continue at your own risk!"
		sleep 3
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -va "$@"
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -va "$@"
	fi
}

recompilepkg() {
	# function to call a recompile of a package and save it to ${PKGDIR}"

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		eerror "If you continue, you continue at your own risk!"
		sleep 3
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --oneshot -va "$@"
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --oneshot -va "$@"
	fi
}

recompileallpkg() {
	# function to recompile everything on the system and also save all the recompiled packages.

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are not allowed to run in --usermode, we propose using: avasile --devmode or --srcmode for this"
		exit 1
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -va $(qlist -IC)
		eerror "Warning: if there are packages that are not found, you must run: epkg update"
		eerror "If the error persists, force remove the package causing the corruption:"
		eerror "in --devmode: epkg remove <package-name>"
		eerror "in --srcmode: emerge --unmerge <package-name>"
		eerror "Then re-run the same command: epkg recompileallpkg"
	fi
}

autocompilepkg() {
	# function to call a recompile of a package and save it to ${PKGDIR}"

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		eerror "If you continue, you continue at your own risk!"
		sleep 3
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -v "$@"
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -v "$@"
	fi
}

autorecompilepkg() {
	# function to call a recompile of a package and save it to ${PKGDIR}"

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		eerror "If you continue, you continue at your own risk!"
		sleep 3
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --oneshot -v "$@"
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --oneshot -v "$@"
	fi
}

autorecompileallpkg() {
	# function to recompile everything on the system and also save all the recompiled packages.

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are not allowed to run in --usermode, we propose using: avasile --devmode or --srcmode for this"
		exit 1
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge -v $(qlist -IC)
	fi
}

# pseudo-portage checks for ebuilds, skips if given packagename is not found in the ebuilds
# filters the best version + revision, checks for missing ebuilds, install whatever is left
# 'if' something is left
_ebuild_exists() {

    local repo
    for repo in "${repo_paths[@]}" ; do
        if [[ -f "${repo}/${1}/${2}/${2}-${3}.ebuild" ]] ; then
            return 0
        fi
    done

    return 1
}

_best_same_version_revision() {

    local repo ebuild base rev
    local best_rev=-1
    local installed_rev=0

    if [[ "${4}" =~ -r([0-9]+)$ ]] ; then
        installed_rev="${BASH_REMATCH[1]}"
    fi

    for repo in "${repo_paths[@]}" ; do
        for ebuild in "${repo}/${1}/${2}/${2}-${3}"*.ebuild ; do
            [[ -f "${ebuild}" ]] || continue
            base="${ebuild##*/}"
            base="${base%.ebuild}"

            if [[ "${base}" == "${2}-${3}" ]] ; then
                rev=0
            elif [[ "${base}" =~ ^"${2}-${3}"-r([0-9]+)$ ]] ; then
                rev="${BASH_REMATCH[1]}"
            else
                continue
            fi

            if [[ ${rev} -gt ${best_rev} ]] ; then
                best_rev="${rev}"
            fi
        done
    done

    if [[ ${best_rev} -gt ${installed_rev} ]] ; then
        echo "${3}-r${best_rev}"
    fi
}

_report_missing_ebuild() {

    local repo ebuild base vdb_repo=""
    local versions=()

    if [[ -f "/var/db/pkg/${1}/${2}-${3}/repository" ]] ; then
        read -r vdb_repo < "/var/db/pkg/${1}/${2}-${3}/repository"
    fi

    for repo in "${repo_paths[@]}" ; do
        for ebuild in "${repo}/${1}/${2}/"*.ebuild ; do
            [[ -f "${ebuild}" ]] || continue
            base="${ebuild##*/}"
            base="${base%.ebuild}"
            versions+=("${base#"${2}"-}")
        done
    done

    if [[ -n "${vdb_repo}" ]] ; then
        ewarn "  installed from repo '${vdb_repo}'"
    fi

    if [[ ${#versions[@]} -gt 0 ]] ; then
        ewarn "  versions still available: $(printf '%s\n' "${versions[@]}" | sort -V | tail -5 | tr '\n' ' ')"
        ewarn "  run 'epkg update', or upgrade it: epkg install ${1}/${2}"
    else
        ewarn "  no longer present in any repo"
        ewarn "  run 'epkg update', or unmerge it: epkg remove =${1}/${2}-${3}"
    fi
}

_filter_depend_atoms() {


    local list_file="${1}"

    [[ -s "${list_file}" ]] || return 0

    if ! command -v qatom > /dev/null 2>&1 ; then
        return 0
    fi

    local repo_paths=()
    local repo repo_path
    for repo in $(portageq get_repos / 2>/dev/null) ; do
        repo_path="$(portageq get_repo_path / "${repo}" 2>/dev/null)"
        [[ -d "${repo_path}" ]] && repo_paths+=("${repo_path}")
    done

    if [[ ${#repo_paths[@]} -eq 0 ]] ; then
        return 0
    fi

    local split_file
    if ! split_file="$(mktemp "${TMPDIR:-/tmp}/epkg_atom_split.XXXXXXXX")" ; then
        return 0
    fi

    xargs qatom -C -F '%{CATEGORY}|%{PN}|%{PV}|%{PVR}' < "${list_file}" > "${split_file}" 2>/dev/null

    local kept=()
    local substituted=0
    local dropped=0
    local category name version version_rev best

    while IFS='|' read -r category name version version_rev ; do
        [[ -n "${category}" && -n "${name}" && -n "${version_rev}" ]] || continue

        if _ebuild_exists "${category}" "${name}" "${version_rev}" ; then
            kept+=("=${category}/${name}-${version_rev}")
            continue
        fi

        best="$(_best_same_version_revision "${category}" "${name}" "${version}" "${version_rev}")"
        if [[ -n "${best}" ]] ; then
            ewarn "${category}/${name}-${version_rev} has no ebuild, using =${category}/${name}-${best} (revision bump)"
            kept+=("=${category}/${name}-${best}")
            substituted=$((substituted + 1))
            continue
        fi

        ewarn "${category}/${name}-${version_rev} has no ebuild in any repo, skipping"
        _report_missing_ebuild "${category}" "${name}" "${version_rev}"
        dropped=$((dropped + 1))
    done < "${split_file}"

    rm -f "${split_file}"

    if [[ ${#kept[@]} -gt 0 ]] ; then
        printf '%s\n' "${kept[@]}" > "${list_file}"
    else
        : > "${list_file}"
    fi

    if [[ ${substituted} -gt 0 || ${dropped} -gt 0 ]] ; then
        einfo "${#kept[@]} package(s) to rebuild, ${substituted} substituted, ${dropped} skipped"
    fi

    if [[ ${dropped} -gt 0 ]] ; then
        return 2
    fi

    return 0
}

_recompile_depend() {
	# simplified implementation for recompile-depend.
	# purpose is to collect a list of of all packages that depend on given
	# list / packagename, and recomiple them.
	# this is strictly done under either mixed or full gentoo mode.

	# until we fix the lack of ebuilds for some of the installed packages, we recommend
	# to have the packages already compiled.

    local ask_mode="${1}"
    shift

    local exclude_packages=()
    local targets=()
    local strict_mode="no"

    while [[ $# -gt 0 ]] ; do
        case "${1}" in
            --strict)
                strict_mode="yes"
                shift
                ;;
            --exclude)
                if [[ -n "${2}" ]] ; then
                    exclude_packages+=("${2}")
                    shift 2
                else
                    eerror "--exclude requires a package name or a slot atom"
                    return 1
                fi
                ;;
            --exclude=*)
                exclude_packages+=("${1#--exclude=}")
                shift
                ;;
            --*)
                eerror "Unknown option: ${1}"
                eerror "Only --exclude <package name or slot atom> and --strict are accepted here"
                return 1
                ;;
            *)
                targets+=("${1}")
                shift
                ;;
        esac
    done

    if [[ ${#targets[@]} -eq 0 ]] ; then
        eerror "No package(s) given"
        return 1
    fi

    if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
        eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
        eerror "If you continue, you continue at your own risk!"
        sleep 3
    fi

    # serialize concurrent (auto)recompile-depend runs
    local lock_file="/run/lock/epkg-recompile-depend.lock"
    mkdir -p "$(dirname "${lock_file}")" || return 1
    exec 200>>"${lock_file}" || return 1
    if ! flock -n 200 ; then
        eerror "Another epkg (auto)recompile-depend is already running"
        exec 200>&-
        return 1
    fi

    local temp_list
    if ! temp_list="$(mktemp "${TMPDIR:-/tmp}/epkg_temporary_list.XXXXXXXX")" ; then
        eerror "Failed to create the temporary package list"
        exec 200>&-
        return 1
    fi

    equery -q -C depends "${targets[@]}" | awk 'NF {print "=" $1}' | sort -u > "${temp_list}"

    local ret=0
    local filter_rc=0
    if [[ -s "${temp_list}" ]] ; then
        _filter_depend_atoms "${temp_list}" || filter_rc=$?

        if [[ ${filter_rc} -eq 2 && "${strict_mode}" == "yes" ]] ; then
            eerror "Some packages have no ebuild for the installed version, --strict given"
            ret=1
        elif [[ -s "${temp_list}" ]] ; then
            local exclude_args=()
            local pkg
            for pkg in "${exclude_packages[@]}" ; do
                exclude_args+=("--exclude" "${pkg}")
            done

            local ask_opt="-va"
            if [[ "${ask_mode}" == "noask" ]] ; then
                ask_opt="-v"
            fi

            local atoms=()
            mapfile -t atoms < "${temp_list}"

            EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --oneshot "${ask_opt}" --keep-going \
                "${atoms[@]}" "${exclude_args[@]}" || ret=$?
        else
            ewarn "No package left to rebuild"
        fi
    else
        einfo "There are no packages that depend on given package(s)"
    fi

    rm -f "${temp_list}"
    flock -u 200
    exec 200>&-

    return "${ret}"
}

recompile_depend() {
    # function to recompile all the packages that directly depend on this package

    _recompile_depend ask "$@"
}

recompile_depend_new() {
    # kept as an alias of recompile_depend for backwards compatibility

    _recompile_depend ask "$@"
}

autorecompile_depend() {
    # function to recompile all the packages that directly depend on this package
    # with no confirmation

    _recompile_depend noask "$@"
}

autorecompile_depend_new() {
    # kept as an alias of autorecompile_depend for backwards compatibility

    _recompile_depend noask "$@"
}

# soon to be rewritten / deprecated
_reinstall_depend() {
	# first argument "ask" to ask for confirmation before emerging, "noask" to run unattended

	local ask_mode="${1}"
	shift

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		eerror "If you continue, you continue at your own risk!"
		sleep 3
	fi

	local temp_list
	if ! temp_list="$(mktemp "${TMPDIR:-/tmp}/epkg_temporary_list.XXXXXXXX")" ; then
		eerror "Failed to create the temporary package list"
		return 1
	fi

	equery -q -C depends "$@" | awk 'NF {print "=" $1}' | sort -u > "${temp_list}"

	local ret=0
	if [[ -s "${temp_list}" ]] ; then
		_filter_depend_atoms "${temp_list}"

		if [[ -s "${temp_list}" ]] ; then
			local ask_opt="-va"
			if [[ "${ask_mode}" == "noask" ]] ; then
				ask_opt="-v"
			fi

			local atoms=()
			mapfile -t atoms < "${temp_list}"

			emerge "${ask_opt}" "${atoms[@]}" || ret=$?
		else
			ewarn "No package left to reinstall"
		fi
	else
		einfo "There are no packages that depend on given package(s)"
	fi

	rm -f "${temp_list}"

	return "${ret}"
}

reinstall_depend() {
	# function to reinstall all new packages that directly depend on this package

	_reinstall_depend ask "$@"
}

autoreinstall_depend() {
	# function to reinstall all new packages that directly depend on this package

	_reinstall_depend noask "$@"
}

fetchsourcepkg() {
	# function to download the source of the program for development / patching purposes
	# the unconventional way here: we import /etc/portage/make.conf into current local function

	checkportdir

	# function to warn the regular user that he's doing something wrong
	# but still do it anyway.

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You are on --usermode, we propose using: avasile --devmode or --srcmode for this"
		sleep 3
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --fetchonly "$@"
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --fetchonly "$@"
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

fetchbinpkg() {
	# function to download the source of the program for development / patching purposes
	# the unconventional way here: we import /etc/portage/make.conf into current local function

	checkportdir

	# function to warn the regular user that he's doing something wrong
	# but still do it anyway.

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "Fetching binary package(s) from remote"
		sleep 2
		emaint binhost -f
		EMERGE_DEFAULT_OPTS="--getbinpkgonly" emerge --fetchonly "$@"
	else
		emaint binhost -f
		EMERGE_DEFAULT_OPTS="--getbinpkgonly" emerge --fetchonly "$@"
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

remove_orphans() {
	# The function calls 'emerge --depclean -a' which removes orphaned packages
	# Probably the most successful emerge algorythm ever made

	checkmakeconf

	emerge --depclean -a
}

buildinstall() {
	# Stands for build (-Bv) and install (-va with --getbinpkg)
	# Also regenerates the binhost Packages file

	if [[ $# -eq 0 ]] ; then
		eerror "You have not specified any package to build & install"
		echo " "
		exit 1
	fi

	checkportdir

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You cannot run buildpkgonly from the user profile!"
		exit 1
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --with-bdeps=y -Bva "$@"
		EMERGE_DEFAULT_OPTS="--getbinpkg --rebuilt-binaries" emerge -av "$@"
		emaint -f binhost
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

autobuildinstall() {
	# Stands for build (-Bv) and install (-va with --getbinpkg) automatically
	# Also regenerates the binhost Packages file

	if [[ $# -eq 0 ]] ; then
		eerror "You have not specified any package to build & install"
		echo " "
		exit 1
	fi

	checkportdir

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You cannot run buildpkgonly from the user profile!"
		exit 1
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --with-bdeps=y -Bv "$@"
		EMERGE_DEFAULT_OPTS="--getbinpkg --rebuilt-binaries" emerge -v "$@"
		emaint -f binhost
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

buildpkgonly() {
	# function to only build 1 or more packages based on input
	# works as: epkg buildpkg-only <something>

	checkportdir

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You cannot run buildpkgonly from the user profile!"
		exit 1
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --with-bdeps=y -Bva "$@"
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

autobuildpkgonly() {
	# function to only build 1 or more packages based on input
	# works as: epkg autobuildpkg-only <something>

	checkportdir

	if [[ "$(readlink -f "${MAKECONF_PATH}")" = "/opt/argentws-build/conf/intel/portage/make.conf.amd64-user" ]] ; then
		eerror "You cannot run buildpkgonly from the user profile!"
		exit 1
	else
		EMERGE_DEFAULT_OPTS="--rebuilt-binaries" emerge --with-bdeps=y -Bv "$@"
	fi

	# regenerating environment here is a must!
	env-update && source /etc/profile
}

syncportageconfig() {
	# syncing with the latest updates on our argent gentoo configs

	pushd /opt/argentws-build > /dev/null 2>&1 || return
	echo ">>> Syncing 'portage config' into '/etc/portage' "
	echo "Git pulling latest modifications. Please, stand by..."

	if [[ ! -e .git ]] ; then
		echo -e ""
		eerror "You do not have any connection with the Argent main server"
		eerror "Establish a .git connection to the main Argent EPKG server"
		eerror "Or use "$ENABLE_COLOR"avasile --help"$DISABLE_COLOR" to switch stance"
		eerror "Ignoring local changes"
		echo -e ""
	else
		git pull
	fi

	echo "=== Sync completed for 'portage config'"

	popd > /dev/null 2>&1 || return
}

argentsync() {
	if [[ "${EPKG_DISTRO_SET}" == "argent" ]]; then
		syncrepos
		syncportageconfig
	fi
	echo ""
}
