#!/bin/bash -e

# Helper script to develop/debug mini-buildd.
#
# Quickstart:
#  Enter your dev chroot (preferably sid). sudo should configured.
#  $ cd mini-buildd
#  $ ./devel installdeps
#  $ ./devel update

MBD_HOME=~mini-buildd

# Use first found mirror from sources as default
_read_mirror()
{
	for s in /etc/apt/sources.list $(ls /etc/apt/sources.list.d/*.list 2>/dev/null | sort); do
		[ -z "${MIRROR}" ] || break
		MIRROR=$(grep "^deb " "${s}" 2>/dev/null | head -n1 | cut -d" " -f2)
	done
	read -p "Mirror: " -e -i "${MIRROR}" MIRROR
}

_head()
{
	printf "\n=> ${*}\n"
}

_check_prog()
{
	local path
	for path in $(printf "${PATH}" | tr ":" " "); do
		local prog="${path}/${1}"
		if [ -x "${prog}" ]; then
			printf "I: Found: ${prog}.\n"
			return 0
		fi
	done
	printf "E: '${1}' not found in path; please install.\n" >&2
	printf "I: You may use './devel installdeps' to install all deps needed.\n" >&2
	exit 1
}

PYPATH="$(readlink -f $(dirname $0))"
DJSETTINGS="doc.django_settings"
PYLINTRC="${PYPATH}/.pylintrc"

mbd_installdeps()
{
	sudo apt-get update
	sudo apt-get --no-install-recommends install devscripts equivs

	# Debian package build dependencies; using target-release=*
	# here to always allow highest versions of any sources
	# configured (for example, for backports).
	mk-build-deps --install --root-cmd=sudo --remove --tool="apt-get --no-install-recommends --target-release='*'" 

	# Extra tools needed for checks
	sudo apt-get install --no-install-recommends pep8 pylint pychecker pyflakes python-django-lint python-apt
	# Extra tools needed vc and package building
	sudo apt-get install --no-install-recommends git git-buildpackage
	# binary package dependecies so we can just dpkg -i for testing
	sudo apt-get install --no-install-recommends --target-release='*' sbuild schroot reprepro debootstrap lintian
}

mbd_pyenv()
{
	printf "export PYTHONPATH=\"${PYPATH}\"\n"
	printf "export DJANGO_SETTINGS_MODULE=\"${DJSETTINGS}\"\n"
	printf "export PYLINTRC=\"${PYLINTRC}\""
}

pyenv()
{
	eval "$(mbd_pyenv)"

	# Be sure we have mini_buildd/__init__.py (missing after fresh checkout or brutal git cleans) so it will be recognized as package
	# (this is implicitly always auto-generated by setup.py)
	python ./setup.py --version
}

mbd_pep8()
{
	_check_prog pep8
	(
		set +e
		pyenv
		# squeeze version does not set an error exit status
		t=$(mktemp)
		trap "rm ${t}" EXIT
		pep8 --ignore=E501,E122 doc/conf.py doc/django_settings.py setup.py mini-buildd mini-buildd-tool mini_buildd/ | tee "${t}"
		[ ! -s "${t}" ]
	)
}

mbd_pymisc()
{
	local f regex
	for f in mini-buildd $(find mini_buildd -type f -name "*.py"); do
		for regex in \
			^from\ __future__\ import\ unicode_literals \
			^\#\ -\\*-\ coding:\ utf-8\ -\\*-; do
			printf "Checking '${f}' for '${regex}'..."
			grep --quiet "${regex}" "${f}"
			printf "OK.\n"
		done
		printf "Checking '${f}' for wrong explicit unicode string literals..."
		if ! grep '\bu"' "${f}"; then
			printf "OK.\n"
		else
			return 1
		fi
	done
}

mbd_codespell()
{
	local ups=$(codespell --quiet-level=2 mini-buildd mini-buildd-tool mini_buildd/ doc/)
	if [ -n "${ups}" ]; then
		printf "${ups}\n" >&2
		return 1
	fi
}

mbd_pydoctests()
{
	(
		pyenv
		for m in mini-buildd mini-buildd-tool mini_buildd/*.py mini_buildd/models/*.py; do
			python -m doctest -v ${m}
		done
	)
}

mbd_pyflakes()
{
	_check_prog pyflakes
	(
		pyenv
		pyflakes mini-buildd mini_buildd/
	)
}

mbd_pylintgeneratedmembers()
{
	# Generate all identifiers with "has no xxx member" error. If
	# needed, manually add those that are _actually_
	# false-positive due to django to -> .pylintrc.
	for o in $(${0} pylint | grep "has no.*member" | cut -d"'" -f4 | sort | uniq); do
		printf "${o},"
	done
	printf "\n"
}

mbd_pylint()
{
	[ "$(lsb_release -s -c)" != "squeeze" ] || { printf "W: Skipping pylint on squeeze\n" >&2; return; }
	_check_prog pylint
	(
		pyenv
		pylint --reports=no setup.py mini-buildd mini-buildd-tool mini_buildd/
	)
}

mbd_pychecker()
{
	_check_prog pychecker
	(
		pyenv
		pychecker mini-buildd mini-buildd-tool $(find mini_buildd/ -name "*.py")
	)
}

mbd_pydjangolint()
{
	_check_prog django-lint
	(
		pyenv
		! django-lint mini_buildd/ | grep --invert-match \
			-e "is actually a directory; consider splitting application" \
			-e "BooleanField with default=True will not be reflected in database" \
			-e "Naive tree structure implementation using ForeignKey('self')" \
			-e "ForeignKey missing related_name" \
			-e "URLField uses verify_exists=True default" \
			-e "Model has too many field" \
			-e "Bad option value" \
			-e "^\*"
	)
}

mbd_check()
{
	# 2014 Feb: 'pydjangolint' removed: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=735199
	local tests="pep8 pymisc pydoctests pyflakes pylint"
	for t in ${tests}; do
		printf "=> mbd_${t}\n"
		mbd_${t}
	done
	printf "\nOK. Tests passed: %s\n" "${tests}"
}

mbd_sfood()
{
	_check_prog sfood
	(
		pyenv
		sfood --internal-only mini_buildd/ | sfood-graph | dot -Tpdf >dependency.pdf
		evince --fullscreen dependency.pdf
	)
}

mbd_doc()
{
	python setup.py build_sphinx --source-dir=build/sphinx
}

mbd_purge()
{
	_head "Purging all mini-buildd packages"
	sudo dpkg --purge mini-buildd python-mini-buildd mini-buildd-common

	# Also test mini-buildd's internal sbuild key workaround
	sudo rm -v -f /var/lib/sbuild/apt-keys/*
}

mbd_update()
{
	if [ "${1}" = "nocheck" ]; then
		export DEB_BUILD_OPTIONS+=" nocheck"
	else
		# Run mbd_check, but with option to continue on error
		set +e
		(
			set -e
			mbd_check
		)
		ret=$?
		[ ${ret} -eq 0 ] || read -p "Check failed. Continue anyway? [R]" dummy
		set -e
	fi

	_head "Checking changelog (must be unchanged)..."
	git diff-index --exit-code HEAD debian/changelog
	trap "git checkout debian/changelog" EXIT

	_head "Building snapshot..."
	git dch --snapshot --auto --ignore-branch
	git-buildpackage --git-ignore-new --git-ignore-branch -us -uc

	_head "Installing snapshot..."
	cat <<EOF | sudo debconf-set-selections --verbose -
mini-buildd mini-buildd/admin_password password admin
mini-buildd mini-buildd/options string --verbose --verbose --debug=exception,http,webapp
EOF
	sudo debi

	if [ "${1}" != "nocheck" ]; then
		_head "Checking basic mini-buildd-tool calls"
		local mbd="/usr/bin/mini-buildd-tool localhost:8066"
		${mbd} status
		${mbd} getkey
		${mbd} getdputconf
		${mbd} getsourceslist wheezy
	fi

	printf "Ok, update successful.\n"
}

mbd_all()
{
	mbd_purge
	mbd_update
	time /usr/share/doc/mini-buildd/examples/auto-setup
}

mbd_doc()
{
	python setup.py build_sphinx --source-dir=build/sphinx
}

sep=" "
for c in $(compgen -A function | grep '^mbd_'); do
	ACTIONS+="${sep}${c:4}"
	sep="|"
done
trap "printf '\nUsage: $(basename "${0}")${ACTIONS}[_arg1_arg2..] \n' >&2" ERR

[ "${*}" ]

for ACTION in ${*}; do
	func=$(printf "${ACTION}" | cut -d_ -f1)
	args=""
	if printf "${ACTION}" | grep -q "_"; then
		args=$(printf "${ACTION}" | cut -d_ -f2- | tr "_" " ")
	fi
	mbd_${func} ${args}
done
