#!/bin/sh

. gb-sh-conf

oneliner()
{
	printf %s "$*" |tr -s '[:space:]' ' '
}

stamp_echo()
{
	echo "$(LC_TIME=C date '+%Y-%b-%d %T') :: $(oneliner "$*")"
}

userid_nums()
{
	find gears -mindepth 2 -maxdepth 2 -path 'gears/[1-7]*/userid' -type f 2>/dev/null |
		cut -d/ -f2 |sort -n
}

gear_nums()
{
	find gears -mindepth 2 -maxdepth 2 -path 'gears/[1-7]*/dir' -type f 2>/dev/null |
		cut -d/ -f2 |sort -n
}

src_nums()
{
	find gears -mindepth 2 -maxdepth 2 \( -path 'gears/[1-7]*/dir' -or -path 'gears/[1-7]*/srpm' \) -type f 2>/dev/null |
		cut -d/ -f2 |sort -n
}

package_nums()
{
	find gears -mindepth 2 -maxdepth 2 -path 'gears/[1-7]*/package' -type f 2>/dev/null |
		cut -d/ -f2 |sort -n
}

copy_nums()
{
	find gears -mindepth 2 -maxdepth 2 -path 'gears/[1-7]*/copy_repo' -type f 2>/dev/null |
		cut -d/ -f2 |sort -n
}

build_nums()
{
	find build -mindepth 3 -maxdepth 3 \( -path 'build/[1-7]*/*/srpm' -or -path 'build/[1-7]*/*/rpms' \) -type d 2>/dev/null |
		cut -d/ -f2 |sort -nu
}

_N="%{name}"
_VR="%{version}-%{release}"
_EVR="%|epoch?{%{epoch}:}|$_VR"
_NVR="%{name}-$_VR"
_A="%{arch}"
qf_src="$_N\\t$_EVR\\t$_NVR.src.rpm\\n"
qf_bin="$_N\\t$_EVR\\t$_A\\t$_NVR.$_A.rpm\\t%{sourcerpm}\\n"

qsrc()
{
	local d
	for d; do
		# src-N  src-EVR  src-F
		find "$d" -name '*.src.rpm' -execdir \
			rpmquery --qf "$qf_src" -p -- '{}' '+'
	done
}

qbin()
{
	local d
	for d; do
		# bin-N  bin-EVR  bin-A  bin-F  src-F
		find "$d" -name '*.rpm' -not -name '*.src.rpm' -execdir \
			rpmquery --qf "$qf_bin" -p -- '{}' '+'
	done
}

# Now what's the plan?  I guess we don't just move some files around.
# We deal with "tuples" (src,bin+).  Therefore, the consistent plan is
# to group files into such tuples, and decide how new tuples replace
# the existing tuples.
#
# Thus we have to assume that the repo is consistent: both src->bin+
# and bin->src mappings must exist for every package in the repo.  Stale
# packages cannot be handled by the plan consistently, and removing them
# is someone else's job.
#
# Tuples are represented with the following table:
#
# src-N  src-EVR  src-F  bin-N  bin-EVR  bin-A  bin-F
# -----  -------  -----  -----  -------  -----  -----
#
# Note: the fact that both mappings mentioned above exist roughly means
# that we can join src+bin on %{SOURCERPM}.  This is how we do the table.

mktable()
{
	local x="$1"; shift
	# sort by src-F field
	sort -k3 -o "$x.src"{,}
	sort -k5 -o "$x.bin"{,}
	# join by src-F field
	join -t$'\t' -13 -25 -o '1.1 1.2 1.3 2.1 2.2 2.3 2.4' -- "$x".{src,bin} >"$x"
	sort -u -o "$x"{,}
}

make_repo_table()
{
	local pocket=
	local repo="${1-}"
	if [ "$repo" = "-p" ]; then
		shift; pocket="${1-}"
		[ -n "$pocket" ] || return 1

		local pocket_dir="$GB_POCKETS_DIR/$pocket"
		local pocket_repo_file="$pocket_dir/files/pocket/repo"
		[ -d "$pocket_dir" ] || return 2
		[ -f "$pocket_repo_file" ] || return 3

		repo="$(cat "$pocket_repo_file")"
	else
		[ -n "$repo" ] || repo="$GB_REPO_NAME"
	fi

	local out="${2:-$repo}"
	[ -z "$pocket" ] ||
		out="${2:-$pocket}"

	if [ -s "$out" ]; then
		return 0
	fi

	local repo_dir repo_flavour
	if [ -z "$pocket" -a "$repo" = "$GB_REPO_NAME" ]; then
		repo_dir="$GB_REPO_DIR"
		repo_flavour="$GB_REPO_FLAVOUR"
	else
		repo_dir="$(unset GB_REPO_DIR &&
			    . $GB_CONF_DIR/gb-sh-conf-$repo &&
			    printf %s "$GB_REPO_DIR")"
		repo_flavour="$(unset GB_REPO_DIR &&
			    . $GB_CONF_DIR/gb-sh-conf-$repo &&
			    printf %s "$GB_REPO_FLAVOUR")"
		if [ -n "$pocket" ]; then
			repo_dir="$(unset GB_REPO_DIR &&
				    . $GB_CONF_DIR/gb-sh-conf-$repo &&
				    . $GB_POCKETS_DIR/$pocket/files/pocket/gb-sh-conf &&
				    printf %s "$GB_REPO_DIR")"
			repo_flavour="$(unset GB_REPO_DIR &&
				    . $GB_CONF_DIR/gb-sh-conf-$repo &&
				    . $GB_POCKETS_DIR/$pocket/files/pocket/gb-sh-conf &&
				    printf %s "$GB_REPO_FLAVOUR")"
		fi
	fi

	local arch
	if [ -s "$repo_dir/files/list/src.list" ]; then
		sort -u "$repo_dir/files/list/src.list" >"$out.src"
	else
		if use_repo_files; then
			qsrc "$repo_dir"/files/SRPMS/
		else
			for arch in $GB_ARCH noarch; do
				qsrc "$repo_dir"/$arch/SRPMS.$repo_flavour/
			done
		fi >"$out.src"
		sort -u -o "$out.src"{,}
	fi

	if [ -s "$repo_dir/files/list/bin.list" ]; then
		sort -u "$repo_dir/files/list/bin.list" >"$out.bin"
	else
		for arch in $GB_ARCH noarch; do
			if use_repo_files; then
				qbin "$repo_dir"/files/$arch/RPMS/
			else
				qbin "$repo_dir"/$arch/RPMS.$repo_flavour/
			fi
		done >"$out.bin"
		sort -u -o "$out.bin"{,}
	fi

	mktable "$out"
}

set_GIT_DIR()
{
	local prefix="$1"; shift
	local project="$1"; shift
	local sym="$(printf %s "$project" |cut -c1)"
	GIT_DIR="$prefix/$sym/$project.git"
	export GIT_DIR
}

git_get_branch_id()
{
	local name="$1"; shift
	[ -n "${name:1}" ]
	git rev-parse --branches="[${name:0:1}]${name:1}"
}

# When replacing packages, versions must increase.
vercheck()
{
	local EVR1="${1:?}" EVR2="${2:?}"
	[ "$(rpmevrcmp "$EVR1" "$EVR2")" -lt 0 ] || return 1
}

halt_build_queue()
{
	echo "${0##*/} failed in $PWD" >>"$GB_STOP_FILE"
	stamp_echo >&2 '*** BUILD QUEUE HALTED ***'
	return 1
}

fail_if_task_abort_requested()
{
	if [ -f task/abort ]; then
		stamp_echo >&2 'task processing ABORTED'
		exit 1
	fi
}

is_check_failure_tolerated()
{
	local n
	for n in ${GB_LIST_OF_CHECKS_ALLOWED_TO_FAIL-}; do
		[ "${0##*/}" = "$n" ] || continue
		return 0
	done
	return 1
}

init_pocket()
{
	local TASK_DIR="$GB_TASKS_DIR/$1/task"
	if [ -f "$TASK_DIR/pocket" ]; then
		: ${GB_POCKETS_DIR:?}
		local pocket=$(cat "$TASK_DIR/pocket")
		. "$GB_POCKETS_DIR/$pocket/files/pocket/gb-sh-conf"
		umask 0002
		cat "$GB_REPO_SOURCES" "$GB_REPO_SELF_SOURCES" >"$TASK_DIR/sources.list"
		sed -e "s|@GB_POCKETS_DIR@|$GB_POCKETS_DIR|" "$GB_POCKETS_SOURCES" >>"$TASK_DIR/sources.list"
	fi
}

list_notifiable_pkg_acl_members()
{
	local n="$1"; shift

	gb-x-girar acl-show "$GB_REPO_NAME" "$n" |
		cut -f2- |
		tr ' ' '\n' |
		egrep -vx '@(nobody|everybody|qa)' |
		cat
}

suffix_arch()
{
	local IFS=.
	set -- $1
	shift $(($#-2))
	echo $1
}

use_repo_files()
{
	local check="$GB_REPO_USE_FILES"
	if [ "$#" -gt 0 ]; then
		check="$1"
	fi
	test "$check" = 'yes'
}
