#!/bin/bash
#
# Make tar for git repo w/ one level of sub modules.
#
set -e

die() {
  echo "$1" >&2
  exit 1
}

maybedie() {
  if [ "$DEVMODE" ]; then
    echo "Warning: $1" >&2
  else
    echo "Error: $1" >&2
    exit 1
  fi
}

usage() {
   cat <<EOF >&2
usage: $0 [-v] [-d] <rev> [<outfile> [<prefix>]]

  <rev> may be any git revision spec. (tag or, using -d, branch or commit id).

  If provided, <outfile> must end with ".tar", ".tar.gz" or ".tar.bz2".
  If <outfile> is omitted, "base-<rev>.tar.gz" will be used.
  If provided, <prefix> must end with "/".  If <prefix> is omitted,
  the default is "base-<rev>/".

  Options:

    -v   Enable verbose prints
    -d   Enable permissive developer mode
EOF
   exit 1
}

export DEVMODE=

while getopts "vd" OPT
do
    case "$OPT" in
    v) set -x;;
    d) DEVMODE=1;;
    ?) echo "Unknown option"
       usage;;
    esac
done
shift $(($OPTIND - 1))

TOPREV="$1"
FINALTAR="$2"
PREFIX="${3:-}"

[ "$TOPREV" ] || usage

case "$FINALTAR" in
"")
  TAROPT=-z
  FINALTAR="base-$TOPREV.tar.gz"
  ;;
*.tar)
  TAROPT=""
  ;;
*.tar.gz)
  TAROPT=-z
  ;;
*.tar.bz2)
  TAROPT=-j
  ;;
*)
  die "outfile must end with '.tar.gz' or '.tar.bz2'"
  ;;
esac

case "$PREFIX" in
"")
  PREFIX="base-$TOPREV/"
  ;;
*/)
  ;;
*)
  die "Prefix must end with '/'"
  ;;
esac

# Check for both <tag> and R<tag>
if ! [ `git tag -l $TOPREV` ]
then
  if [ `git tag -l R$TOPREV` ]
  then
    TOPREV="R$TOPREV"
  else
    maybedie "No tags exist '$TOPREV' or 'R$TOPREV'"
  fi
fi

# temporary directory w/ automatic cleanup
TDIR=`mktemp -d`
trap 'rm -rf "$TDIR"' EXIT INT QUIT TERM

mkdir "$TDIR"/tar

echo "Exporting revision $TOPREV as $FINALTAR with prefix $PREFIX"

# Use git-archive to copy files at the given revision into our temp. dir.
# Respects 'export-exclude' in .gitattributes files.

git archive --prefix=$PREFIX $TOPREV | tar -C "$TDIR"/tar -x

# use ls-tree instead of submodule-foreach to capture submodule revision associated with supermodule rev.
#
# sub-modules appear in tree as eg.:
#  160000 commit c3a6cfcf0dad4a4eeecf59b474710d06ff3eb68a  modules/ca
git ls-tree -r $TOPREV | \
  awk '/^[0-9]+ commit / && $4 != ".ci" {print $3, $4}' | \
while read HASH MODDIR
do
    echo "Visiting $HASH $MODDIR"
    if [ -e $MODDIR/.git ]
    then
        git -C $MODDIR archive --prefix=${PREFIX}${MODDIR}/ $HASH | tar -C "$TDIR"/tar -x
    else
        maybedie "  Submodule not checked out."
    fi
done

# make a list of files copied and filter out undesirables

(cd "$TDIR"/tar && find . -mindepth 1 -not -type d) > "$TDIR"/list.1

# Remove leading ./ from filenames
sed -i -e 's|^\./||' "$TDIR"/list.1

# Exclude files
sed \
  -e '/\/\.appveyor\.yml$/d' \
  -e '/\/\.appveyor\//d' \
  -e '/\/\.ci-local\//d' \
  -e '/\/\.ci\//d' \
  -e '/\/\.cproject$/d' \
  -e '/\/\.github\//d' \
  -e '/\/\.gitmodules$/d' \
  -e '/\/\.hgtags$/d' \
  -e '/\/\.lgtm\.yml$/d' \
  -e '/\/\.project$/d' \
  -e '/\/\.readthedocs\.yml$/d' \
  -e '/\/\.tools\//d' \
  -e '/\/\.travis\.yml$/d' \
  -e '/\/jenkins\//d' \
  "$TDIR"/list.1 > "$TDIR"/list.2

if ! diff -U 0 "$TDIR"/list.1 "$TDIR"/list.2
then
    echo "Excluding the files shown above"
fi

# Use the filtered list to build the final tar
tar -c $TAROPT -C "$TDIR"/tar -T "$TDIR"/list.2 -f "$FINALTAR"

echo "Wrote $FINALTAR"

tar -t $TAROPT -f "$FINALTAR" > "$TDIR"/list.3

# make sure we haven't picked up anything extra
if ! diff -u "$TDIR"/list.2 "$TDIR"/list.3
then
    die "Oops! Tarfile diff against plan shown above"
fi
