#!/bin/bash
# Simple shell script for importing a collection of Debian source packages
# into a git repository.
#
# Copyright(C) 2007, 2008, Ron <ron@debian.org>
# This script is distributed according to the terms of the GNU GPL.

set -e

UPSTREAM_BRANCH="upstream"
DEBIAN_BRANCH="master"

UPSTREAM_TAG_PREFIX="v"
DEBIAN_TAG_PREFIX="v"

# We default to the linux kernel style tags, but people who prefer the
# git-buildpackage style and like slashes in their tags can do this:
#UPSTREAM_TAG_PREFIX="$UPSTREAM_BRANCH/"
#DEBIAN_TAG_PREFIX="debian/"


usage()
{
    cat 1>&2 <<EOF

git-debimport path-prefix

 This program will take all files that match \${path-prefix}_*.diff.gz, and the
 list of corresponding orig.tar.gz files, and create a git repository from them.

  For example:
  $ mkdir mydestdir && cd mydestdir
  $ git-debimport ../mysrcdir/mypackagename

EOF

    exit $1
}

# This function replaces all consecutive illegal constructs in a git refname
# with a single '_'.  The rules for git refnames are described in the manual
# page for git-check-ref-format(1).
sanitise_git_ref()
{
    (
	shopt -s extglob

	ref="${1//\/.//_}"				# rule 1.
	ref="${ref//../_}"				# rule 2.
	ref="${ref//[[:cntrl:][:space:]:~^?*[]/_}"	# rule 3.
	ref="${ref%%+(/)}"				# rule 4.
	ref="${ref//+(_)_/_}"

	echo "$ref"
    )
}


[ $# -gt 0 ] && [ $# -lt 2 ] || usage 1


PACKAGES_DIR="${1%/*}"
PACKAGE_NAME="${1##*/}"
PACKAGE_DIFFS="$(find $PACKAGES_DIR -type f -name ${PACKAGE_NAME}_*.diff.gz | sort)"
CACHE_DIR="../${PACKAGE_NAME}-import-cache"

if [ -z "$PACKAGE_DIFFS" ]; then
    echo "No ${1}_*.diff.gz files found, aborting."
    exit 1
fi

if [ -e "$PACKAGE_NAME" ]; then
    echo "A $PACKAGE_NAME dir already exists, please (re)move it first"
    exit 1
fi

case $PACKAGES_DIR in /*) ;; *) PKG_ROOT="../" ;; esac


# We really need the packages in the order dpkg thinks they are in here, and
# the only way to reliably know that is to ask dpkg what it thinks.  Since that
# is a rather expensive operation, and the number of operations to be performed
# grows rapidly as the number of packages to import gets longer, we must do the
# only sane thing feasible, and cheat.
#
# By doing a fast lexical pre-sort of the list, we can in almost all but the
# most pathological cases get the order almost, or even exactly, right.  So from
# that probable starting point, Simplicity, in her infinite wisdom, will reward
# all those people who numbered their packages sanely, with O(n) or near to it
# performance in determining the Proper order if we just do a trivial insertion
# sort for this next step.
#
# Pros:
# The Good People will get better results than the most fancy patent pending
# product of a college education algorithm is likely to do, and the Bad People
# will get the time-squared in pergatory that they deserve.
#
# Cons:
# Had you inferred all this from the 4 lines of code below?
#
# Todo:
# Maybe output a warning that this could take a while if $count > N.
# Determine N.

P=( $PACKAGE_DIFFS )
count=${#P[*]}
COMPARE="dpkg --compare-versions"

for(( i=1; i < count; ++i )) do
    j=i
    #echo "was $i: ${P[i]}"
    while (($j)) && $COMPARE "${P[j-1]%.diff.gz}" gt "${P[i]%.diff.gz}"; do ((--j)); done
    ((i==j)) || P=( ${P[@]:0:j} ${P[i]} ${P[j]} ${P[@]:j+1:i-(j+1)} ${P[@]:i+1} )
done
#for(( i=1; i < count; ++i )) do echo "now $i: ${P[i]}"; done

PACKAGE_DIFFS="${P[@]}"


mkdir "$PACKAGE_NAME"
cd "$PACKAGE_NAME"
git init

for f in $PACKAGE_DIFFS; do

    DEBIAN_VERSION="${f%.diff.gz}"
    DEBIAN_VERSION="${DEBIAN_VERSION##*_}"
    UPSTREAM_VERSION="${DEBIAN_VERSION%-*}"

    if [ -z "$LAST_UPSTREAM_VERSION" ]; then
    	echo "Initial import of $PACKAGES_DIR/${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz"

	rm -rf "$CACHE_DIR"
	mkdir -p "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig"
	tar -xf "$PKG_ROOT$PACKAGES_DIR/${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz" \
	     -C "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig" --strip 1
	for i in $(ls -A "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig"); do
	    cp -al "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig/$i" .
	done

	DATE=$(file -L $PKG_ROOT$PACKAGES_DIR/${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz | sed -n "s/.*, last modified: \([^,]*\),*.*/\1/p")

	git add .
	GIT_AUTHOR_DATE="$DATE" GIT_COMMITTER_DATE="$DATE" \
	    git commit -a -m "git-debimport ${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz"
	git checkout -b "$UPSTREAM_BRANCH"
	git tag $(sanitise_git_ref "$UPSTREAM_TAG_PREFIX$UPSTREAM_VERSION")

	LAST_UPSTREAM_VERSION="$UPSTREAM_VERSION"
    fi

    if [ "$LAST_UPSTREAM_VERSION" != "$UPSTREAM_VERSION" ]; then
    	echo "Importing $PACKAGES_DIR/${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz"

	git checkout "$UPSTREAM_BRANCH"
	for i in $(ls -A); do
	    if [ "$i" != ".git" ]; then rm -rf $i; fi
	done

	rm -rf "$CACHE_DIR"
	mkdir -p "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig"
	tar -xf "$PKG_ROOT$PACKAGES_DIR/${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz" \
	     -C "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig" --strip 1
	for i in $(ls -A "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig"); do
	    cp -al "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig/$i" .
	done

	DATE=$(file -L $PKG_ROOT$PACKAGES_DIR/${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz | sed -n "s/.*, last modified: \([^,]*\),*.*/\1/p")

	git add .
	GIT_AUTHOR_DATE="$DATE" GIT_COMMITTER_DATE="$DATE" \
	    git commit -a -m "git-debimport ${PACKAGE_NAME}_${UPSTREAM_VERSION}.orig.tar.gz"
	git tag $(sanitise_git_ref "$UPSTREAM_TAG_PREFIX$UPSTREAM_VERSION")

	LAST_UPSTREAM_VERSION="$UPSTREAM_VERSION"
    fi

    echo "Importing $f"

    git checkout "$DEBIAN_BRANCH"
    for i in $(ls -A); do
	if [ "$i" != ".git" ]; then rm -rf $i; fi
    done

    for i in $(ls -A "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig"); do
	cp -al "$CACHE_DIR/${PACKAGE_NAME}-${UPSTREAM_VERSION}.orig/$i" .
    done
    zcat "$PKG_ROOT$f" | patch -p1
    chmod 755 debian/rules

    DATE=$(dpkg-parsechangelog | sed -n 's/Date: //p')
    AUTHOR=$(dpkg-parsechangelog | sed -n 's/Maintainer: //p' | cut -d\< -f1)
    EMAIL=\<$(dpkg-parsechangelog | sed -n 's/Maintainer: //p' | cut -d\< -f2)

    git add .
    GIT_AUTHOR_NAME="$AUTHOR" GIT_COMMITTER_NAME="$AUTHOR" \
    GIT_AUTHOR_EMAIL="$EMAIL" GIT_COMMITTER_EMAIL="$EMAIL" \
    GIT_AUTHOR_DATE="$DATE" GIT_COMMITTER_DATE="$DATE" \
	git commit -a -m "git-debimport ${PACKAGE_NAME}_${DEBIAN_VERSION}.diff.gz"
    git tag $(sanitise_git_ref "$DEBIAN_TAG_PREFIX$DEBIAN_VERSION")

done

rm -rf "$CACHE_DIR"
git merge -s ours "$UPSTREAM_BRANCH"

echo "All done!"

# vi:sts=4:sw=4:noet:foldmethod=marker
