1#!/bin/bash 2# Copyright 2012 the V8 project authors. All rights reserved. 3# Redistribution and use in source and binary forms, with or without 4# modification, are permitted provided that the following conditions are 5# met: 6# 7# * Redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer. 9# * Redistributions in binary form must reproduce the above 10# copyright notice, this list of conditions and the following 11# disclaimer in the documentation and/or other materials provided 12# with the distribution. 13# * Neither the name of Google Inc. nor the names of its 14# contributors may be used to endorse or promote products derived 15# from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29########## Global variable definitions 30 31BRANCHNAME=prepare-merge 32PERSISTFILE_BASENAME=/tmp/v8-merge-to-branch-tempfile 33ALREADY_MERGING_SENTINEL_FILE="$PERSISTFILE_BASENAME-already-merging" 34COMMIT_HASHES_FILE="$PERSISTFILE_BASENAME-PATCH_COMMIT_HASHES" 35TEMPORARY_PATCH_FILE="$PERSISTFILE_BASENAME-temporary-patch" 36 37########## Function definitions 38 39source $(dirname $BASH_SOURCE)/common-includes.sh 40 41usage() { 42cat << EOF 43usage: $0 [OPTIONS]... [BRANCH] [REVISION]... 44 45Performs the necessary steps to merge revisions from bleeding_edge 46to other branches, including trunk. 47 48OPTIONS: 49 -h Show this message 50 -s Specify the step where to start work. Default: 0. 51 -p Specify a patch file to apply as part of the merge 52 -m Specify a commit message for the patch 53 -r Reverse specified patches 54EOF 55} 56 57persist_patch_commit_hashes() { 58 echo "PATCH_COMMIT_HASHES=( ${PATCH_COMMIT_HASHES[@]} )" > $COMMIT_HASHES_FILE 59} 60 61restore_patch_commit_hashes() { 62 source $COMMIT_HASHES_FILE 63} 64 65restore_patch_commit_hashes_if_unset() { 66 [[ "${#PATCH_COMMIT_HASHES[@]}" == 0 ]] && restore_patch_commit_hashes 67 [[ "${#PATCH_COMMIT_HASHES[@]}" == 0 ]] && [[ -z "$EXTRA_PATCH" ]] && \ 68 die "Variable PATCH_COMMIT_HASHES could not be restored." 69} 70 71########## Option parsing 72REVERT_FROM_BLEEDING_EDGE=0 73 74while getopts ":hs:fp:rm:R" OPTION ; do 75 case $OPTION in 76 h) usage 77 exit 0 78 ;; 79 p) EXTRA_PATCH=$OPTARG 80 ;; 81 f) rm -f "$ALREADY_MERGING_SENTINEL_FILE" 82 ;; 83 r) REVERSE_PATCH="--reverse" 84 ;; 85 m) NEW_COMMIT_MSG=$OPTARG 86 ;; 87 s) START_STEP=$OPTARG 88 ;; 89 R) REVERSE_PATCH="--reverse" 90 REVERT_FROM_BLEEDING_EDGE=1 91 ;; 92 ?) echo "Illegal option: -$OPTARG" 93 usage 94 exit 1 95 ;; 96 esac 97done 98let OPTION_COUNT=$OPTIND-1 99shift $OPTION_COUNT 100 101########## Regular workflow 102 103# If there is a merge in progress, abort. 104[[ -e "$ALREADY_MERGING_SENTINEL_FILE" ]] && [[ $START_STEP -eq 0 ]] \ 105 && die "A merge is already in progress" 106touch "$ALREADY_MERGING_SENTINEL_FILE" 107 108initial_environment_checks 109 110if [ $START_STEP -le $CURRENT_STEP ] ; then 111 let MIN_EXPECTED_ARGS=2-$REVERT_FROM_BLEEDING_EDGE 112 if [ ${#@} -lt $MIN_EXPECTED_ARGS ] ; then 113 if [ -z "$EXTRA_PATCH" ] ; then 114 die "Either a patch file or revision numbers must be specified" 115 fi 116 if [ -z "$NEW_COMMIT_MSG" ] ; then 117 die "You must specify a merge comment if no patches are specified" 118 fi 119 fi 120 echo ">>> Step $CURRENT_STEP: Preparation" 121 if [ $REVERT_FROM_BLEEDING_EDGE -eq 1 ] ; then 122 MERGE_TO_BRANCH="bleeding_edge" 123 else 124 MERGE_TO_BRANCH=$1 125 [[ -n "$MERGE_TO_BRANCH" ]] || die "Please specify a branch to merge to" 126 shift 127 fi 128 persist "MERGE_TO_BRANCH" 129 common_prepare 130fi 131 132let CURRENT_STEP+=1 133if [ $START_STEP -le $CURRENT_STEP ] ; then 134 echo ">>> Step $CURRENT_STEP: Create a fresh branch for the patch." 135 restore_if_unset "MERGE_TO_BRANCH" 136 git checkout -b $BRANCHNAME svn/$MERGE_TO_BRANCH \ 137 || die "Creating branch $BRANCHNAME failed." 138fi 139 140let CURRENT_STEP+=1 141if [ $START_STEP -le $CURRENT_STEP ] ; then 142 echo ">>> Step $CURRENT_STEP: Find the git \ 143revisions associated with the patches." 144 current=0 145 for REVISION in "$@" ; do 146 NEXT_HASH=$(git svn find-rev "r$REVISION" svn/bleeding_edge) 147 [[ -n "$NEXT_HASH" ]] \ 148 || die "Cannot determine git hash for r$REVISION" 149 PATCH_COMMIT_HASHES[$current]="$NEXT_HASH" 150 [[ -n "$REVISION_LIST" ]] && REVISION_LIST="$REVISION_LIST," 151 REVISION_LIST="$REVISION_LIST r$REVISION" 152 let current+=1 153 done 154 if [ -n "$REVISION_LIST" ] ; then 155 if [ -n "$REVERSE_PATCH" ] ; then 156 if [ $REVERT_FROM_BLEEDING_EDGE -eq 0 ] ; then 157 NEW_COMMIT_MSG="Rollback of$REVISION_LIST in $MERGE_TO_BRANCH branch." 158 else 159 NEW_COMMIT_MSG="Revert$REVISION_LIST." 160 fi 161 else 162 NEW_COMMIT_MSG="Merged$REVISION_LIST into $MERGE_TO_BRANCH branch." 163 fi; 164 fi; 165 166 echo "$NEW_COMMIT_MSG" > $COMMITMSG_FILE 167 echo "" >> $COMMITMSG_FILE 168 for HASH in ${PATCH_COMMIT_HASHES[@]} ; do 169 PATCH_MERGE_DESCRIPTION=$(git log -1 --format=%s $HASH) 170 echo "$PATCH_MERGE_DESCRIPTION" >> $COMMITMSG_FILE 171 echo "" >> $COMMITMSG_FILE 172 done 173 for HASH in ${PATCH_COMMIT_HASHES[@]} ; do 174 BUG=$(git log -1 $HASH | grep "BUG=" | awk -F '=' '{print $NF}') 175 if [ -n "$BUG" ] ; then 176 [[ -n "$BUG_AGGREGATE" ]] && BUG_AGGREGATE="$BUG_AGGREGATE," 177 BUG_AGGREGATE="$BUG_AGGREGATE$BUG" 178 fi 179 done 180 if [ -n "$BUG_AGGREGATE" ] ; then 181 echo "BUG=$BUG_AGGREGATE" >> $COMMITMSG_FILE 182 fi 183 persist "NEW_COMMIT_MSG" 184 persist "REVISION_LIST" 185 persist_patch_commit_hashes 186fi 187 188let CURRENT_STEP+=1 189if [ $START_STEP -le $CURRENT_STEP ] ; then 190 echo ">>> Step $CURRENT_STEP: Apply patches for selected revisions." 191 restore_if_unset "MERGE_TO_BRANCH" 192 restore_patch_commit_hashes_if_unset "PATCH_COMMIT_HASHES" 193 rm -f "$TOUCHED_FILES_FILE" 194 for HASH in ${PATCH_COMMIT_HASHES[@]} ; do 195 echo "Applying patch for $HASH to $MERGE_TO_BRANCH..." 196 git log -1 -p $HASH > "$TEMPORARY_PATCH_FILE" 197 apply_patch "$TEMPORARY_PATCH_FILE" 198 done 199 if [ -n "$EXTRA_PATCH" ] ; then 200 apply_patch "$EXTRA_PATCH" 201 fi 202fi 203 204let CURRENT_STEP+=1 205if [ $START_STEP -le $CURRENT_STEP ] && [ $REVERT_FROM_BLEEDING_EDGE -eq 0 ] ; then 206 echo ">>> Step $CURRENT_STEP: Prepare $VERSION_FILE." 207 # These version numbers are used again for creating the tag 208 read_and_persist_version 209fi 210 211let CURRENT_STEP+=1 212if [ $START_STEP -le $CURRENT_STEP ] && [ $REVERT_FROM_BLEEDING_EDGE -eq 0 ] ; then 213 echo ">>> Step $CURRENT_STEP: Increment version number." 214 restore_if_unset "PATCH" 215 NEWPATCH=$(($PATCH + 1)) 216 confirm "Automatically increment PATCH_LEVEL? (Saying 'n' will fire up \ 217your EDITOR on $VERSION_FILE so you can make arbitrary changes. When \ 218you're done, save the file and exit your EDITOR.)" 219 if [ $? -eq 0 ] ; then 220 echo $NEWPATCH $VERSION_FILE 221 sed -e "/#define PATCH_LEVEL/s/[0-9]*$/$NEWPATCH/" \ 222 -i.bak "$VERSION_FILE" || die "Could not increment patch level" 223 else 224 $EDITOR "$VERSION_FILE" 225 fi 226 read_and_persist_version "NEW" 227fi 228 229let CURRENT_STEP+=1 230if [ $START_STEP -le $CURRENT_STEP ] ; then 231 echo ">>> Step $CURRENT_STEP: Commit to local branch." 232 git commit -a -F "$COMMITMSG_FILE" \ 233 || die "'git commit -a' failed." 234fi 235 236upload_step 237 238let CURRENT_STEP+=1 239if [ $START_STEP -le $CURRENT_STEP ] ; then 240 echo ">>> Step $CURRENT_STEP: Commit to the repository." 241 restore_if_unset "MERGE_TO_BRANCH" 242 git checkout $BRANCHNAME \ 243 || die "cannot ensure that the current branch is $BRANCHNAME" 244 wait_for_lgtm 245 PRESUBMIT_TREE_CHECK="skip" git cl dcommit \ 246 || die "failed to commit to $MERGE_TO_BRANCH" 247fi 248 249let CURRENT_STEP+=1 250if [ $START_STEP -le $CURRENT_STEP ] && [ $REVERT_FROM_BLEEDING_EDGE -eq 0 ] ; then 251 echo ">>> Step $CURRENT_STEP: Determine svn commit revision" 252 restore_if_unset "NEW_COMMIT_MSG" 253 restore_if_unset "MERGE_TO_BRANCH" 254 git svn fetch || die "'git svn fetch' failed." 255 COMMIT_HASH=$(git log -1 --format=%H --grep="$NEW_COMMIT_MSG" \ 256 svn/$MERGE_TO_BRANCH) 257 [[ -z "$COMMIT_HASH" ]] && die "Unable to map git commit to svn revision" 258 SVN_REVISION=$(git svn find-rev $COMMIT_HASH) 259 echo "subversion revision number is r$SVN_REVISION" 260 persist "SVN_REVISION" 261fi 262 263let CURRENT_STEP+=1 264if [ $START_STEP -le $CURRENT_STEP ] && [ $REVERT_FROM_BLEEDING_EDGE -eq 0 ] ; then 265 echo ">>> Step $CURRENT_STEP: Create the tag." 266 restore_if_unset "SVN_REVISION" 267 restore_version_if_unset "NEW" 268 echo "Creating tag svn/tags/$NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH" 269 if [ "$MERGE_TO_BRANCH" == "trunk" ] ; then 270 TO_URL="$MERGE_TO_BRANCH" 271 else 272 TO_URL="branches/$MERGE_TO_BRANCH" 273 fi 274 svn copy -r $SVN_REVISION \ 275 https://v8.googlecode.com/svn/$TO_URL \ 276 https://v8.googlecode.com/svn/tags/$NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH \ 277 -m "Tagging version $NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH" 278 persist "TO_URL" 279fi 280 281let CURRENT_STEP+=1 282if [ $START_STEP -le $CURRENT_STEP ] ; then 283 echo ">>> Step $CURRENT_STEP: Cleanup." 284 restore_if_unset "SVN_REVISION" 285 restore_if_unset "TO_URL" 286 restore_if_unset "REVISION_LIST" 287 restore_version_if_unset "NEW" 288 common_cleanup 289 if [ $REVERT_FROM_BLEEDING_EDGE==0 ] ; then 290 echo "*** SUMMARY ***" 291 echo "version: $NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH" 292 echo "branch: $TO_URL" 293 echo "svn revision: $SVN_REVISION" 294 [[ -n "$REVISION_LIST" ]] && echo "patches:$REVISION_LIST" 295 fi 296fi 297