#!/bin/sh
# vim: filetype=zsh

set -e

# I use this in EVERY shell script ;)
LF="
"

d00=`pwd`
while ! [ -f ./all ]; do
	if [ x"`pwd`" = x"/" ]; then
		echo "Cannot find myself."
		echo "Please run this script with the working directory inside a Xonotic checkout."
		exit 1
	fi
	cd ..
done
d0=`pwd`
SELF="$d0/all"

# If we are on WINDOWS:
case "$0" in
	all|*/all)
		case "`uname`" in
			MINGW*|Win*)
				# Windows hates users. So this script has to copy itself elsewhere first...
				tname=
				cp "$SELF" ../all.xonotic.sh
				export WE_HATE_OUR_USERS=1
				exec ../all.xonotic.sh "$@"
				;;
		esac
		;;
esac

msg()
{
	echo "$*"
}

checksum()
{
	if [ -x /usr/bin/md5sum ]; then
		/usr/bin/md5sum "$@"
	elif [ -x /bin/md5sum ]; then
		/bin/md5sum "$@"
	elif [ -x /usr/bin/cksum ]; then
		/usr/bin/cksum "$@"
	else
		echo "NOCHECKSUM"
	fi
}

self=`checksum "$SELF"`
checkself()
{
	self_new=`checksum "$SELF"`
	if [ x"$self" != x"$self_new" ]; then
		msg "./all has changed."
		if [ -z "$XONOTIC_FORBID_RERUN_ALL" ]; then
			msg "Rerunning the requested operation to make sure."
			export XONOTIC_FORBID_RERUN_ALL=1
			exec "$SELF" "$@"
		else
			msg "Please try $SELF update, and then retry your requested operation."
			exit 1
		fi
	fi
	return 0
}

verbose()
{
	msg "+ $*"
	"$@"
}

visible_repo_name()
{
	case "$1" in
		.)
			echo "the root directory"
			;;
		*)
			echo "\"$1\""
			;;
	esac
}

check_mergeconflict()
{
	if git ls-files -u | grep ' 1	'; then
		echo
		echo "MERGE CONFLICT."
		echo "change into the \"$1\" project directory, and then:"
		echo "- edit the files mentioned above with your favorite editor,"
		echo "  and fix the conflicts (marked with <<<<<<< blocks)"
		echo "- for binary files, you can select the files using"
		echo "  git checkout --ours or git checkout --theirs"
		echo "- when done with a file, 'git add' the file"
		echo "- when done, 'git commit'"
		echo
		exit 1
	fi
}

yesno()
{
	yesno=
	while [ x"$yesno" != x"y" -a x"$yesno" != x"n" ]; do
		eval "$2"
		echo "$1"
		IFS= read -r yesno
	done
	[ x"$yesno" = x"y" ]
}

enter()
{
	$2 cd "$1"
	check_mergeconflict "$1"
}

repos_urls="
.                             |                                                   | master      |
data/xonotic-data.pk3dir      |                                                   | master      |
data/xonotic-maps.pk3dir      |                                                   | master      |
data/xonotic-music.pk3dir     |                                                   | master      |
data/xonotic-nexcompat.pk3dir |                                                   | master      |
mediasource                   |                                                   | master      |
darkplaces                    |                                                   | div0-stable | svn
fteqcc                        | git://github.com/Blub/qclib.git                   | master      |
div0-gittools                 | git://git.icculus.org/divverent/div0-gittools.git | master      |
netradiant                    |                                                   | master      |
"
# todo: in darkplaces, change repobranch to div0-stable

repos=`echo "$repos_urls" | grep . | cut -d '|' -f 1 | tr -d ' '`

base=`git config remote.origin.url`
case "$base" in
	*/xonotic.git)
		base=${base%xonotic.git}
		;;
	*)
		echo "The main repo is not xonotic.git, what have you done?"
		exit 1
		;;
esac

repourl()
{
	t=`echo "$repos_urls" | grep "^$1 " | cut -d '|' -f 2 | tr -d ' '`
	if [ -n "$t" ]; then
		case "$t" in
			*://*)
				echo "$t"
				;;
			*)
				echo "$base$t"
				;;
		esac
	else
		if [ x"$1" = x"." ]; then
			echo "$base""xonotic.git"
		else
			echo "$base${1##*/}.git"
		fi
	fi
}

repobranch()
{
	t=`echo "$repos_urls" | grep "^$1 " | cut -d '|' -f 3 | tr -d ' '`
	if [ -n "$t" ]; then
		echo "$t"
	else
		echo "master"
	fi
}

repoflags()
{
	echo "$repos_urls" | grep "^$1 " | cut -d '|' -f 4 | tr -d ' '
	echo "$t"
}

repos=`for d in $repos; do
	p="${d%dir}"
	if [ x"$p" = x"$d" ] || [ -d "$d" ] || ! [ -f "$p" ]; then
		echo "$d"
	fi
done`

if [ "$#" = 0 ]; then
	set -- help
fi
cmd=$1
shift

case "$cmd" in
	update|pull)
		allow_pull=true
		if [ x"$1" = x"-N" ]; then
			allow_pull=false
		fi
		for d in $repos; do
			url=`repourl "$d"`
			branch=`repobranch "$d"`
			if [ -d "$d0/$d" ]; then
				if $allow_pull; then
					enter "$d0/$d" verbose
					verbose git config remote.origin.url "$url"
					verbose git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

					r=`git symbolic-ref HEAD`
					r=${r#refs/heads/}
					if git config branch.$r.remote >/dev/null 2>&1; then
						if ! verbose git pull; then
							check_mergeconflict "$d"
							echo "Pulling failed. Press ENTER to continue, or Ctrl-C to abort."
							read -r DUMMY
						fi
					fi

					cd "$d00"
					checkself "$cmd" "$@"
					cd "$d0/$d"
					verbose git remote prune origin
					cd "$d0"
				fi
			else
				verbose git clone "$url" "$d0/$d"
				enter "$d0/$d" verbose
				if [ "$branch" != "master" ]; then
					verbose git checkout --track -b "$branch" origin/"$branch"
				fi
				cd "$d0"
			fi
		done
		;;
	update-maps)
		misc/tools/xonotic-map-compiler-autobuild download
		;;
	checkout|switch)
		remote=$1
		branch=$2
		if [ -z "$branch" ]; then
			case "$remote" in
				origin/*)
					branch=${remote#origin/}
					remote=origin
					;;
				*)
					branch=$remote
					remote=origin
					;;
			esac
		fi
		exists=false
		for d in $repos; do
			enter "$d0/$d" verbose
			b=$branch
			if [ -n "$b" ] && git rev-parse "refs/heads/$b" >/dev/null 2>&1; then
				exists=true
				verbose git checkout "$b"
			elif [ -n "$b" ] && git rev-parse "refs/remotes/$remote/$b" >/dev/null 2>&1; then
				exists=true
				verbose git checkout --track -b "$b" "$remote/$b"
			else
				b=`repobranch "$d"`
				if git rev-parse "refs/heads/$b" >/dev/null 2>&1; then
					exists=true
					verbose git checkout "$b"
				elif git rev-parse "refs/remotes/$remote/$b" >/dev/null 2>&1; then
					exists=true
					verbose git checkout --track -b "$b" "$remote/$b"
				else
					echo "WTF? Not even branch $b doesn't exist in $d"
					exit 1
				fi
			fi
			cd "$d00"
			checkself "$cmd" "$@"
			cd "$d0"
		done
		if ! $exists; then
			echo "The requested branch was not found in any repository."
		fi
		exec "$SELF" branch
		;;
	branch)
		remote=$1
		branch=$2
		srcbranch=$3
		if [ -z "$branch" ]; then
			branch=$remote
			remote=origin
		fi
		if [ -z "$branch" ]; then
			for d in $repos; do
				enter "$d0/$d"
				r=`git symbolic-ref HEAD`
				r=${r#refs/heads/}
				echo "$d is at $r"
				cd "$d0"
			done
		else
			for d in $repos; do
				dv=`visible_repo_name "$d"`
				enter "$d0/$d" verbose
				if git rev-parse "refs/heads/$branch" >/dev/null 2>&1; then
					echo "Already having this branch in $dv."
				else
					if yesno "Branch in $dv?"; then
						if [ -n "$srcbranch" ]; then
							b=$srcbranch
						else
							b=origin/"`repobranch "$d"`"
							verbose git fetch origin || true
						fi
						# TODO do this without pushing
						verbose git checkout -b "$branch" "$b"
						verbose git config "branch.$branch.remote" "$remote"
						verbose git config "branch.$branch.merge" "refs/heads/$branch"
					fi
				fi
				cd "$d0"
			done
			"$SELF" branch
		fi
		;;
	branches)
		for d in $repos; do
			cd "$d0/$d" # am in a pipe, shouldn't use enter
			git branch -a -v -v | cut -c 3- | sed "s,^,$d ,"
			cd "$d0"
		done | {
			branches_list=
			# branches_repos_*=
			while read -r d BRANCH REV UPSTREAM TEXT; do
				if [ x"$BRANCH" = x"`repobranch "$d"`" ]; then
					continue
				fi
				case "$UPSTREAM" in
					\[*)
						UPSTREAM=${UPSTREAM#\[}
						UPSTREAM=${UPSTREAM%\]}
						UPSTREAM=${UPSTREAM%:*}
						;;
					*)
						TEXT="$UPSTREAM $TEXT"
						UPSTREAM=
						;;
				esac
				if [ x"$REV" = x"->" ]; then
					continue
				fi
				BRANCH=${BRANCH#remotes/}
				ID=`echo "$BRANCH" | tr -c "A-Za-z0-9." "_"`
				branches_list="$branches_list $BRANCH" # TEH SORT MAKEZ IT UNIEQ
				eval "r=\$branches_repos_$ID"
				case "$UPSTREAM" in
					'')
						r="$r $d"
						;;
					*)
						r="$r $d:$UPSTREAM"
						;;
				esac
				eval "branches_repos_$ID=\$r"
			done
			echo -n "$branches_list" | xargs -n 1 echo | sort -u | while IFS= read -r BRANCH; do
				ID=`echo "$BRANCH" | tr -c "A-Za-z0-9." "_"`
				eval "r=\$branches_repos_$ID"
				printf "%-60s %s\n" "$BRANCH" "$r"
				#echo "$BRANCH: $r"
			done
		}
		;;
	merge)
		for d in $repos; do
			dv=`visible_repo_name "$d"`
			enter "$d0/$d" verbose
			r=`git symbolic-ref HEAD`
			r=${r#refs/heads/}
			if git log HEAD..origin/"`repobranch "$d"`" | grep .; then
				# we have uncommitted changes
				if yesno "Could merge from \"`repobranch "$d"`\" into \"$r\" in $dv. Do it?"; then
					if ! verbose git merge origin/"`repobranch "$d"`"; then
						check_mergeconflict "$d"
						exit 1 # this should ALWAYS be fatal
					fi
				fi
			fi
			cd "$d0"
		done
		;;
	push|commit)
		submit=$1
		for d in $repos; do
			dv=`visible_repo_name "$d"`
			enter "$d0/$d" verbose
			r=`git symbolic-ref HEAD`
			r=${r#refs/heads/}
			if git diff HEAD | grep .; then
				# we have uncommitted changes
				if yesno "Uncommitted changes in \"$r\" in $dv. Commit?"; then
					verbose git commit -a
				fi
			fi
			rem=`git config "branch.$r.remote" || echo origin`
			bra=`git config "branch.$r.merge" || echo "$r"`
			upstream="$rem/$bra"
			if ! [ git rev-parse "$upstream" ]; then
				upstream="`repobranch "$d"`"
			fi
			if git log "$upstream".."$r" | grep .; then
				if yesno "Push \"$r\" in $dv?"; then
					verbose git push "$rem" HEAD
				fi
			fi
			if [ x"$submit" = x"-s" ]; then
				case "$r" in
					*/*)
						verbose git push "$rem" HEAD:"${bra%%/*}/finished/${bra#*/}"
						;;
				esac
			fi
			cd "$d0"
		done
		;;
	compile)
		if [ -n "$WE_HATE_OUR_USERS" ]; then
			TARGETS="sv-debug cl-debug"
			if [ -z "$CC" ]; then
				export CC=gcc
			fi
		elif [ x"`uname`" = x"Darwin" ] && ( [ -d /Library/Frameworks/SDL.framework ] || [ -d $(HOME)/Library/Frameworks/SDL.framework ] ); then
			# AGL is broken in Snow Leopard, so let's default to SDL if it is available.
			TARGETS="sv-debug sdl-debug"
		else
			TARGETS="sv-debug cl-debug sdl-debug"
		fi
		case "$1" in
			-c)
				clean=true
				shift
				;;
			*)
				clean=false
				;;
		esac
		case "$1" in
			sdl)
				TARGETS="sdl-debug"
				shift
				;;
			glx|agl|wgl)
				TARGETS="cl-debug"
				shift
				;;
			dedicated)
				TARGETS="sv-debug"
				shift
				;;
		esac
		if [ -z "$MAKEFLAGS" ]; then
			if [ -f /proc/cpuinfo ]; then
				ncpus=$((`grep -c '^processor	:' /proc/cpuinfo`+0))
				if [ $ncpus -gt 1 ]; then
					MAKEFLAGS=-j$ncpus
				fi
			fi
			case "`uname`" in
				Linux|*BSD)
					MAKEFLAGS="$MAKEFLAGS DP_LINK_TO_LIBJPEG=1"
					;;
			esac
			if [ -n "$WE_HATE_OUR_USERS" ]; then
				MAKEFLAGS="$MAKEFLAGS DP_MAKE_TARGET=mingw"
			fi
		fi
		enter "$d0/fteqcc" verbose
		if $clean; then
			verbose make $MAKEFLAGS clean
		fi
		verbose make $MAKEFLAGS
		enter "$d0/data/xonotic-data.pk3dir" verbose
		if $clean; then
			verbose make $MAKEFLAGS clean
		fi
		verbose make FTEQCC="$d0/fteqcc/fteqcc.bin" "$@" $MAKEFLAGS clean
		verbose make FTEQCC="$d0/fteqcc/fteqcc.bin" "$@" $MAKEFLAGS
		enter "$d0/darkplaces" verbose
		if $clean; then
			verbose make $MAKEFLAGS clean
		fi
		for T in $TARGETS; do
			verbose make $MAKEFLAGS "$@" "$T"
		done
		verbose "$SELF" update-maps
		;;
	makebuild)
		
		;;
	run)
		if [ -n "$WE_HATE_OUR_USERS" ]; then
			client=
			export PATH="$d0/misc/buildfiles/w32:$PATH"
		elif [ x"`uname`" = x"Darwin" ]; then
			export DYLD_LIBRARY_PATH="$d0/misc/buildfiles/osx/Xonotic-SDL.app/Contents/MacOS"
			client=-sdl
		else
			client=-sdl
		fi
		case "$1" in
			sdl|glx|agl|dedicated)
				client=-$1
				shift
				;;
			wgl)
				client=
				shift
				;;
		esac
		if ! [ -x "darkplaces/darkplaces$client" ]; then
			if [ -x "darkplaces/darkplaces$client.exe" ]; then
				client=$client.exe
			else
				echo "Client darkplaces/darkplaces$client not found, aborting"
				exit 1
			fi
		fi
		set -- "darkplaces/darkplaces$client" -nexuiz -customgamename Xonotic -customgamedirname1 data -customgamedirname2 "" -customgamescreenshotname xonotic -customgameuserdirname xonotic "$@"

		# if pulseaudio is running: USE IT
		if [ -z "$SDL_AUDIODRIVER" ] && ! [ -n "$WE_HATE_OUR_USERS" ] && ! [ x"`uname`" = x"Darwin" ]; then
			if ps -C pulseaudio >/dev/null; then
				if ldd /usr/lib/libSDL.so 2>/dev/null | grep pulse >/dev/null; then
					export SDL_AUDIODRIVER=pulse
				fi
			fi
		fi

		if [ -n "$USE_GDB" ]; then
			set -- gdb --args "$@"
		fi
		"$@"
		;;
	each|foreach)
		keep_going=false
		if [ x"$1" = x"-k" ]; then
			keep_going=true
			shift
		fi
		for d in $repos; do
			if verbose cd "$d0/$d"; then
				if $keep_going; then
					verbose "$@" || true
				else
					verbose "$@"
				fi
				cd "$d0"
			fi
		done
		;;
	save-patches)
		outfile=$1
		patchdir=`mktemp -d -t save-patches.XXXXXX`
		for d in $repos; do
			enter "$d0/$d" verbose
			git branch -v -v | cut -c 3- | {
				i=0
				while read -r BRANCH REV UPSTREAM TEXT; do
					case "$UPSTREAM" in
						\[*)
							UPSTREAM=${UPSTREAM#\[}
							UPSTREAM=${UPSTREAM%\]}
							UPSTREAM=${UPSTREAM%:*}
							TRACK=true
							;;
						*)
							UPSTREAM=origin/"`repobranch "$d"`"
							TRACK=false
							;;
					esac
					if [ x"$REV" = x"->" ]; then
						continue
					fi
					if git format-patch -o "$patchdir/$i" "$UPSTREAM".."$BRANCH"; then
						echo "$d" > "$patchdir/$i/info.txt"
						echo "$BRANCH" >> "$patchdir/$i/info.txt"
						echo "$UPSTREAM" >> "$patchdir/$i/info.txt"
						echo "$TRACK" >> "$patchdir/$i/info.txt"
						i=$(($i+1))
					else
						rm -rf "$patchdir/$i"
					fi
				done
			}
		done
		( cd "$patchdir" && tar cvzf - . ) > "$outfile"
		rm -rf "$patchdir"
		;;
	restore-patches)
		infile=$1
		patchdir=`mktemp -d -t restore-patches.XXXXXX`
		( cd "$patchdir" && tar xvzf - ) < "$infile"
		# detach the head
		for P in "$patchdir"/*/info.txt; do
			D=${P%/info.txt}
			exec 3<"$P"
			read -r d <&3
			read -r BRANCH <&3
			read -r UPSTREAM <&3
			read -r TRACK <&3
			verbose git checkout HEAD^0
			verbose git branch -D "$BRANCH"
			if [ x"$TRACK" = x"true" ]; then
				verbose git checkout --track -b "$BRANCH" "$UPSTREAM"
			else
				verbose git branch -b "$BRANCH" "$UPSTREAM"
			fi
			verbose git am "$D"
		done
		rm -rf "$patchdir"
		;;
	admin-merge)
		if [ "$#" = 1 ]; then
			set -- "${1%%/*}" "${1#*/}"
		fi
		for d in $repos; do
			enter "$d0/$d" verbose
			git rev-parse "$1/$2" || continue
			# 1. review
			{
				git log HEAD.."$1/$2"
				git diff HEAD..."$1/$2"
			} | less
			if yesno "Merge \"$1/$2\" into `git symbolic-ref HEAD` of $d?"; then
				git merge "$1/$2"
				if "$SELF" compile && yesno "Still merge \"$1/$2\" into `git symbolic-ref HEAD` of $d? Maybe you want to test first."; then
					git push origin HEAD
					git push "$1" :"$2"
				else
					git reset --hard HEAD@{1}
				fi
			fi
		done
		;;
	admin-merge-2)
		t=`mktemp`
		report=""
		reportecho()
		{
			report=$report"$*$LF"
			echo "$*"
		}
		reportecho4()
		{
			report=$report"    $*$LF"
			echo "    $*"
		}
		reportdo4()
		{
			o=`"$@" | sed 's/^/    /' || true`
			reportecho "$o"
		}
		for d in $repos; do
			enter "$d0/$d" verbose
			base="`repobranch "$d"`"
			reportecho "In $d:"
			for ref in `git for-each-ref --format='%(refname)' refs/remotes/origin/`; do
				case "${ref#refs/remotes/origin/}" in
					"$base")
						continue
						;;
					HEAD|master)
						continue
						;;
				esac
				reportecho "  Branch $ref:"
				note=`GIT_NOTES_REF=refs/notes/admin-merge git notes show "$ref" 2>/dev/null || true`
				logdata=`git log --color "$base".."$ref"`
				diffdata=`git diff --color --find-copies-harder --ignore-space-change "$base"..."$ref"`
				if [ -z "$logdata" ]; then
					reportecho4 "--> not merging, no changes vs master"
				elif [ -z "$diffdata" ]; then
					reportecho4 "--> not merging, no changes vs master, branch contains redundant history"
					if yesno "Branch \"$ref\" probably should get deleted. Do it?" '{ echo "$logdata"; } | less -r'; then
						git push origin :"${ref#refs/remotes/origin/}"
						reportecho4 "--> branch deleted"
					fi
				elif [ -n "$note" ]; then
					reportdo4 echo "$note"
					reportecho4 "--> not merging, already had this one rejected before"
				elif yesno "Branch \"$ref\" may want to get merged. Do it?" '{ echo "$logdata"; echo "$diffdata"; } | less -r'; then
					git checkout "$base"
					org=`git rev-parse HEAD`
					if ! git merge "$ref" 2>&1 | tee "$t"; then
						git reset --hard "$org"
						GIT_NOTES_REF=refs/notes/admin-merge git notes edit -m "Merge failed:$LF`cat "$t"`" "$ref"
						reportdo4 cat "$t"
						reportecho4 "--> merge failed"
					elif ! "$SELF" compile 2>&1 | tee "$t"; then
						git reset --hard "$org"
						GIT_NOTES_REF=refs/notes/admin-merge git notes edit -m "Compile failed:$LF`cat "$t"`" "$ref"
						reportdo4 cat "$t"
						reportecho4 "--> compile failed"
					elif ! yesno "Still merge \"$ref\" into `git symbolic-ref HEAD` of $d? Maybe you want to test first."; then
						git reset --hard "$org"
						git notes edit "$ref"
						note=`GIT_NOTES_REF=refs/notes/admin-merge git notes show "$ref" 2>/dev/null || true`
						reportdo4 echo "$note"
						reportecho4 "--> test failed"
					else
						case ",`repoflags "$d"`," in
							*,svn,*)
								# we do quite a mess here... luckily we know $org
								git pull # svn needs to be current
								git rebase -i --onto master "$org"
								git svn dcommit --add-author-from
								git reset --hard "$org"
								;;
							*)
								git push origin HEAD
								;;
						esac
						reportecho4 "--> MERGED"
						if yesno "Delete original branch \"$ref\"?"; then
							git push origin :"${ref#refs/remotes/origin/}"
							reportecho4 "--> branch deleted"
						fi
					fi
				else
					GIT_NOTES_REF=refs/notes/admin-merge git notes edit "$ref"
					note=`GIT_NOTES_REF=refs/notes/admin-merge git notes show "$ref" 2>/dev/null || true`
					if [ -n "$note" ]; then
						reportdo4 echo "$note"
						reportecho4 "--> rejected"
					else
						reportecho4 "--> postponed"
					fi
				fi
				reportecho ""
			done
			reportecho ""
		done
		rm -f "$t"
		echo "$report" | ssh nexuiz@rm.endoftheinternet.org cat '>>' public_html/xonotic-merge-notes.txt
		;;

	# release building goes here
	release-mkdir)
		mkdir -p Xonotic/"$1"
		;;
	release-prepare)
#"$SELF" each git clean -fxd
		mkdir -p Xonotic
		"$SELF" release-copy Docs/
		"$SELF" release-copy misc/
		"$SELF" release-copy server/
		"$SELF" release-copy xonotic-linux-glx.sh
		"$SELF" release-copy xonotic-linux-sdl.sh
		"$SELF" release-mkdir data
		;;
	release-copy)
		rsync --exclude=.git -vaSHPAX "$1" Xonotic/"$1"
		;;
	release-engine-win32)
		rsync --exclude=.git -vaSHPAX Xonotic/misc/buildfiles/w32/* Xonotic/
		;;
	release-engine-osx)
		rsync --exclude=.git -vaSHPAX Xonotic/misc/buildfiles/osx/* Xonotic/
		;;
	release-engine-linux32)
		;;
	release-engine-linux64)
		;;
	release-engine)
		"$SELF" release-engine-win32
		"$SELF" release-engine-osx
		"$SELF" release-engine-linux32
		"$SELF" release-engine-linux64
		;;
	release-maps)
		"$SELF" update-maps
		for X in data/*-????????????????????????????????????????-????????????????????????????????????????.pk3; do
			if [ -f "$X" ]; then
				cd Xonotic/data/xonotic-maps.pk3dir
				unzip ../../../"$X"
				cd ../../..
			fi
		done
		;;
	release-finish)
		# version numnber and stuff like that
		;;
	release-buildpk3-transform-raw)
		;;
	release-buildpk3-transform-normal)
		# texture: convert to jpeg
		;;
	release-buildpk3-transform-low)
		# texture: convert to jpeg and downscale
		# music: reduce bitrate
		;;
	release-buildpk3)
		src=$1
		dst=$2
		transform=$3
		case "$dst" in
			/*)
				;;
			*/
				dst="$PWD/$dst"
				;;
		esac
		rm -rf Xonotic/temp
		rsync --exclude=.git -vaSHPAX "$src"/ "Xonotic/temp"
		"$SELF" release-buildpk3-transform-$transform "Xonotic/temp"
		7za a -tzip -mx=9 "$dst" .
		rm -rf Xonotic/temp
		;;
	release-buildpk3s)
		src=$1
		shift
		while [ "$#" -gt 1 ]; do
			"$SELF" release-buildpk3 "$src" "Xonotic/${src%.pk3dir}$2.pk3" "$1"
		done
		rm -rf "$src"
		;;
	release-pack)
		"$SELF" release-buildpk3s  data/font-dejavu.pk3dir                  raw ''
		"$SELF" release-buildpk3s  data/xonotic-data.pk3dir       normal '' raw '-raw' low '-low'
		"$SELF" release-buildpk3s  data/xonotic-maps.pk3dir       normal '' raw '-raw' low '-low'
		"$SELF" release-buildpk3s  data/xonotic-music.pk3dir      normal '' raw '-raw' low '-low'
		"$SELF" release-buildpk3s data/xonotic-nexcompat.pk3dir                        low ''
		;;
	release)
		"$SELF" release-prepare
		"$SELF" release-engine
		"$SELF" release-gamedata
		"$SELF" release-maps
		"$SELF" release-finish
		"$SELF" release-pack
		;;

	*)
		echo "Usage:"
		echo "  $SELF pull"
		echo "  $SELF merge"
		echo "  $SELF push [-s]"
		echo "  $SELF branches"
		echo "  $SELF branch [<remote>] <branchname>"
		echo "  $SELF branch <remote> <branchname> <srcbranchname>"
		echo "  $SELF checkout [<remote>] <branchname>"
		echo "  $SELF compile [-c] [<client>] <options>"
		echo "  $SELF run [<client>] <options>"
		echo "  $SELF each <command>"
		;;
esac