#! /usr/bin/env sh
# This script is part of the eix project and distributed under the
# terms of the GNU General Public License v2.
#
# Author and Copyright (c):
#   Martin V\"ath <vaeth@mathematik.uni-wuerzburg.de>
#
# It can be used to fetch the "standard" overlay data and add it to the
# eix database. (eix 0.22.5).

. '/usr/bin/eix-functions.sh'
ReadFunctions

addr='http://dev.gentooexperimental.org/eix_cache/eix-caches.tbz2'

ReadVar local_portage_configroot PORTAGE_CONFIGROOT
eixremoteconf="${local_portage_configroot}/etc/eix-remote.conf"

Usage() {
	n="${0##*/}"
	p='eix 0.22.5'
	f="${filearg:-(none)}"
	eval_gettext 'Usage: ${n} [options] command [FILE]
Get data from a remote datebase for ${p}.
The following commands are provided:

update: Fetch the eix-caches of some layman overlays into a temporary file
        resp. into FILE and add them to the eix database.
        To keep this data across eix-update calls, you might want to set
        KEEP_VIRTUALS=true in /etc/eixrc (or in ~/.eixrc)
fetch:  Only fetch the overlays into FILE.
add:    Only add the overlays from FILE to the eix database.
remove: Remove all temporarily added virtual overlays from the eix database;
        this is similar to
        	KEEP_VIRTUALS=false eix-update
        but faster (without actual updating where possible).

It is strongly recommended to use the update/fetch commands with very limited
permissions. Permissions are dropped when run as root (cf. default in -U)
or when the -u option is specified. Do not use "-u root"!

For "update" and "add" all corresponding local layman overlay paths are
excluded from the update of the current database to avoid confusion.
These local paths are determined by prefixing the path
	${LOCAL_LAYMAN}
You can modify this value with the -l option or by setting the environment
variable LOCAL_LAYMAN. If you do not want this feature (i.e. if you want
to see your local layman overlays and the remote layman overlays),
use here some path not containing any overlays (usually "/" will do).

Options can be specified in the eix (or environment) variable EIX_REMOTE_OPTS.
This data is evalued, so be aware of security risks.
Moreover, "--" in this variable will exclude further command line options.
The following options are available:

-f FILE This is the same as giving FILE as the last argument.
        This is mainly useful for default options. Current value:
        ${f}
-u USER Call wget as USER. Ignored if not set unless you are root.
-U USER Call wget as USER if called as root. Currently "${fetchroot}"
-s/-S   Use sudo/su to change user permission. Currently: ${suprg}
-l PATH Use PATH as LOCAL_LAYMAN
-a ADDR Use ADDR as remote database address. Current value:
        ${addr}
-i      Ignore all previous options (e.g. of local defaults).
-v      Verbose (default)
-q      Quiet'
	echo
	exitcode=${1:-1}
	exit ${exitcode}
}

SanitizeLocalLayman() {
	normalize_resolve=false NormalizeNames LOCAL_LAYMAN \
		|| die "`gettext '$LOCAL_LAYMAN must not be empty'`"
	[ -z "${relative}" ] || \
		die "`gettext '$LOCAL_LAYMAN must start with /'`"
}

PrintLaymanStorage() {
	printf '%s\n%s\n' 'from layman.config import Config' \
	"print(Config()['storage'])" | python -- "${@}" 2>/dev/null
}

SetLocalLayman() {
	for i
	do	[ -n "${i}" ] && test -d "${i}" && LOCAL_LAYMAN="${i}" \
			&& return
	done
	return 1
}

InitLocalLayman() {
	[ -n "${LOCAL_LAYMAN}" ] && return
	LOCAL_LAYMAN="`PrintLaymanStorage`" || LOCAL_LAYMAN=''
	if [ -z "${LOCAL_LAYMAN}" ]
	then	LOCAL_LAYMAN="`PrintLaymanStorage`" || LOCAL_LAYMAN=''
	fi
	SetLocalLayman "${LOCAL_LAYMAN}" \
		'/usr/local/portage/layman' \
		"${local_portdir:-/}local/layman/make.conf" \
		'/var/lib/layman'
}

CalcSuprg() {
	for i
	do	suprgpath="${i}"
		suprg="${i##*/}"
		case "${i}" in
			/*) test -x "${i}" && break;;
			*) command -v "${i}" >/dev/null 2>&1 && break;;
		esac
	done
}


DefaultOpts() {
	CalcSuprg /usr/bin/sudo /bin/su sudo su
	verbose=:
	fetchuser=''
	fetchroot='nobody'
	filearg=''
}

InitLocalLayman
SanitizeLocalLayman
DefaultOpts

eval "Push -c opt `eix-update --print EIX_REMOTE_OPTS`"
Push opt "${@}"
eval "set -- ${opt}"
OPTIND=1
while getopts 'f:vqu:U:l:a:sSi?hH' opt
do	case "${opt}" in
		f) filearg="${OPTARG}";;
		v) verbose=:;;
		q) verbose=false;;
		u) fetchuser="${OPTARG}";;
		U) fetchroot="${OPTARG}";;
		l) LOCAL_LAYMAN="${OPTARG}"; SanitizeLocalLayman;;
		a) addr="${OPTARG}";;
		s) CalcSuprg /usr/bin/sudo sudo;;
		S) CalcSuprg /bin/su su;;
		i) DefaultOpts;;
		*) Usage 0;;
	esac
done
opt=''
[ ${OPTIND} -gt 1 ] && shift "`Expr ${OPTIND} - 1`"

need_arg=false
GetFilename() {
	[ ${#} -gt 1 ] && Usage
	if [ ${#} -lt 1 ]
	then	filename="${filearg}"
	else	filename="${1}"
	fi
	if [ -z "${filename}" ]
	then	return
	fi
	case "${filename}" in
		'') ${need_arg} &&
			die "`gettext 'Filename argument is mandatory'`";;
		/*|'~'*) :;;
		*) filename="`pwd`/${filename}";;
	esac
}

CalcSuCmd() {
#	local shexec a
	if [ -z "${fetchuser}" ]
	then	[ -n "${UID}" ] || UID="`id -u`"
		if [ "${UID}" -ne 0 ]
		then	Push -c sucmd "${@}"
			return
		fi
		fetchuser=${fetchroot}
	fi
	sucmd="${suprgpath}"
	a="${1}"
	shift
	Pathify sucmd a
	Push -c sucmd "${sucmd}"
	if [ "${suprg}" = 'sudo' ]
	then	Push sucmd -u "${fetchuser}" -- "${a}" "${@}"
		return
	fi
	shexec="${SHELL}"
	if [ -z "${shexec}" ] || test ! -x "${SHELL}"
	then	shexec='sh'
	fi
	Pathify shexec
	Push -c a "${a}" "${@}"
	Push sucmd '-s' "${shexec}" '-c' "eval exec ${a}" "${fetchuser}"
}

CdDir() {
	cd -- "${1}" >/dev/null && return
	a="${1}"
	die "`eval_gettext 'cannot cd to ${a}'`"
}

tmpdir=''
exitcode=0
Cleanup() {
	trap : EXIT HUP INT TERM
	cd / >/dev/null
	if [ -n "${tmpdir}" ]
	then	test -d "${tmpdir}" && rm -rf -- "${tmpdir}"
	fi
	tmpdir=''
	trap - EXIT HUP INT TERM
	exit "${exitcode}"
}
MakeTempDir() {
	[ -n "${tmpdir}" ] && return
	AssignTemp tmpdir -d
	trap Cleanup EXIT HUP INT TERM
	chmod -- 755 "${tmpdir}"
	[ -z "${1}" ] || CdDir "${tmpdir}"
}

tmpsub=''
MakeTempSub() {
	if [ -z "${tmpsub}" ]
	then	MakeTempDir
		tmpsub="${tmpdir}/1"
		( umask 000; mkdir -- "${tmpsub}" )
	fi
	[ -z "${1}" ] || CdDir "${tmpsub}"
}

tmpfile=''
FetchTemp() {
	eixcachesname="${addr##*/}"
	[ -z "${eixcachesname}" ] && die "`eval_gettext \
'remote address is not properly set.
Please specify a valid remote file with option -a.
The default should have been set with ./configure --remote-file'`"
	MakeTempDir cd
	tmpfile="${tmpdir}/${eixcachesname}"
	( umask 000; : >"${tmpfile}" )
	CalcSuCmd wget -c -- "${addr}"
	eval "set -- ${sucmd}"
	RunCommand "`eval_gettext 'Fetching ${eixcachesname}'`" "${@}" || \
		die "`eval_gettext 'could not fetch ${addr}'`"
}

BugReport() {
	archive="${1}"
	echo
	printf '\n'
	eval_gettext \
'Probably your eix cachefile was *not* updated successfully.
Unless the above messages suggest another cause or you specified a
wrong filename, the most likely cause of this is that the server uses
another eix version than you or produced broken data. Please inspect
	${archive}
whether this is a valid *.tar.bz2 archive containing eix cachefiles
(if it has already been deleted, download it using fetch).
If this is not the case (but was freshly downloaded), please report a bug.
Note that the archive is *not* broken if only the cachefile format versions
differ: In that case only report a bug if the eix cachefile format versions
in the downloaded file are *older* than that of the most current ~x86 eix
version in the portage tree (but first retry after several days before
reporting such a bug to give the server maintainers a chance to upgrade
after a version bump of eix).
Conversely, if the downloaded versions are even newer than that supported by
your eix, you will have to upgrade to the most current ~x86 version of eix
to use eix-remote: This inconvenience cannot be avoided and is not a bug!'
}

AddArchive() {
	a="${1}"
	RunCommand "Unpacking data" tar xjf "${a}" || {
		msg=`eval_gettext 'cannot unpack ${a}'; BugReport "${a}"`
		die "${msg}"
	}
	ClearUpdateArgs
	AddLocalMethods
	for i in *
	do	n="${i%.eix}"
		while :
		do	case "${n}" in
				_*) n="${n#_}";;
				*_*_*_*) n="${n#*_}";;
				*) break;;
			esac
		done
		Replace -g n '_' '?'
		n="*/${n}"
		p="${2}/${i}"
		name=`EIX_CACHEFILE="${p}" eix --print-overlay-path "${n}"` \
			&& [ -n "${name}" ] || {
			printf '%s\n' "`eval_gettext \
				'problems arised with cachefile ${i}'`" >&2
			exitcode=1
			continue
		}
		l=`EIX_CACHEFILE="${p}" eix --print-overlay-label "${n}"` || \
			l=''
		name="${name##*/}"
		virtual="layman/${name}"
		printf '%s -> %s\n' "${virtual}" "${l:-no repo-name}"
		Replace -g p '\' '\\'
		Replace -g p ':' '\:'
		AddMethod "${virtual}" "eix*:${p}:${n}"
		AddOverlays "${virtual}"
		[ -n "${l}" ] && AddRepoName "${virtual}" "${l}"
		AddExcludes "${LOCAL_LAYMAN}/${name}"
	done
	msg=''
	[ ${exitcode} -ne 0 ] && \
		msg="`eval_gettext 'could not read all eix cachefiles of ${a}'`"
	die_on_update_failure=false
	export KEEP_VIRTUALS
	KEEP_VIRTUALS=:
	CallUpdate || {
		exitcode=${?}
		msg=`gettext 'eix-update failed'; \
			[ -n "${msg}" ] && printf '\n%s' "${msg}"`
	}
	[ -z "${msg}" ] && return
	msg=`printf '%s' "${msg}"; BugReport "${a}"`
	die "${msg}"
}

FetchCopy() {
	GetFilename "${@}"
	FetchTemp
	[ -z "${filename}" ] && return
	(
		[ "${UID}" -eq 0 ] && umask 002
		cp --preserve=timestamps -- "${tmpfile}" "${filename}"
	)
	[ "${UID}" -eq 0 ] && chown -- portage:portage "${filename}"
}

Fetch() {
	need_arg=:
	FetchCopy "${@}"
}

Add() {
	need_arg=:
	GetFilename "${@}"
	test -r "${filename}" || \
		die "`eval_gettext 'cannot read ${filename}'`"
	MakeTempDir cd
	AddArchive "${filename}" "${tmpdir}"
}

Remove() {
	ClearUpdateArgs
	AddLocalMethods
	export KEEP_VIRTUALS=false
	CallUpdate
}

Update() {
	FetchCopy "${@}"
	MakeTempSub cd
	AddArchive "${tmpfile}" "${tmpsub}"
}

main_command="${1}"
[ ${#} -gt 0 ] && shift

[ -n "${UID}" ] || UID="`id -u`"

case "${main_command}" in
	update|both)
		Update "${@}";;
	fetch*|get|wget)
		Fetch "${@}";;
	add*)
		Add "${@}";;
	rem*|del*|rm*|sub*)
		Remove "${@}";;
	*)	Usage;;
esac

exit 0
