#!/bin/bash

# helper script to build tor debian releases.
#
# Usage: [GITDIR=.../tor] $0 <orig.tar.gz> [debian-revision]
#
# Given a Tor git tree and an orig.tar.gz, builds a tor source package
# and backport source packages for many Debian and Ubuntu suites.
#
# This script is used both manually by the maintainer, e.g. when preparing
# uploads to security.d.o, as well as the Tor jenkins instance when building
# release builds.  As of 2017, the latter only uses the backport_all function
# from this script.

# Copyright 2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017 Peter Palfrader
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

assert_files_dont_exist () {
	local pkg="$1"; shift
	local debian_version="$1";
	if [ -z "$debian_version" ]; then
		echo "assert_files_dont_exist called without debian_version" >&2
		exit 1;
	fi

	if [ -e "${pkg}_$debian_version.diff.gz" ] ; then
		echo "${pkg}_$debian_version.diff.gz already exists" >&2
		exit 1;
	fi
	if [ -e "${pkg}_$debian_version.dsc" ] ; then
		echo "${pkg}_$debian_version.dsc already exists" >&2
		exit 1;
	fi
	if [ -e "${pkg}_$debian_version""_amd64.deb" ] ; then
		echo "${pkg}_$debian_version""_amd64.deb already exists" >&2
		exit 1;
	fi
	if [ -e "${pkg}_$debian_version""_amd64.changes" ] ; then
		echo "${pkg}_$debian_version""_amd64.changes already exists" >&2
		exit 1;
	fi
}

get_debian_version() {
	local dir="$1"; shift
	local which="${1:-}"; shift

	if [ -z "$which" ]; then
		( cd $dir && dpkg-parsechangelog | grep-dctrl -n -s Version '' )
	else
		local v=$(get_debian_version $dir)
		case "$which" in
			upstream) echo "${v%-*}" ;;
			debrev) echo "${v##*-}" ;;
			*)
				echo >&2 "Unknown key '$which' in get_debian_version"
				exit 1
		esac
	fi
}

# remove_completely ... 0 replace hardening-includes with hardening-wrapper
#                       1 get rid entirely
hardening_backport() {
	local remove_completely="$1"

	sed -i -e '/^Build-Depends/ s/, *hardening-includes//' debian/control
	if [ "$remove_completely" = 0 ]; then
		sed -i -e '/^Build-Depends/ s/$/, hardening-wrapper/' debian/control
	fi

	if [ "$remove_completely" = 0 ]; then
		sed -i -e 's#include /usr/share/hardening-includes/hardening.make#export DEB_BUILD_HARDENING=1#' debian/rules
		sed -i -e '/export DEB_BUILD_HARDENING=1/ a export DEB_BUILD_HARDENING_DEBUG=1' debian/rules
	else
		sed -i -e 's#include /usr/share/hardening-includes/hardening.make##' debian/rules
	fi

	if [ "$remove_completely" = 0 ]; then
		dch --append "Replace hardening-includes use with hardening-wrapper."
	else
		dch --append "Completely remove hardening-includes use."
	fi
}

remove_libzstd() {
	if grep -q libzstd-dev debian/control; then
		sed -i -e '/^Build-Depends/ s/, *libzstd-dev\( *\[[^]]*\]\)\?//' debian/control
		dch --append "Remove libzstd-dev build dependency for backport."
	fi
}

old_debug_pkg() {
	patch debian/rules << EOF
diff --git a/debian/rules b/debian/rules
index 6950e6d3c..af002ae52 100755
--- a/debian/rules
+++ b/debian/rules
@@ -70,7 +70,10 @@ override_dh_install-arch:
 	cp debian/tor.apparmor-profile.abstraction debian/tor/etc/apparmor.d/abstractions/tor
 	dh_apparmor --profile-name=system_tor -ptor
 
+override_dh_installdocs:
+	dh_installdocs -ptor-dbg --link-doc=tor
+	dh_installdocs
 override_dh_strip:
-	dh_strip --dbgsym-migration='tor-dbg (<< 0.3.1.5-alpha)'
+	dh_strip --dbg-package=tor-dbg
 override_dh_installinit:
 	dh_installinit --error-handler=tor_error_init
EOF
  cat >> debian/control << 'EOF'

Package: tor-dbg
Architecture: any
Depends: tor (= ${binary:Version}), ${misc:Depends}
Suggests: gdb
Priority: extra
Section: debug
Description: debugging symbols for Tor
 This package provides the debugging symbols for Tor, The Onion Router.
 Those symbols allow your debugger to assign names to your backtraces, which
 makes it somewhat easier to interpret core dumps.
EOF

	dch --append "Restore building of tor-dbg."
	sed -i -e '/^Build-Depends/ s/debhelper [^,]*, */debhelper (>= 9), /' debian/control
	dch --append "Downgrade debhelper build dependency to just >= 9."
}



bp1() {
	local pkg="$1"; shift
	local dir="$1"; shift
	local sid_debian_version="$1"; shift
	local dist="$1"; shift

	dpkg-source -x ${pkg}_$sid_debian_version.dsc
	(cd $dir; backport $dist)
}
bp2() {
	local pkg="$1"; shift
	local dir="$1"; shift
	local origtar="$1"; shift

	local debian_version=$(get_debian_version $dir)
	assert_files_dont_exist $pkg $debian_version
	dpkg-source -b $dir $origtar
	rm -r $dir
}

backport_all() {
	local pkg="$1"; shift
	local dir="$1"; shift
	local origtar="$1"; shift
	local sid_debian_version="$1"; shift

	# sid
	#################################################
	# null

	# jessie
	#################################################
	bp1 $pkg $dir $sid_debian_version jessie
	(cd $dir; remove_libzstd)
	(cd $dir; old_debug_pkg)
	bp2 $pkg $dir $origtar

	# stretch
	#################################################
	bp1 $pkg $dir $sid_debian_version stretch
	bp2 $pkg $dir $origtar

	# buster
	#################################################
	bp1 $pkg $dir $sid_debian_version buster
	bp2 $pkg $dir $origtar

	# bullseye
	#################################################
	bp1 $pkg $dir $sid_debian_version bullseye
	bp2 $pkg $dir $origtar


	# xenial (EOL: Apr 2021)
	#################################################
	bp1 $pkg $dir $sid_debian_version xenial
	bp2 $pkg $dir $origtar

	# bionic (EOL: Apr 2023)
	#################################################
	bp1 $pkg $dir $sid_debian_version bionic
	bp2 $pkg $dir $origtar

	# eoan (EOL: Jul 2020)
	#################################################
	bp1 $pkg $dir $sid_debian_version eoan
	bp2 $pkg $dir $origtar

	# focal (EOL: 2025-04)
	#################################################
	bp1 $pkg $dir $sid_debian_version focal
	bp2 $pkg $dir $origtar

	# groovy (EOL: 2021-07)
	#################################################
	bp1 $pkg $dir $sid_debian_version groovy
	bp2 $pkg $dir $origtar

	#################################################
	## BPO
	#################################################

}

main() {
	local origtar="$1"; shift
	local deb_revision="$1"; shift
	local gitdir="$1"; shift
	local pkg="$1"; shift

	[ -d local-build ] || mkdir local-build

	if [ -z "$origtar" ] ; then
		echo "Usage: $0 <orig.tar.gz> [debian-revision]" >&2
		exit 1;
	fi


	if [ ! -e "$origtar" ] ; then
		echo "$origtar does not exist." >&2
		exit 1;
	fi

	if [ "${origtar#${pkg}-}" != $origtar ]; then
		ver="$origtar"
		ver=${ver#${pkg}-}
		ver=${ver%.tar.gz}
		neworig="${pkg}_$ver.orig.tar.gz"
		if ! [ -e "$neworig" ]; then
			ln -v "$origtar" "$neworig"
		fi
		echo "Using $neworig instead of $origtar"
		origtar="$neworig"
	fi

	local dir
	local dir_version
	dir=`tar tzf $origtar 2>/dev/null | head -n1`
	dir="${dir%%/}"
	dir_version="${dir##${pkg}-}"
	if [ -e "$dir" ] ; then
		echo "$dir already exists." >&2
		exit 1;
	fi
	tar xzf $origtar
	git clone -n -s "$gitdir" git-"$dir"
	local tag="debian-${pkg}-$dir_version-${deb_revision//\~/_}"
	(cd "git-$dir" && git checkout $tag)
	if diff -qr "git-$dir" "$dir" --exclude .git  | grep -v '^Only in ' | grep --color .; then
		echo "Differenced detected."
		exit 1
	fi
	(cd "git-$dir" && echo "\"`git rev-parse --short=16 "$tag"`\"" > "debian/micro-revision.i")
	cp -av "git-$dir/debian" "$dir"
	rm -rf "git-$dir"


	debian_upstream_version=$(get_debian_version $dir upstream)
	if [ "$origtar" != "${pkg}_$debian_upstream_version.orig.tar.gz" ] ; then
		echo "possible mismatch: $origtar but $debian_upstream_version in debian/changelog" >&2
		exit 1;
	fi

	debian_version=$(get_debian_version $dir)
	sid_debian_version="$debian_version"
	assert_files_dont_exist $pkg $debian_version
	dpkg-source -b $dir $origtar
	rm -r $dir



	# local
	#################################################
	cd local-build
	dpkg-source -x ../${pkg}_$debian_version.dsc
	cd ${pkg}-$debian_upstream_version
	debuild -j8 -rfakeroot -uc -us
	cd ../..


	[ "$DO_BACKPORTS" -gt 0 ] && backport_all "$pkg" "$dir" "$origtar" "$sid_debian_version"

	echo
	echo "All done"
}

usage() {
  cat << EOF
Usage: $0 [-B] <tor-xyz.tar.gz>
EOF
}

# this is hardcoded to weasel's directory layout. sorry.
case "$(basename $0)" in
	build-tor-sources)
		DO_BACKPORTS=1
		while getopts "hB" option; do
			case "$option" in
				h)
					usage
					exit
					;;
				B)
					DO_BACKPORTS=0
					;;
				*)
					usage >&2
					exit 1
					;;
			esac
		done
		shift $(($OPTIND - 1))

		set -e
		set -x
		GITDIR="${GITDIR:-$HOME/projects/tor/tor}"
		if ! [ -e "$GITDIR/.git" ] ; then
			echo >&2 "\$GITDIR does not exist or does not have a .git.  It needs to point to the tor git repository."
			exit 1
		fi
		PKG="tor"
		DO_BPO=1
		main "${1:-}" ${2:-1} $GITDIR $PKG
		;;
esac
