#!/bin/sh

set -e

ORIGIN="Jones"
LABEL="Jones"
DISTS="lenny squeeze wheezy sid"
ARCHS="i386 powerpc amd64"

PRVBASE=~/public_debian
PUBBASE=~/public_websites/debian.jones.dk
#PUBTOSRC=../../public_debian

debugprint() {
	[ -n "$DEBUG" ] || return 0
	debuglevel="${2:-1}"
	[ "$DEBUG" -ge "$debuglevel" ] || return 0
	echo 1>&2 "$1"
}

compactlist() {
	( for item in $@; do echo $item; done ) \
		| sort -u \
		| tr '\n' ' ' \
		| sed 's/[[:space:]]\+/ /g; s/^[[:space:]]//; s/[[:space:]]$//'
}

regexfromlist() {
	echo $@ | sed 's/[[:space:]]\+/|/g; s/^/(/; s/$/)/'
}

sectionsfromhintstream() {
	perl -ne 's/^Sections:\W*// && do { s/\W*,\W*/\n/g; s/\W*$/\n/; print; }'
}

pkginfofromprvpkgdir() {
	package="$(basename "$1")"
	pool="$(dirname "$1" | sed 's,.*/pool-\([^/]\+\)/\?.*,\1,; s,-all$,,')"
	dist="$(echo "$pool" | sed 's,[^a-z].*$,,')"
	buildhost="$(echo $(dirname "$@") | sed 's,^\([^/]\+\)/pool-.*,\1,')"

	echo "$package $pool $dist $buildhost"
}

archsfromdirs() {
	archs="$( \
		find "$@" -type l -exec find '{}'/ -type f -name '*.deb' ';' \
			| sed 's/^.*_\([a-z0-9-]\+\)\.deb$/\1/; s/\ball\b/'"$ARCHS"'/g' \
	)"
	archs="$(compactlist $archs)"
	debugprint "Archs found: \"$archs\"" "2"
	for arch in $archs; do
		valid=
		for arch_supported in $ARCHS; do
			case $arch in
			    $arch_supported)
				debugprint "Arch ok: \"$arch\"" "2"
				echo "$arch"
				valid=1
				;;
			esac
		done
		if [ -z "$valid" ]; then
			# TODO: Optionally just skip
			echo 1>&2 "ERROR: Unsupported architecture: \"$arch\"."
			exit 1
		fi
	done
}

distsfromprvgrpdirs() {
	dists="$( \
		find "$@" -type l -exec find '{}'/ -type f -name '*.deb' ';' \
			| sed 's,^.*/sections/[^/]*/\([^/]\+\)/.*$,\1,' \
	)"
	dists="$(compactlist $dists)"
	debugprint "Dists found: \"$dists\"" "2"
	for dist in $dists; do
		valid=
		for dist_supported in $DISTS; do
			case $dist in
			    $dist_supported)
				debugprint "Dist ok: \"$dist\"" "2"
				echo "$dist"
				valid=1
				;;
			esac
		done
		if [ -z "$valid" ]; then
			# TODO: Optionally just skip
			echo 1>&2 "ERROR: Unsupported distribution: \"$dist\"."
			exit 1
		fi
	done
}

genlist() {
	section="$1"
	dist="$2"
	arch="$3"
	srcdir="$4"
	basedir="$5"
	case "$arch" in
	    source)
		destdir="$basedir/source";
		cmd="dpkg-scansources";
		file="Sources";
		;;
	    *)
		destdir="$basedir/binary-$arch";
		cmd="dpkg-scanpackages -a$arch";
		file="Packages";
		;;
	esac
	mkdir -p "$destdir"
	debugprint "genlist: \"$cmd . /dev/null pkg/$section/\"" "2"
	if [ -n "$DEBUG" ] && [ "$DEBUG" -ge 2 ]; then
		( cd "$srcdir" && $cmd . /dev/null pkg/$section/ ) > "$destdir/$file"
	else
		( cd "$srcdir" && $cmd . /dev/null pkg/$section/ ) > "$destdir/$file" 2> /dev/null
	fi
	if [ -s "$destdir/$file" ]; then
		debugprint "Finalizing list at \"$destdir/\"" "2"
		gzip -c "$destdir/$file" > "$destdir/$file.gz"
		bzip2 -c "$destdir/$file" > "$destdir/$file.bz2"
		cat <<EOF > "$destdir/Release"
Archive: $dist
Component: $section
Origin: $ORIGIN
Label: $LABEL
Architecture: $arch
EOF
	else
		debugprint "purge empty list at \"$destdir/\"" "2"
		rm -f "$destdir/$file" "$destdir/$file.gz" "$destdir/$file.bz2" "$destdir/Release"
		rmdir -p --ignore-fail-on-non-empty "$destdir"
	fi
}

genrelease() {
	dist="$1"
	shift
	sections="$@"
	archs="$(archsfromdirs "$PRVBASE/sections"/*/"$dist")"
	archs="$(compactlist $archs)"
	case "$dist" in
	    etch) suite="oldstable";;
	    lenny) suite="stable";;
	    squeeze) suite="testing";;
	    sid) suite="unstable";;
	esac
	cat <<EOF > "$PUBBASE/dists/$dist/Release"
Origin: $ORIGIN
Label: $LABEL
Suite: $suite
Codename: $dist
Architectures: $archs
Components: $sections
EOF
}

packages="$@"
packages="$(compactlist $packages)"
debugprint "Packages: \"$packages\""

case "$packages" in
    -a|--all)
	pkg_re=".*"
	;;
    "")
	echo 1>&2 "ERROR: No package(s) provided."
	exit 1
	;;
    *)
# FIXME: tighten to avoid \b (which wrongly includes - )
	pkg_re="\b$(regexfromlist $packages)\b"
	;;
esac

# Find packages in $prvpkgdir belonging to $sections
#
#   $PRVBASE/$buildhost/pool-$pool/$package/
#
batchsections="$( \
	find "$PRVBASE" -type f -regextype egrep -regex '.*/'"$pkg_re"'/HINTS' -exec cat '{}' ';' \
		| sectionsfromhintstream
)"
batchsections="$(compactlist $batchsections)"
debugprint "Sections in batch: \"$batchsections\""

batchsections_re=
if [ -n "$batchsections" ]; then
	batchsections_re="\b$(regexfromlist ${batchsections/+/\\\\+})(\s|\Z)"
else
	echo 1>&2 "ERROR: Package(s) $@ was not found in any section."
	exit 1
fi

echo "Clean dangling symlinks..."
if [ -n "$DEBUG" ] && [ "$DEBUG" -ge 3 ]; then
	echo "Clean dangling symlinks below \"$PRVBASE\" and \"$PUBBASE\"..."
	debugprint "symlinks -dr ${DEBUG:+-v} \"$PRVBASE\" \"$PUBBASE\""
	symlinks -dr ${DEBUG:+-v} "$PRVBASE" "$PUBBASE"
else
	symlinks -dr ${DEBUG:+-v} "$PRVBASE" "$PUBBASE" > /dev/null
fi

# Create/update symlink farms $prvgrpdir and $pubpkgdir
#
#   $PRVBASE/sections/$section/$dist/$section/$package/$pool/$buildhost
#   $PUBBASE/pkg/$package/$pool/$buildhost
#
cd "$PRVBASE" && find * -type f -name HINTS -exec grep -Pq "^Sections:.*$batchsections_re" '{}' ';' -printf '%h\n' \
	| while read prvpkgdir; do
	debugprint "prvpkgdir: \"$prvpkgdir\""
	set -- $(pkginfofromprvpkgdir "$prvpkgdir")
	package="$1" pool="$2" dist="$3" buildhost="$4"
	shift 4
	pkgsections="$(cat "$PRVBASE/$prvpkgdir/HINTS" | sectionsfromhintstream)"
	pkgsections="$(compactlist $pkgsections)"
	for section in $pkgsections; do
		subdir="$section/$package/$pool"
		mkdir -p "$PUBBASE/pkg/$subdir"
		ln -sf -T "$PRVBASE/$prvpkgdir" "$PUBBASE/pkg/$subdir/$buildhost"
		mkdir -p "$PRVBASE/sections/$section/$dist/$subdir"
		ln -sf -T "../../../../../../$prvpkgdir" "$PRVBASE/sections/$section/$dist/$subdir/$buildhost"
	done
done

# Create/update package lists
#
#   $PUBBASE/dists/$dist/$section/{binary-$arch,source}
#
[ -n "$DEBUG" ] || printf "Creating/updating package sections:"
for section in $batchsections; do
	[ -n "$DEBUG" ] || printf " $section"
	dists="$(distsfromprvgrpdirs "$PRVBASE/sections/$section")"
	for dist in $dists; do
		if [ -n "$DEBUG" ]; then
			debugprint "genlists \"\$PRVBASE/sections/$section/$dist\" -> \"\$PUBBASE/dists/$dist/$section\""
		else
			printf .
		fi
		prvgrpdir="$PRVBASE/sections/$section/$dist/$section"
		pubpkgdir="$PUBBASE/dists/$dist/$section"
		archs="$(archsfromdirs "$prvgrpdir")"
		for arch in $archs; do
			genlist "$section" "$dist" "$arch" "$prvgrpdir" "$pubpkgdir"
		done
		[ -z "$archs" ] || genlist "$section" "$dist" "source" "$prvgrpdir" "$pubpkgdir"
	done
done
[ -n "$DEBUG" ] || echo " - Done!"

# Create/update Release files
#
#   $PUBBASE/dists/$dist/Release
#
[ -n "$DEBUG" ] || printf "Creating/updating release files:"
allsections="$( \
	find "$PRVBASE" -type f -name HINTS -exec cat '{}' ';' \
		| sectionsfromhintstream
)"
allsections="$(compactlist $allsections)"
debugprint "All sections: \"$allsections\"" "2"

dists="$(distsfromprvgrpdirs "$PRVBASE/sections")"
dists="$(compactlist $dists)"
for dist in $dists; do
	[ -n "$DEBUG" ] || printf " $dist"
	genrelease "$dist" ${allsections}
done
[ -n "$DEBUG" ] || echo " - Done!"

exit 0