#!/bin/sh

# Script to pull patches or tarballs from remote git repositories

usage() {
    cat <<EOF
Usage: $0 [-b <BRANCH>] [-c <CLONES_DIR>] [-d <DEST_DIR>]
          [-e <PATCH_EXT>] [-p <PATCH_PREFIX>] [-r <REPO>]
          [-?] [-h] [-f] [-F] [-T]

Creates a patch (or tarball if -T is specified) from BRANCH of REPO in
the directory DEST_DIR, named "PATCH_PREFIX-<branch_id>.PATCH_EXT".
Will not overwrite an existing file by this name, unless the -f option
is specified.  A clone of the branch will be created and cached in
"CLONES_DIR/BRANCH".  The cached tree will be reused, if it exists,
unless the -F option is specified.  <branch_id> is determined from the
git clone and will be a string beginning with 'g' of the form
"g1234abc".

If not specified, the CLONES_DIR and DEST_DIR will be the current
working directory, PATCH_EXT will be "diff", REPO will be 
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git,
and PATCH_PREFIX will be "linux".  BRANCH defaults to "origin".

Each of these parameters may also be provided as environment variables,
prefixed by PKGFIND_.  E.g., PKGFIND_BRANCH.

Example:
  $0 -p linux \\
     -r git://linux-nfs.org/~bfields/exports/linux.git \\
     -b nfs-server-stable \\
     -d /testing/packages/nfsv4/ \\
     -c /var/cache/git
EOF
    exit $1
}

CLONES_DIR=${PKGFIND_CLONES_DIR:-"."}
PATCH_PREFIX=${PKGFIND_PATCH_PREFIX:-"linux"}
REPO=${PKGFIND_REPO:-"git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git"}
BRANCH=${PKGFIND_BRANCH:-"origin"}
PATCH_EXT=${PKGFIND_PATCH_EXT:-"diff"}
DEST_DIR=${PKGFIND_DEST_DIR:-"$PWD"}
FORCE_PATCH_GENERATION=0
FORCE_RECLONE=0
TARBALL=0

while getopts "b:c:d:e:p:r:FT\?" opt; do
    case $opt in
    b) BRANCH=$OPTARG ;;
    c) CLONES_DIR=$OPTARG ;;
    d) DEST_DIR=$OPTARG ;;
    e) PATCH_EXT=$OPTARG ;;
    f) FORCE_PATCH_GENERATION=1 ;;
    p) PATCH_PREFIX=$OPTARG ;;
    r) REPO=$OPTARG ;;
    F) FORCE_RECLONE=1 ;;
    T) TARBALL=1 ;;
    \?) usage 1 ;;
    esac
done
shift `expr $OPTIND - 1`

if [ ! -w $CLONES_DIR ]; then
    echo "ERROR:  '$CLONES_DIR' is not writable"
    exit 1
fi

# We will cache the cloned tree under $BRANCH
if [ $FORCE_RECLONE -eq 1 ]; then
   if [ -e "$CLONES_DIR/$BRANCH" ]; then
       echo "Removing existing '$CLONES_DIR/$BRANCH'"
       rm -rf "$CLONES_DIR/$BRANCH"
       if [ $? -ne 0 ]; then
           echo "ERROR:  Could not rm '$CLONES_DIR/$BRANCH'"
           exit 1
       fi
   fi
fi

cd $CLONES_DIR
if [ $? -ne 0 ]; then
    echo "ERROR:  Could not cd to '$CLONES_DIR'"
    exit 1
fi

if [ ! -d "$CLONES_DIR/$BRANCH" ]; then
   echo "Cloning $REPO"
   git clone $REPO $BRANCH
   if [ $? -ne 0 ]; then
       echo "ERROR:  Could not clone $REPO" 
       exit 1
   fi
fi

cd "$CLONES_DIR/$BRANCH"
if [ $? -ne 0 ]; then
    echo "ERROR:  Could not cd to '$CLONES_DIR/$BRANCH'"
    exit 1
fi

if [ $TARBALL -eq 1 ]; then
    # Create a tarball of the tip of the branch
    git tar-tree $BRANCH
    if [ $? -ne 0 ]; then
        echo "ERROR:  Could not create tarball in '$DEST_DIR'"
        exit 1
    fi
fi

if [ "$BRANCH" != "origin" ]; then
    echo "git fetch --force origin $BRANCH:$BRANCH"
    fetch_output=`git fetch --force origin $BRANCH:$BRANCH 2>&1`
    if [ $? -ne 0 ]; then
        echo "ERROR:  Could not switch to origin for $BRANCH"
        exit 1
    fi
    echo "Fetch returned:  $fetch_output"
else
    echo "TODO:  Should call git-fetch here..."
fi

echo "git describe $BRANCH"
BRANCH_ID=`git describe $BRANCH`
if [ "$BRANCH" == "origin" ]; then
    BRANCH_ID=$BRANCH
elif [ -z "$BRANCH_ID" ]; then
    echo "ERROR:  Could not determine branch id"
    exit 1
fi

# Strip off the -extraversion portion
BASE=`echo $BRANCH_ID | sed "s/-g[a-z0-9]*$//"`

# Strip off leading 'v' if necessary
BRANCH_ID=`echo $BRANCH_ID | sed "s/^v//"`

PATCH="$PATCH_PREFIX-$BRANCH_ID.$PATCH_EXT"

if [ -e $DEST_DIR/$PATCH ]; then
    if [ $FORCE_PATCH_GENERATION -eq 0 ]; then
        echo "Not overwriting existing '$DEST_DIR/$PATCH'.  Use -f to force."
        exit 10
    else
        echo "WARNING:  Overwriting existing '$DEST_DIR/$PATCH'"
    fi
fi

# Get the diff between base and the tip of the branch
echo "git diff $BASE $BRANCH > $DEST_DIR/$PATCH"
git diff $BASE $BRANCH > $DEST_DIR/$PATCH
if [ $? -ne 0 ]; then
    echo "ERROR:  Could not create patch '$DEST_DIR/$PATCH'"
    exit 1
fi

if [ -s "$DEST_DIR/$PATCH" ]; then
    echo "$PATCH"
elif [ -f "$DEST_DIR/$PATCH" ]; then
    echo "no diff available"
    rm "$DEST_DIR/$PATCH"
fi

exit 0

