#!/bin/sh

PROGNAME=`basename $0`
OUTDIR="./"

usage() {
	echo "usage: $PROGNAME architecture Packages Sources [pkgname]" >&2
	echo >&2
	echo "Find the reasons why source packages are B-D transitive essential." >&2
	echo "Assumes that Architecture:all packages need not be bootstrapped." >&2
	echo "Operates on the strong dependency graph." >&2
	echo >&2
	echo "If the optional \"pkgname\" argument is specified as well, then only" >&2
	echo "the results for that one package will be output." >&2
	echo >&2
	echo " -h, --help       Show this help message and exit" >&2
	echo " -k, --keep       Keep the temporary files" >&2
	echo " -T, --timers     time all program executions" >&2
	echo " -o, --output=DIR Output directory. Default is the current directory" >&2
	echo " -t, --tmp=DIR    Temporary directory. Default is created by mktemp(1)" >&2
	echo " -v, --verbose    Be more verbose" >&2
	echo " -d, --debug      Maximum verbosity" >&2
	echo " -D, --develop    Execute tools from the source checkout instead of \$PATH" >&2
}


die() {
	echo " + error $@"
	if [ -n "$KEEP" ] || [ "$CUSTOMTMP" = "yes" ]; then
		echo " + temporary files stored in $tmp" >&2
	else
		rm -f "$tmp"/*
		rm -fd $tmp
	fi
	exit 1
}

run() {
	if [ -n "$TIMERS" ]; then
		time --format "%e seconds" "$@"
	else
		"$@"
	fi
}

# clean up when sighup, sigint or sigterm is received
trap "die \"got signal\"" 1 2 15

getopt -T > /dev/null && exitcode=0 || exitcode=$?
if [ $exitcode -eq 4 ]; then
	# GNU enhanced getopt is available
	ARGS=`getopt --long help,keep,timers,output:,tmp:,verbose,debug,develop --options hkTo:t:vdD -- "$@"`
else
	# Original getopt is available
	ARGS=`getopt hkTo:t:vdD "$@"`
fi

if [ $? -ne 0 ]; then
	exit 1
fi

eval set -- $ARGS

while [ $# -gt 0 ]; do
	case "$1" in
		-h | --help)     usage; exit 0;;
		-k | --keep)     KEEP=true;;
		-T | --timers)   TIMERS=true;;
		-o | --output)   OUTDIR="$2"; shift;;
		-t | --tmp)      tmp="$2"; shift;;
		-v | --verbose)  VERBOSE=--verbose;;
		-d | --debug)    set -x;;
		-D | --develop)  DEVELOP=true;;
		--)              shift; break;;
	esac
	shift
done

bin_buildcheck=dose-builddebcheck
if [ -n "$DEVELOP" ]; then
	[ -f ./bin2src.native ] && bin_bin2src=./bin2src.native || bin_bin2src=./bin2src.d.byte
	[ -f ./create-graph.native ] && bin_create_graph=./create-graph.native || bin_create_graph=./create-graph.d.byte
	bin_latest_version=./tools/latest-version.py
	bin_graph_shortest_path=./tools/graph-shortest-path.py
	bin_graphml2dot=./tools/graphml2dot.py
	bin_graph2text=./tools/graph2text.py
else
	bin_bin2src=botch-bin2src
	bin_create_graph=botch-create-graph
	bin_selfcycles=botch-selfcycles
	bin_latest_version=botch-latest-version
	bin_graph_shortest_path=botch-graph-shortest-path
	bin_graphml2dot=botch-graphml2dot
	bin_graph2text=botch-graph2text
fi

mkdir -p "$OUTDIR"

if [ $# -ne 3 -a $# -ne 4 ]; then
	usage
	exit 1
fi

arch="$1"
packages="$2"
sources="$3"
pkgname="$4"

if [ -n "$tmp" ]; then
	mkdir -p "$tmp"
else
	tmp=`mktemp --directory`
	CUSTOMTMP="no"
fi

if [ "$KEEP" != "true" ]; then
	if [ -n "$(ls -A $tmp)" ]; then
		echo "$tmp is not empty and you did not specify --keep" >&2
		echo "refusing to run and delete that directory" >&2
		exit 1
	fi
fi

zcat -f "$packages" | grep-dctrl --exact-match -F Architecture all > "$tmp/available-noall"

zcat -f "$packages" | grep-dctrl --exact-match --field Package build-essential \
	| run $bin_latest_version - - \
	| run $bin_bin2src --deb-native-arch="$arch" - "$sources" \
	| run $bin_create_graph --verbose --progress \
		--deb-native-arch="$arch" --strongtype \
		--available "$tmp/available-noall" --bg "$sources" "$packages" - \
	> "$tmp/buildgraph.xml"

found="no"
run $bin_graph2text ${tmp}/buildgraph.xml "{name} {version} {__ID__}" --vertices type:src \
	| sort \
	| while read name version vertex; do
		if [ -n "$pkgname" -a "$pkgname" != "$name" ]; then
			continue
		fi
		found="yes"
		fname="${name}_${version}_${vertex}"
		run $bin_graph_shortest_path ${tmp}/buildgraph.xml ${tmp}/${fname}.xml --source name:build-essential --target __ID__:$vertex || die "botch-graph-shortest-path failed"
		run $bin_graphml2dot ${tmp}/${fname}.xml ${OUTDIR}/${fname}.dot || die "botch-graphml2dot failed"
		run dot -Tpng ${OUTDIR}/${fname}.dot > ${OUTDIR}/${fname}.png || die "dot failed"
		# execute graph-easy but do not fail if it doesn't exist or doesn't work as advertised
		# redirect graph output to standard error because this tool is
		# not supposed to create something on standard output to then
		# be piped somewhere else
		{ graph-easy --input ${OUTDIR}/${fname}.dot --as_ascii || true; } | tee ${OUTDIR}/${fname}.txt >&2
	done

if [ -n "$pkgname" -a "$found" != "yes" ]; then
	echo "$pkgname is not part of the b-d-transitive-essential set" >&2
fi

if [ -n "$KEEP" ] || [ "$CUSTOMTMP" = "yes" ]; then
	echo " + temporary files stored in $tmp" >&2
else
	rm -f "$tmp"/*
	rm -fd $tmp
fi
