Skip to content

Instantly share code, notes, and snippets.

@froydnj
Created November 21, 2013 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save froydnj/7588223 to your computer and use it in GitHub Desktop.
Save froydnj/7588223 to your computer and use it in GitHub Desktop.
A small shell script for exporting Firefox patches from git repositories to hg ones.
#!/bin/bash
BUG=$(git branch | fgrep '*' | awk '{print $2}')
HG_REPO=
BUGZILLA_BUG=
TRY_PUSH=false
COMMIT_INBOUND=false
PRINT_TO_STDOUT=false
DONTBUILD_BECAUSE_NPOTB=false
REVIEWERS=
APPROVERS=
CLOSED_TREE=false
EMAIL_FIXUP="perl -p -e s/gmail.com/mozilla.com/"
PATCH_CONVERT=~/src/patch-converter/git-patch-to-hg-export.py
DEFAULT_TRY_OPTS='-b do -p all -u all -t none -n'
while getopts ":a:b:fh:r:t:cno" opt
do
case $opt in
a)
APPROVERS=$OPTARG
;;
b)
if echo $OPTARG | grep -q ':' 2>/dev/null; then
BUGZILLA_BUG=($(echo $OPTARG | tr ':' ' '))
else
BUGZILLA_BUG=($OPTARG)
fi
;;
f)
CLOSED_TREE=true
;;
h)
if [ ! -d $OPTARG ]; then
echo "$OPTARG is not a directory"
exit 1
fi
HG_REPO=$OPTARG
;;
r)
if echo $OPTARG | grep -q ':' 2>/dev/null; then
REVIEWERS=($(echo "$OPTARG" | tr ':' ' '))
else
REVIEWERS=("$OPTARG")
fi
;;
t)
TRY_OPTS="$OPTARG"
TRY_PUSH=true
;;
c)
COMMIT_INBOUND=true
;;
n)
DONTBUILD_BECAUSE_NPOTB=true
;;
o)
PRINT_TO_STDOUT=true
;;
?)
case $OPTARG in
t)
TRY_OPTS="$DEFAULT_TRY_OPTS"
TRY_PUSH=true
;;
*)
echo "no argument provided for $OPTARG"
exit 1
;;
esac
;;
*)
echo "Invalid option '${opt}'"
exit 1
;;
esac
done
shift $(($OPTIND - 1))
if [ $# -ne 1 ]; then
echo "need a revision or a revision range"
exit 1
fi
REVISION_SPEC=$1
if git rev-parse --verify --quiet ${REVISION_SPEC} >/dev/null; then
REVISION_SPEC="${REVISION_SPEC}^..${REVISION_SPEC}"
fi
if [ -n "${HG_REPO}" -a \! -d "${HG_REPO}/.hg" ]; then
echo "directory ${HG_REPO} is not a mercurial repository"
exit 1
fi
if $TRY_PUSH; then
if [ -z "${HG_REPO}" ]; then
echo "must specify hg repo for automatic try pushes"
exit 1
fi
if ! (cd ${HG_REPO} && hg paths default|grep -q central 2>/dev/null); then
echo "must push to try from a mozilla-central repository"
exit 1
fi
fi
if $COMMIT_INBOUND; then
if [ -z "${HG_REPO}" ]; then
echo "must specify hg repo for automatic inbound pushes"
exit 1
fi
if ! (cd ${HG_REPO} && hg paths default|grep -q inbound 2>/dev/null); then
echo "must push to inbound from a mozilla-inbound repository"
exit 1
fi
if [ -z "${BUGZILLA_BUG}" ]; then
echo "must specify bug number for automatic inbound pushes"
exit 1
fi
fi
if $COMMIT_INBOUND && $TRY_PUSH; then
echo "cannot push to inbound and try simultaneously"
exit 1
fi
if $PRINT_TO_STDOUT; then
git format-patch -k --stdout ${REVISION_SPEC}
exit 0
fi
COMMIT_IDS="git log --format=oneline ${REVISION_SPEC}"
N_COMMITS=$(${COMMIT_IDS} | awk '{print $1}' | wc -l)
if [ "${#REVIEWERS[*]}" -ne 1 -a "${#REVIEWERS[*]}" -ne $N_COMMITS ]; then
echo number of reviewers "${#REVIEWERS[*]}" does not match number of commits $N_COMMITS
exit 0
fi
if [ "${#BUGZILLA_BUG[*]}" -ne 1 -a "${#BUGZILLA_BUG[*]}" -ne $N_COMMITS ]; then
echo number of bugs "${#BUGZILLA_BUG[*]}" does not match number of commits $N_COMMITS
exit 0
fi
LAST_PATCH=
ALL_PATCHES=
i=$((N_COMMITS-1))
for id in $(${COMMIT_IDS} | awk '{print $1}')
do
logmsg=$(git show --format=oneline $id | head -n 1 | cut -d ' ' -f 2-)
patch_name=${BUG}-${id}-${i}.patch
ALL_PATCHES="${ALL_PATCHES} ${patch_name}"
GIT_EMAIL="git show --unified=3 --binary $id"
if [ -z "${LAST_PATCH}" ]; then
LAST_PATCH=${patch_name}
fi
FORMAT="format:From %H %cd%nFrom: %aN <%aE>%nDate: %aD%n"
subject=""
if git show --format=%s ${id}|head -n 1|egrep -q '^Bug' 2>/dev/null; then
subject="%s"
else
if [ ${#BUGZILLA_BUG[*]} -eq 1 ]; then
bug="${BUGZILLA_BUG[0]}"
else
bug="${BUGZILLA_BUG[${i}]}"
fi
subject="Bug ${bug} - %s"
fi
if [ -n "${REVIEWERS}" ]; then
if [ ${#REVIEWERS[*]} -eq 1 ]; then
reviewer="${REVIEWERS[0]}"
else
reviewer="${REVIEWERS[${i}]}"
fi
subject="${subject}; r=${reviewer}"
fi
if [ -n "${APPROVERS}" ]; then
subject="${subject}; a=${APPROVERS}"
fi
FORMAT="${FORMAT}Subject: [PATCH] ${subject}%n%n%b"
if $DONTBUILD_BECAUSE_NPOTB && [ $i -eq $((N_COMMITS-1)) ]; then
FORMAT="${FORMAT}%nDONTBUILD because NPOTB"
fi
if $CLOSED_TREE && [ $i -eq $((N_COMMITS-1)) ]; then
FORMAT="${FORMAT}%nLanding this on a CLOSED TREE"
fi
if [ -n "${HG_REPO}" ]; then
# Useless Use of cat (instead of --no-pager) to make output look right
# in emacs's shell mode.
git log -n 1 --format="${subject}" $id | cat
${GIT_EMAIL} --format="${FORMAT}" |${EMAIL_FIXUP} | ${PATCH_CONVERT} \
| $(cd $HG_REPO && hg qimport -f --name ${patch_name} -)
else
patch_file=~/src/${patch_name}
echo "exporting '$FORMAT' to ${patch_file}"
${GIT_EMAIL} --format="${FORMAT}"|${EMAIL_FIXUP} | ${PATCH_CONVERT} > ${patch_file}
fi
i=$((i-1))
done
if $TRY_PUSH; then
(cd "$HG_REPO";
if hg qpush "$LAST_PATCH"; then
hg qref -m "Bug ${BUG} try: ${TRY_OPTS}";
hg pushtry
fi;
# Whatever happened, we want to pop patches and remove them.
hg qpop -a && hg qrm $ALL_PATCHES)
fi
if $COMMIT_INBOUND; then
(cd "$HG_REPO" && hg pull -u;
if hg qpush "$LAST_PATCH"; then
hg qfinish -a && hg push inbound
else
hg qpop -a && hg qrm $ALL_PATCHES
fi)
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment