#!/bin/sh -e
# Separate tarball/patch build system by Adam Heath <doogie@debian.org>
# Modified by Ben Collins <bcollins@debian.org>
# Modified by Brian May <bam@debian.org>

FILE2CAT=/usr/share/dbs/file2cat
VARSBUILD=/usr/share/dbs/vars.build

######################
# PARSE COMMAND LINE #
######################
usage () {
  echo "dbs-edit-patch, edit/create a dbs patch file" >&2
  echo "   usage: dbs-edit-patch [-t|--tmpdir t] [-s|--sourcedir s] [-p 1] patch" >&2
}

# stolen from /usr/bin/fakeroot, Debian potato version.
GETOPTEST=`getopt --version`
case $GETOPTEST in
getopt*) # GNU getopt
    TEMP=`getopt -n dbs-edit-patch -l help,tmpdir:,sourcedir:,strip: -- +ht:s:p: "$@"`
    ;;
*) # POSIX getopt ?
    TEMP=`getopt ht:s:p: "$@"`
    ;;
esac

if test "$?" != "0"
then
  echo "Terminating..." >&2
  exit 1
fi

# Initialize value of temporary directory to $TMP || /tmp
TMP_DIR="${TMP:-/tmp}"

STRIP=0
SOURCE_DIR=`pwd`

eval set -- "$TEMP"
while test "$1" != "--"; do
  case "$1" in
    -p|--strip)
      shift
      STRIP="$1"
      ;;
    -t|--tmpdir)
      shift
      TMP_DIR="$1"
      ;;
    -s|--sourcedir)
      shift
      SOURCE_DIR="$1"
      ;;
    -P|--sourcepatchdir)
      shift
      SRC_PATCH_DIR="$1"
      ;;
    -T|--sourcetardir)
      shift
      SRC_TAR_DIR="$1"
      ;;
    -h|--help)
      usage
      exit 0
      ;;
  esac
  shift
done

# Defaults that depend on other variables
PATCH_DIR="$SOURCE_DIR/debian/patches"
HOOK_DIR="${HOOK_DIR:-$SOURCE_DIR/debian/dbs-hooks}"
SRC_TAR_DIR="${SRC_TAR_DIR:-$SOURCE_DIR}"

shift

if [ $# -lt 1 ]
then
  usage
  exit 
fi

PATCH="$1"; shift

# Initialize values using the debian/vars file, if exists
if [ -e "$SOURCE_DIR/debian/vars" ] ; then
   echo "Parse $SOURCE_DIR/debian/vars" 
   sh "$VARSBUILD" debian/vars shell > $TMP_DIR/vars
   # SOURCE_DIR is the package root for packaged DBS, and where unpacked (=build-tree) for glib DBS
   OLD_SOURCE_DIR="$SOURCE_DIR"
   . "$TMP_DIR/vars"
   if echo "$PATCH_DIR" | egrep -q -v '^/' ; then PATCH_DIR="$OLD_SOURCE_DIR/$PATCH_DIR"; fi
   if echo "$SRC_PATCH_DIR" | egrep -q -v '^/' ; then SRC_PATCH_DIR="$OLD_SOURCE_DIR/$SRC_PATCH_DIR"; fi
   if echo "$SRC_TAR_DIR" | egrep -q -v '^/' ; then SRC_TAR_DIR="$OLD_SOURCE_DIR/$SRC_TAR_DIR"; fi
fi

DIFF_EXCLUDE=`for i in $DIFF_EXCLUDE ; do echo -n "-x $i "; done`

# ENSURE PATCH DIRECTORY EXISTS (directory with patches)
if [ ! -d "$PATCH_DIR" ]
then 
  echo "Cannot find patch dir $PATCH_DIR" >&2
  exit 1
fi

# ENSURE TMP DIRECTORY EXISTS (where files to be edited will go)
if [ ! -d "$TMP_DIR" ]
then 
  echo "Cannot find directory $TMP_DIR" >&2
  exit 1
fi

if [ "$STRIP" != 1 -a "$STRIP" != 0 ]
then 
  echo "Invalid value for -p or --strip" >&2
  exit 1
fi

# CREATE DIRECTORY WITH SAME NAME AS PATCH FILE
OUT_DIR="$TMP_DIR/$PATCH"
rm -rf "$OUT_DIR"
mkdir "$OUT_DIR"

if [ ! -d "$OUT_DIR" ]
then 
  echo "Cannot create directory $OUT_DIR" >&2
  exit 1
fi
  
# EXTRACT SOURCE FILES
for f in `find $SRC_TAR_DIR -type f -maxdepth 1 -name \*.tgz -o -name \*.tar.gz -o -name \*.tar.bz -o -name \*.tar.bz2 | LC_COLLATE=C sort`; do 
    file=`basename $f`
    echo -n "Extracting source $file ... "; 
    if "$FILE2CAT" "$f" | tar -C $OUT_DIR -xvf - > /dev/null; then 
      echo "successful." 
    else 
      echo "failed!"
      exit 1
    fi
done

case "$STRIP" in
  1)
    # DETERMINE DIRECTORY NAME (assume only one exists)
    for f in `find $OUT_DIR -type d -maxdepth 1`; do 
      DEST_DIR="$f"
    done
    ;;

  0)
    DEST_DIR="$OUT_DIR"
    ;;
esac

apply_patch () {
    THIS_PATCH="$1"
    THIS_BASE=`basename "$THIS_PATCH"`
    if [ ! -f "$THIS_PATCH" ]; then
	return 1;
    fi
    echo -n "Applying patch $THIS_BASE ... ";
    if "$FILE2CAT" "$THIS_PATCH" |
	(cd "$DEST_DIR";patch -p"$STRIP" --no-backup-if-mismatch) >/dev/null; then
	echo "successful."
    else
	echo "failed!"; 
	exit 1;
    fi;
}

apply_patches () {
  local PATCH_DIR=$1
  for f in `(cd "$PATCH_DIR"; find . -type f ! -name 'chk-*' -and ! -name '*~' -and ! -name '*.bak' -and ! -name '.*' -and ! -path './.*' -and ! -path 'CVS') | sed 's,^\./,,g' | LC_COLLATE=C sort`; do 
    if [ "$f" = "$PATCH" ]; then
      break
    else
      apply_patch "$PATCH_DIR/$f"
    fi
  done
}

# APPLY UPSTREAM PATCHES
if [ -n "$SRC_PATCH_DIR" ]; then
  echo "Applying upstream patches"
  apply_patches "$SRC_PATCH_DIR"
else
  echo "No upstream patches"
fi

# APPLY PATCHES UP TO (and not including) $PATCH
NEW_PATCH=""
echo "Applying patches up to (and not including) the requested patch"
if [ ! -f "$PATCH_DIR/$PATCH" ]; then
  touch "$PATCH_DIR/$PATCH"
  NEW_PATCH="true"
fi
apply_patches "$PATCH_DIR"
if [ -n "$NEW_PATCH" ]; then
  rm "$PATCH_DIR/$PATCH"
fi

# MAKE COPY OF SOURCE
cat >> "$OUT_DIR/dbs-update-patch" <<EOF
#!/bin/sh -e
cd "$OUT_DIR"
HOOK_DIR=$HOOK_DIR
test -d "\$HOOK_DIR" && run-parts "\$HOOK_DIR" --arg update-patch-prediff
find -name "*.bak" -print0 | xargs -0 --no-run-if-empty rm
find -name "*~" -print0 | xargs -0 --no-run-if-empty rm
: > new_patch
EOF

for f in `find "$OUT_DIR" -type d -mindepth 1 -maxdepth 1`; do 
  file=`basename "$f"`
  echo -n "Copying $file to $file-old ... "; 
  cp -a "$f" "$f-old"
  echo "successful." 

  # CREATE SHELL SCRIPT TO UPDATE PATCH
  cat >> "$OUT_DIR/dbs-update-patch" <<EOF
diff -ruN $DIFF_EXCLUDE $file-old $file >> new_patch || test \$? -eq 1
EOF
done

cat >> $OUT_DIR/dbs-update-patch <<EOF
mv new_patch "$PATCH_DIR/$PATCH"
test -d "\$HOOK_DIR" && run-parts "\$HOOK_DIR" --arg update-patch-postdiff
EOF

chmod +x $OUT_DIR/dbs-update-patch

# APPLY LAST PATCH
if [ -n "$NEW_PATCH" ]; then
  echo "Patch does not yet exist; will create a new patch $PATCH";
else
  apply_patch "$PATCH_DIR/$PATCH"
fi
