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 31 BRANCHNAME=prepare-merge 32 PERSISTFILE_BASENAME=/tmp/v8-merge-to-branch-tempfile 33 ALREADY_MERGING_SENTINEL_FILE="$PERSISTFILE_BASENAME-already-merging" 34 COMMIT_HASHES_FILE="$PERSISTFILE_BASENAME-PATCH_COMMIT_HASHES" 35 TEMPORARY_PATCH_FILE="$PERSISTFILE_BASENAME-temporary-patch" 36 37 ########## Function definitions 38 39 source $(dirname $BASH_SOURCE)/common-includes.sh 40 41 usage() { 42 cat << EOF 43 usage: $0 [OPTIONS]... [BRANCH] [REVISION]... 44 45 Performs the necessary steps to merge revisions from bleeding_edge 46 to other branches, including trunk. 47 48 OPTIONS: 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 54 EOF 55 } 56 57 persist_patch_commit_hashes() { 58 echo "PATCH_COMMIT_HASHES=( ${PATCH_COMMIT_HASHES[@]} )" > $COMMIT_HASHES_FILE 59 } 60 61 restore_patch_commit_hashes() { 62 source $COMMIT_HASHES_FILE 63 } 64 65 restore_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 72 73 while getopts ":hs:fp:rm:" OPTION ; do 74 case $OPTION in 75 h) usage 76 exit 0 77 ;; 78 p) EXTRA_PATCH=$OPTARG 79 ;; 80 f) rm -f "$ALREADY_MERGING_SENTINEL_FILE" 81 ;; 82 r) REVERSE_PATCH="--reverse" 83 ;; 84 m) NEW_COMMIT_MSG=$OPTARG 85 ;; 86 s) START_STEP=$OPTARG 87 ;; 88 ?) echo "Illegal option: -$OPTARG" 89 usage 90 exit 1 91 ;; 92 esac 93 done 94 let OPTION_COUNT=$OPTIND-1 95 shift $OPTION_COUNT 96 97 ########## Regular workflow 98 99 # If there is a merge in progress, abort. 100 [[ -e "$ALREADY_MERGING_SENTINEL_FILE" ]] && [[ $START_STEP -eq 0 ]] \ 101 && die "A merge is already in progress" 102 touch "$ALREADY_MERGING_SENTINEL_FILE" 103 104 initial_environment_checks 105 106 if [ $START_STEP -le $CURRENT_STEP ] ; then 107 if [ ${#@} -lt 2 ] ; then 108 if [ -z "$EXTRA_PATCH" ] ; then 109 die "Either a patch file or revision numbers must be specified" 110 fi 111 if [ -z "$NEW_COMMIT_MSG" ] ; then 112 die "You must specify a merge comment if no patches are specified" 113 fi 114 fi 115 echo ">>> Step $CURRENT_STEP: Preparation" 116 MERGE_TO_BRANCH=$1 117 [[ -n "$MERGE_TO_BRANCH" ]] || die "Please specify a branch to merge to" 118 shift 119 persist "MERGE_TO_BRANCH" 120 common_prepare 121 fi 122 123 let CURRENT_STEP+=1 124 if [ $START_STEP -le $CURRENT_STEP ] ; then 125 echo ">>> Step $CURRENT_STEP: Create a fresh branch for the patch." 126 restore_if_unset "MERGE_TO_BRANCH" 127 git checkout -b $BRANCHNAME svn/$MERGE_TO_BRANCH \ 128 || die "Creating branch $BRANCHNAME failed." 129 fi 130 131 let CURRENT_STEP+=1 132 if [ $START_STEP -le $CURRENT_STEP ] ; then 133 echo ">>> Step $CURRENT_STEP: Find the git \ 134 revisions associated with the patches." 135 current=0 136 for REVISION in "$@" ; do 137 NEXT_HASH=$(git svn find-rev "r$REVISION" svn/bleeding_edge) 138 [[ -n "$NEXT_HASH" ]] \ 139 || die "Cannot determine git hash for r$REVISION" 140 PATCH_COMMIT_HASHES[$current]="$NEXT_HASH" 141 [[ -n "$REVISION_LIST" ]] && REVISION_LIST="$REVISION_LIST," 142 REVISION_LIST="$REVISION_LIST r$REVISION" 143 let current+=1 144 done 145 if [ -n "$REVISION_LIST" ] ; then 146 if [ -n "$REVERSE_PATCH" ] ; then 147 NEW_COMMIT_MSG="Rollback of$REVISION_LIST in $MERGE_TO_BRANCH branch." 148 else 149 NEW_COMMIT_MSG="Merged$REVISION_LIST into $MERGE_TO_BRANCH branch." 150 fi; 151 fi; 152 153 echo "$NEW_COMMIT_MSG" > $COMMITMSG_FILE 154 echo "" >> $COMMITMSG_FILE 155 for HASH in ${PATCH_COMMIT_HASHES[@]} ; do 156 PATCH_MERGE_DESCRIPTION=$(git log -1 --format=%s $HASH) 157 echo "$PATCH_MERGE_DESCRIPTION" >> $COMMITMSG_FILE 158 echo "" >> $COMMITMSG_FILE 159 done 160 for HASH in ${PATCH_COMMIT_HASHES[@]} ; do 161 BUG=$(git log -1 $HASH | grep "BUG=" | awk -F '=' '{print $NF}') 162 if [ -n "$BUG" ] ; then 163 [[ -n "$BUG_AGGREGATE" ]] && BUG_AGGREGATE="$BUG_AGGREGATE," 164 BUG_AGGREGATE="$BUG_AGGREGATE$BUG" 165 fi 166 done 167 if [ -n "$BUG_AGGREGATE" ] ; then 168 echo "BUG=$BUG_AGGREGATE" >> $COMMITMSG_FILE 169 fi 170 persist "NEW_COMMIT_MSG" 171 persist "REVISION_LIST" 172 persist_patch_commit_hashes 173 fi 174 175 let CURRENT_STEP+=1 176 if [ $START_STEP -le $CURRENT_STEP ] ; then 177 echo ">>> Step $CURRENT_STEP: Apply patches for selected revisions." 178 restore_if_unset "MERGE_TO_BRANCH" 179 restore_patch_commit_hashes_if_unset "PATCH_COMMIT_HASHES" 180 rm -f "$TOUCHED_FILES_FILE" 181 for HASH in ${PATCH_COMMIT_HASHES[@]} ; do 182 echo "Applying patch for $HASH to $MERGE_TO_BRANCH..." 183 git log -1 -p $HASH > "$TEMPORARY_PATCH_FILE" 184 apply_patch "$TEMPORARY_PATCH_FILE" 185 done 186 if [ -n "$EXTRA_PATCH" ] ; then 187 apply_patch "$EXTRA_PATCH" 188 fi 189 fi 190 191 let CURRENT_STEP+=1 192 if [ $START_STEP -le $CURRENT_STEP ] ; then 193 echo ">>> Step $CURRENT_STEP: Prepare $VERSION_FILE." 194 # These version numbers are used again for creating the tag 195 read_and_persist_version 196 fi 197 198 let CURRENT_STEP+=1 199 if [ $START_STEP -le $CURRENT_STEP ] ; then 200 echo ">>> Step $CURRENT_STEP: Increment version number." 201 restore_if_unset "PATCH" 202 NEWPATCH=$(($PATCH + 1)) 203 confirm "Automatically increment PATCH_LEVEL? (Saying 'n' will fire up \ 204 your EDITOR on $VERSION_FILE so you can make arbitrary changes. When \ 205 you're done, save the file and exit your EDITOR.)" 206 if [ $? -eq 0 ] ; then 207 echo $NEWPATCH $VERSION_FILE 208 sed -e "/#define PATCH_LEVEL/s/[0-9]*$/$NEWPATCH/" \ 209 -i.bak "$VERSION_FILE" || die "Could not increment patch level" 210 else 211 $EDITOR "$VERSION_FILE" 212 fi 213 read_and_persist_version "NEW" 214 fi 215 216 let CURRENT_STEP+=1 217 if [ $START_STEP -le $CURRENT_STEP ] ; then 218 echo ">>> Step $CURRENT_STEP: Commit to local branch." 219 git commit -a -F "$COMMITMSG_FILE" \ 220 || die "'git commit -a' failed." 221 fi 222 223 upload_step 224 225 let CURRENT_STEP+=1 226 if [ $START_STEP -le $CURRENT_STEP ] ; then 227 echo ">>> Step $CURRENT_STEP: Commit to the repository." 228 restore_if_unset "MERGE_TO_BRANCH" 229 git checkout $BRANCHNAME \ 230 || die "cannot ensure that the current branch is $BRANCHNAME" 231 wait_for_lgtm 232 git cl dcommit || die "failed to commit to $MERGE_TO_BRANCH" 233 fi 234 235 let CURRENT_STEP+=1 236 if [ $START_STEP -le $CURRENT_STEP ] ; then 237 echo ">>> Step $CURRENT_STEP: Determine svn commit revision" 238 restore_if_unset "NEW_COMMIT_MSG" 239 restore_if_unset "MERGE_TO_BRANCH" 240 git svn fetch || die "'git svn fetch' failed." 241 COMMIT_HASH=$(git log -1 --format=%H --grep="$NEW_COMMIT_MSG" \ 242 svn/$MERGE_TO_BRANCH) 243 [[ -z "$COMMIT_HASH" ]] && die "Unable to map git commit to svn revision" 244 SVN_REVISION=$(git svn find-rev $COMMIT_HASH) 245 echo "subversion revision number is r$SVN_REVISION" 246 persist "SVN_REVISION" 247 fi 248 249 let CURRENT_STEP+=1 250 if [ $START_STEP -le $CURRENT_STEP ] ; then 251 echo ">>> Step $CURRENT_STEP: Create the tag." 252 restore_if_unset "SVN_REVISION" 253 restore_version_if_unset "NEW" 254 echo "Creating tag svn/tags/$NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH" 255 if [ "$MERGE_TO_BRANCH" == "trunk" ] ; then 256 TO_URL="$MERGE_TO_BRANCH" 257 else 258 TO_URL="branches/$MERGE_TO_BRANCH" 259 fi 260 svn copy -r $SVN_REVISION \ 261 https://v8.googlecode.com/svn/$TO_URL \ 262 https://v8.googlecode.com/svn/tags/$NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH \ 263 -m "Tagging version $NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH" 264 persist "TO_URL" 265 fi 266 267 let CURRENT_STEP+=1 268 if [ $START_STEP -le $CURRENT_STEP ] ; then 269 echo ">>> Step $CURRENT_STEP: Cleanup." 270 restore_if_unset "SVN_REVISION" 271 restore_if_unset "TO_URL" 272 restore_if_unset "REVISION_LIST" 273 restore_version_if_unset "NEW" 274 common_cleanup 275 echo "*** SUMMARY ***" 276 echo "version: $NEWMAJOR.$NEWMINOR.$NEWBUILD.$NEWPATCH" 277 echo "branch: $TO_URL" 278 echo "svn revision: $SVN_REVISION" 279 [[ -n "$REVISION_LIST" ]] && echo "patches:$REVISION_LIST" 280 fi 281