Created
November 21, 2013 19:42
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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