summaryrefslogtreecommitdiff
path: root/backflip
blob: 237dbfed9cf842cec0a559c1be5423a4bf9b5457 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#!/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