-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcranky-update-tree
More file actions
executable file
·220 lines (185 loc) · 5.24 KB
/
cranky-update-tree
File metadata and controls
executable file
·220 lines (185 loc) · 5.24 KB
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
#!/bin/bash -eu
#
# Update to a parent kernel
#
C=${C:-cranky}
function out()
{
local rc=${?}
trap - EXIT INT TERM HUP
if [ -n "${TMP_BRANCH}" ] ; then
git reset --hard
git checkout -f "${CUR_BRANCH}"
git branch -D "${TMP_BRANCH}"
fi
if [ "${rc}" -ne 0 ] ; then
echo "-- Update failed" >&2
fi
exit "${rc}"
}
function usage()
{
cat <<EOF
Usage: ${C} update-tree [-h] PARENT [REFSPEC]
Rebase onto (or cherry-pick from) a parent kernel.
Positional arguments:
PARENT Name of the parent kernel. A local directory with the name
debian.<PARENT> must exist.
REFSPEC Rebase onto (or cherry-pick up to) REFSPEC. If not provided,
determines REFSPEC automatically.
Optional arguments:
-d, --dry-run
--force
-h, --help Show this help text and exit.
-s, --strategy STRATEGY Valid values: rebase, cherry-pick. If not provided,
defaults to rebase.
EOF
}
dry_run=0
force=0
strategy=rebase
parent=
refspec=
while [ ${#} -gt 0 ] ; do
case "${1}" in
-d|--dry-run)
dry_run=1
;;
--force)
force=1
;;
-h|--help)
usage
exit
;;
-s|--strategy)
shift
strategy=${1}
;;
*)
if [ -z "${parent}" ] ; then
parent=${1}
elif [ -z "${refspec}" ] ; then
refspec=${1}
else
echo "Invalid argument; ${1}" >&2
exit 2
fi
;;
esac
shift
done
if [ -z "${parent}" ] ; then
usage
exit 2
fi
case "${strategy}" in
rebase|cherry-pick) ;;
*)
echo "Invalid strategy: ${strategy}" >&2
exit 2
;;
esac
TMP_BRANCH=
CUR_BRANCH=
trap out EXIT INT TERM HUP
if ! [ -d debian."${parent}" ] ; then
echo "No such directory: debian.${parent}" >&2
fi
changelog=debian."${parent}"/changelog
ser=$(dpkg-parsechangelog -l "${changelog}" -S Distribution)
src=$(dpkg-parsechangelog -l "${changelog}" -S Source)
parent=${ser}:${src}
# Get the git URL/branch of the parent's main package
read -r _series _type url branch < <("$C" list-repos --git-url --include main "${parent}")
if [ -z "${url}" ] || [ -z "${branch}" ] ; then
echo "Failed to determine git repo URL and branch for ${parent}"
exit 1
fi
if [ -z "${refspec}" ] ; then
refspec=${branch}
fi
echo "Fetch ${url} ${refspec}"
git fetch "${url}" "${refspec}"
# Find the remote parent commit to rebase onto
new_base=$(git log --format='%H %s' FETCH_HEAD | grep -m1 -E '^[0-9a-f]{40} UBUNTU: Ubuntu-' || true)
if [ -z "${new_base}" ] ; then
echo "Failed to find remote parent commit ('UBUNTU: Ubuntu-...')" >&2
exit 1
fi
echo "Remote parent commit (new base): ${new_base}"
# Find the latest local parent commit
cur_base=$(git log --format='%H %s' -- "${changelog}" | grep -m1 -E '^[0-9a-f]{40} UBUNTU: Ubuntu-' || true)
if [ -z "${cur_base}" ] ; then
echo "Failed to find local parent commit ('UBUNTU: Ubuntu-...')" >&2
exit 1
fi
echo "Local parent commit (current base): ${cur_base}"
new_base_hash=${new_base%% *}
new_base_subject=${new_base#* }
cur_base_hash=${cur_base%% *}
cur_base_subject=${cur_base#* }
if [ "${strategy}" = "rebase" ] ; then
if [ "${cur_base}" = "${new_base}" ] ; then
echo "Already up-to-date (no rebase necessary)"
exit 0
fi
echo "Rebase needed from '${cur_base_subject}' onto '${new_base_subject}'"
if [ "${cur_base_subject}" = "${new_base_subject}" ] ; then
echo "WARNING: Commit subjects are identical! Did you mean to use --strategy cherry-pick?"
if [ ${force} -eq 0 ] ; then
echo "Use --force to continue with the rebase"
exit 1
fi
fi
echo "git rebase --onto ${new_base_hash} ${cur_base_hash}"
if [ ${dry_run} -eq 1 ] ; then
echo "Dry-run, exiting..."
exit
fi
git rebase --onto "${new_base_hash}" "${cur_base_hash}"
fi
if [ "${strategy}" = "cherry-pick" ] ; then
if [ "${cur_base_subject}" = "${new_base_subject}" ] ; then
echo "Already up-to-date (no cherry-picking necessary)"
exit 0
fi
echo "Cherry-picking needed from '${cur_base_subject}' to '${new_base_subject}'"
# Construct the list of commits to cherry-pick
new_cur_base=$(git log --format='%H %s' FETCH_HEAD | grep -m1 -E "^[0-9a-f]{40} ${cur_base_subject}$" || true)
if [ -z "${new_cur_base}" ] ; then
echo "Failed to find remote parent commit ('${cur_base_subject}')" >&2
exit 1
fi
new_cur_base_hash=${new_cur_base%% *}
echo "Cherry-picking the following commits:"
{
git log --oneline --no-merges "${cur_base_hash}"..
git log --oneline --no-merges "${new_cur_base_hash}".."${new_base_hash}"
} | tac
if [ ${dry_run} -eq 1 ] ; then
echo "Dry-run, exiting..."
exit
fi
# Switch to a temporary branch to do all the work on
CUR_BRANCH=$(git rev-parse --abbrev-ref HEAD)
TMP_BRANCH=cranky-update-tree-$$
git checkout -b "${TMP_BRANCH}" "${cur_base_hash}"
# Cherry-pick the new parent commits
git cherry-pick "${new_cur_base_hash}".."${new_base_hash}" || {
echo >&2
echo "Cherry-pick failure! Dropping into a recovery shell. Fix conflicts and enter 'exit' to continue." >&2
bash || true
}
# Cherry-pick the remaining current local commits
git cherry-pick "${cur_base_hash}".."${CUR_BRANCH}" || {
echo >&2
echo "Cherry-pick failure! Dropping into a recovery shell. Fix conflicts and enter 'exit' to continue." >&2
bash || true
}
# All done, reset the original branch to the new one
git checkout "${CUR_BRANCH}"
git reset --hard "${TMP_BRANCH}"
git branch -D "${TMP_BRANCH}"
TMP_BRANCH=
fi