#!/bin/sh
#
# Copyright (c) 2010 Pierre Habouzit <madcoder@debian.org>

NONGIT_OK=Yes
OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git workdir create <name> <repository> [-b] <branch> [<start-point>]
git workdir rename <name>
--
"

. git-sh-setup

get_master_dir() {
	d="$(readlink "$1"/logs/HEAD)"
	echo ${d%/logs/workdir/*/HEAD}
}

get_wd_name() {
	d="$(readlink "$1"/logs/HEAD)"
	d="${d%/HEAD}"
	echo "${d#*/logs/workdir/}"
}

workdir_create() {
	test $# -ge 3 || usage

	name="$1"; shift
	orig_git="$1"; shift
	new_workdir="$(pwd)"

	# want to make sure that what is pointed to has a .git directory ...
	git_dir=$(cd "$orig_git" 2>/dev/null &&
	  git rev-parse --git-dir 2>/dev/null) ||
	  die "Not a git repository: \"$orig_git\""

	if test -e "$git_dir/logs/workdir/$name/"; then
		die "workdir \"$name\" already exists"
	fi

	# be sure '.' is empty
	if test "$(ls -1a | wc -l)" != 2; then
		die "\"$new_workdir\" isn't empty"
	fi

	case "$git_dir" in
		.git) git_dir="$orig_git/.git";;
		.)    git_dir="$orig_git";;
	esac

	# don't link to a configured bare repository
	if test "$(git --git-dir="$git_dir" config --bool --get core.bare)" = "true"
	then
		die "\"$git_dir\" has core.bare set to true," \
			" remove from \"$git_dir/config\" to use $0"
	fi

	# don't link to a workdir
	if test -L "$git_dir/config"; then
		die "\"$orig_git\" is a working directory only, please specify" \
			"a complete repository."
	fi

	# make sure the the links use full paths
	git_dir=$(cd "$git_dir"; pwd)
	cd "$new_workdir"

	trap 'rm -rf *; rm -rf .* 2>/dev/null' 0 1 2 3 15

	# create the workdir
	mkdir -p "$git_dir/logs/workdir/$name/"
	touch "$git_dir/logs/workdir/$name/HEAD"
	mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"

	# create the links to the original repo.  explictly exclude index, HEAD and
	# logs/HEAD from the list since they are purely related to the current working
	# directory, and should not be shared.
	for x in config refs logs/refs objects info hooks packed-refs rr-cache svn
	do
		case $x in
		*/*)
			mkdir -p "$(dirname "$new_workdir/.git/$x")"
			;;
		esac
		ln -s "$git_dir/$x" "$new_workdir/.git/$x"
	done
	ln -s "$git_dir/logs/workdir/$name/HEAD" "$new_workdir/.git/logs/HEAD"

	# now checkout what the user asked for
	cp "$git_dir/HEAD" .git/HEAD
	git checkout -f "$@"
	git --git-dir="$git_dir" config "workdir.$name.path" "$new_workdir"
	trap - 0
}

workdir_rename() {
	test $# = 1 || usage

	git_dir="$(git rev-parse --git-dir)" || exit
	test -L "$git_dir/config" || die "the repository isn't a working directory"
	cd "$git_dir"

	master_dir="$(get_master_dir .)"
	oldname="$(get_wd_name .)"
	name="$1"

	if test -e "$master_dir/logs/workdir/$name/HEAD"; then
		die "\"$name\" workdir already exists"
	fi
	mv "$master_dir/logs/workdir/$oldname" "$master_dir/logs/workdir/$name" || \
		die "unable to rename workdir from $oldname to $name"
	ln -sf "$master_dir/logs/workdir/$name/HEAD" logs/HEAD
	git --git-dir="$master_dir" config --rename-section "workdir.$oldname" "workdir.$name"
}

workdir_info() {
	git_dir="$(git rev-parse --git-dir)" || exit
	test -L "$git_dir/config" || die "the repository isn't a working directory"

	cd "$git_dir"
	echo "workdir \"$(get_wd_name .)\" -> \"$(get_master_dir .)\""
}

while test $# != 0
do
	case "$1" in
		--) shift; break;;
		*)  usage;;
	esac
done

case "$1" in
	create)
		shift
		workdir_create "$@"
		;;
	rename)
		shift
		workdir_rename "$@"
		;;
	"")
		workdir_info
		;;
	*)
		usage
		;;
esac
