#!/bin/bash # ============================================================================== # *** BackFLiP (a.k.a BACKporting Fun with LInaro People) *** # # Usage: backflip rev_number # ============================================================================== # ============================================================================== # Configuration # ============================================================================== VERSION=4.9 REF_BRANCH=linaro-${VERSION}-branch DATE=`date +%Y-%m-%d` NAME=`git config user.name` FNAME=`echo ${NAME} | cut -d ' ' -f 1` EMAIL=`git config user.email` EDITOR="${EDITOR:-vim}" STACKED=false CMPTOOL="meld" # Arguments while getopts "b:r:v:" options do case $options in r ) REF_BRANCH=$OPTARG ;; b ) DEV_BRANCH=$OPTARG STACKED=true ;; v ) VERSION=$OPTARG REF_BRANCH=linaro-${VERSION}-branch ;; esac done shift $(($OPTIND - 1)) REV=$1 if [ -z ${DEV_BRANCH+x} ]; then DEV_BRANCH=${REF_BRANCH} fi # Style NC='\e[0m' red='\e[0;31m' blue='\e[1;34m' green='\e[0;32m' bold='\e[1m' lines=`perl -E 'say "-" x 80'` # ============================================================================== # Functions # ============================================================================== print_step() { echo -e "${blue}${lines}\n${red}** ${1}\n${blue}${lines}${NC}\n" } print_info() { echo -e "${blue}** ${NC}${1}" } die() { echo -e "${red}${bold}ERROR: ${NC}${bold}${1}${NC}" exit 1 } open_shell() { PROMPT_COMMAND="echo -n -e '${bold}[${red}BackFLiP${NC}${bold}]${NC} '" bash } # arg1 : a sentence # arg2 : a variable # print arg1 and gather user input in arg2 ask() { echo -n -e "${blue}** ${NC}${1} ${NC}" eval "read ${2}" } # arg1 : svn rev number # arg2 : ChangeLog file # Create ChangeLog entry for arg1 in arg2.arg1.frag forge_entry() { echo -e $DATE" "$NAME" <"$EMAIL">\n\n\tBackport from trunk r"$1"." >> $2.$1.frag git show --format=oneline ${SHA1} -- $2 \ | grep ^+ \ | sed -e '1d' -e 's:^+::' \ | awk '$1 ~ /^2.*$/ {print "\t"$0} $1 !~ /^2.*$/ {print $0}' >> $2.$1.frag print_info "${bold}Forged ChangeLog entry:${NC}" cat $2.$1.frag ask "${bold}Edit ChangeLog entry [N/y] ?" user_edit if [ "$user_edit" == "y" ]; then "$EDITOR" $2.$1.frag fi } # arg1 : backported revision sha1 compare() { git show $1 > $REV.orig git diff --cached > $REV.linaro print_info "Generated diff files: ${bold}$REV.orig $REV.linaro${NC}" "$CMPTOOL" $REV.orig $REV.linaro ask "${bold}Do you need a Shell [N/y] ?" user_shell if [ "$user_shell" == "y" ]; then open_shell fi rm $REV.orig $REV.linaro } # ============================================================================== # Checking Configuration # ============================================================================== if ! git remote -v 2>&1 | grep "ssh.*git.*\.linaro\.org" > /dev/null ; then die "You're not in the right directory !" fi if [ ! -e .gitreview ]; then print_info "Gerrit configuration (.gitreview) is missing, creating it." cat <<- EOF > .gitreview [gerrit] host=review.linaro.org port=29418 project=toolchain/gcc EOF fi if ! which $CMPTOOL > /dev/null ; then print_info "Default comparison tool is missing" ask "Enter tool name: " CMPTOOL fi echo -e "${blue}${lines}" print_info "Backport will de done on top of branch: ${bold}$DEV_BRANCH${NC}" print_info "Reference branch used for review is: ${bold}$REF_BRANCH${NC}" print_info "To change GCC version in a Linaro branch use ${bold}-v${NC}" print_info "example: ${bold}backflip -v 4.8${NC}" print_info "To change reference branch use ${bold}-r${NC}" print_info "example: ${bold}backflip -r master${NC}" # ============================================================================== print_step "Finding SHA1" # ============================================================================== SHA1=`git log --format=format:"%H" --grep=trunk@${REV} master` print_info "${NC}SVN rev ${bold}${1}${NC} SHA1: ${bold}${SHA1}${NC}" ask "${bold}View the commit [N/y] ?" user_view if [ "$user_view" == "y" ]; then git show $SHA1 fi # ============================================================================== print_step "Cherry-picking Revision" # ============================================================================== git checkout $DEV_BRANCH git cherry-pick -n $SHA1 # ============================================================================== print_step "Handling ChangeLogs Conflicts" # ============================================================================== CHLOGS=`git diff-tree --no-commit-id --name-only -r ${SHA1} | grep ChangeLog` for i in $CHLOGS; do print_info "${green}$i" # Revert ChangeLog corruption git reset -q HEAD $i git checkout $i # Create ChangeLog entry forge_entry $1 $i done # ============================================================================== print_step "Status Checking" # ============================================================================== git status ask "${bold}Open a Shell [N/y] ?" user_shell if [ "$user_shell" == "y" ]; then open_shell fi # ============================================================================== print_step "Verification" # ============================================================================== compare $SHA1 # ============================================================================== print_step "Branch/Commit/Push/Review" # ============================================================================== if $STACKED; then bname=${DEV_BRANCH}-${1} else bname=${FNAME}-${VERSION}-backport-${1} fi ask "${bold}Create backport branch [Y/n] ?" user_bc if [ "$user_bc" != "n" ]; then ask "${bold}Change name (${blue}${bname}${NC}${bold}) [N/y] ?" user_bname if [ "$user_bname" == "y" ]; then ask "${bold}Enter name :" bname fi git checkout -b ${bname} ${DEV_BRANCH} ask "${bold}Commit backport [Y/n] ?" user_commit if [ "$user_commit" != "n" ]; then if $STACKED; then git commit --amend else git commit fi echo print_info "If you want to stack another backport on top of this one" print_info "you can stop here, and invoke backflip with command:" print_info "${bold}backflip -b ${bname} REV_NUMBER${NC}" print_info "The next steps are only needed for review and validation.\n" ask "${bold}Create patch [Y/n] ?" user_patch if [ "$user_patch" != "n" ]; then git format-patch -o ../ --suffix=.${bname}.patch -1 fi ask "${bold}Request review (amend commit) [Y/n] ?" user_review if [ "$user_review" != "n" ]; then git review $REF_BRANCH git checkout $DEV_BRANCH fi fi fi # ============================================================================== ask "${bold}Abort and Cleanup [N/y] ?" user_abort # ============================================================================== if [ "$user_abort" == "y" ]; then git reset --hard git checkout ${DEV_BRANCH} if [ "$user_bc" != "n" ]; then git branch -D ${bname} if [ "$user_push" != "n" ]; then git push origin :${bname} fi fi exit 0 fi