]> git.wh0rd.org - home.git/blob - .bin/r
repo: make `repo` search more flexible
[home.git] / .bin / r
1 #!/bin/bash
2 g() { git "$@"; }
3 err() { printf '%b\n' "$*" 1>&2; exit 1; }
4 vr() { echo "$@"; "$@"; }
5
6 case $1 in
7 -x) set -x; shift;;
8 esac
9
10 case $1 in
11 ""|-*) ;;
12 l)
13 cmd=list
14 shift
15 ;;
16 s)
17 cmd=sync
18 shift
19 ;;
20 *)
21 cmd=$1
22 shift
23 acmd=$(git config --get "alias.${cmd}" | sed 's: -.*::')
24 ;;
25 esac
26
27 mj_init() {
28 pipe=$(mktemp)
29 rm -f "${pipe}"
30 mkfifo "${pipe}"
31 exec {ctlfd}<>"${pipe}"
32 rm -f "${pipe}"
33 jobs=0
34 jobs_max=${1:-$(getconf _NPROCESSORS_ONLN)}
35 }
36 _mj_child() { echo ${BASHPID} $? >&${ctlfd} ; }
37 mj_child() {
38 (
39 "$@"
40 _mj_child
41 ) &
42 mj_post_child
43 }
44 mj_post_child() {
45 : $(( ++jobs ))
46 if [[ ${jobs} -eq ${jobs_max} ]] ; then
47 read -r -u ${ctlfd} pid ret
48 : $(( --jobs ))
49 fi
50 }
51 mj_finish() {
52 wait
53 }
54
55 repo_root() {
56 local root=${PWD}
57 while [[ ! -d ${root}/.repo && ${root} != "/" ]] ; do
58 root=${root%/*}
59 done
60 echo "${root}"
61 }
62
63 process_reviewers() {
64 local r arr=()
65 for r in ${*//,/ } ; do
66 case ${r} in
67 *OWNERS)
68 local owners=$(
69 awk -F'@' '
70 ($2 == "chromium.org" || $2 == "google.com") {list = list "," $1}
71 END {print substr(list, 2)}
72 ' "${r}"
73 )
74 if [[ -z ${owners} ]] ; then
75 err "cannot find OWNERS list"
76 else
77 echo "Auto setting reviewers to: ${owners}"
78 fi
79 arr+=( ${owners} )
80 ;;
81 *)
82 arr+=( "${r}" )
83 ;;
84 esac
85 done
86 reviewers=$(printf '%s,' "${arr[@]}")
87 reviewers=${reviewers%,}
88 }
89
90 find_repo() {
91 # Diff projects have diff versions of repo. Find a compatible one.
92 local root=$(repo_root)
93
94 # Use the manifest repo URL.
95 local manifest_dir="${root}/.repo/manifests.git"
96 local d
97
98 # Default to the local repo if it's there.
99 local search=(
100 "${root}/.repo/repo"
101 )
102
103 case $(g --git-dir="${manifest_dir}" config remote.origin.url) in
104 *android*)
105 search+=(
106 /usr/local/src/repo
107 ~/src/repo
108 )
109 ;;
110 *chromium*|*chrome*)
111 search+=(
112 ~/depot_tools
113 ~/chromiumos/depot_tools
114 /usr/local/src/depot_tools
115 ~/src/depot_tools
116 )
117 ;;
118 esac
119 for d in "${search[@]}" ; do
120 if [[ -x ${d}/repo ]] ; then
121 echo "${d}"/repo
122 return
123 fi
124 done
125
126 # Fallback: use $PATH.
127 type -P repo
128 }
129
130 case ${acmd:-${cmd}} in
131 rebase)
132 if [[ $1 == "all" ]] ; then
133 shift
134 if [[ $# -eq 0 ]] ; then
135 eval $(bash-colors --env | sed 's:^:export :')
136 root=$(repo_root)
137 mj_init
138 while read -a line ; do
139 dir=${line[0]}
140 proj=${line[2]}
141 if ! cd "${root}/${dir}" ; then
142 echo "bad ${proj}"
143 continue
144 fi
145 (
146 out=$(env _proj=${proj} r rb all . 2>&1)
147 if [[ -n ${out} ]] ; then
148 while read line ; do
149 if [[ ${line} == "# "* ]] ; then
150 line="${line#[#] }"
151 printf '%s### %s%-40s%s: %s\n' \
152 "${BRACKET}" "${GOOD}" "${line%%:*}" "${NORMAL}" "${line#*:}"
153 else
154 printf '%s### %s%-40s%s: ERROR: %s\n' \
155 "${BRACKET}" "${BAD}" "${dir}" "${NORMAL}" "${line}"
156 fi
157 done < <(echo "${out}")
158 fi
159 _mj_child
160 ) &
161 mj_post_child
162 done < <(r l)
163 mj_finish
164 exit 0
165 #exec r forall -p -c 'r rb all .' </dev/null
166 fi
167
168 branches=$(g b | awk '
169 {
170 if ($0 ~ "^[*] *[(]no branch[)]") {
171 next
172 } else if ($0 ~ "^[*] *[(](HEAD )?detached (from|at) ") {
173 next
174 } else if ($1 == "*") {
175 b = $2
176 } else {
177 list = list $1 " "
178 }
179 }
180 END { print list b }')
181 [[ -z ${branches} ]] && exit 0
182
183 [[ -z ${GOOD} ]] && eval $(bash-colors --env)
184 #echo "${GOOD}### ${PWD}${NORMAL}"
185 # Skip if rebase is in progress.
186 if [[ -e .git/rebase-merge/interactive ]] ; then
187 echo -e "# ${_proj}: ${WARN}skipping due to active rebase${NORMAL}"
188 exit 1
189 fi
190 for b in ${branches} ; do
191 #echo " ${HILITE}### $b${NORMAL}"
192 g co -q $b || exit 1
193 if ! r rb -q "$@" ; then
194 g rb-a
195 fi
196 done
197 exit 0
198 fi
199 ;;
200 clean)
201 root=$(repo_root)
202 cd "${root}" || exit 1
203 mj_init
204 while read -a line ; do
205 dir=${line[0]}
206 proj=${line[2]}
207 cd "${root}/${dir}"
208 (
209 out=$(g clean "$@" 2>&1)
210 if [[ -n ${out} ]] ; then
211 echo "### ${proj}"
212 echo "${out}"
213 fi
214 _mj_child
215 ) &
216 mj_post_child
217 done < <(r l)
218 mj_finish
219 exit
220 ;;
221 sb)
222 sb_cmd=$1
223 case ${sb_cmd} in
224 pull) ;;
225 push) ;;
226 f|fetch) sb_cmd="fetch" ;;
227 *) err "unknown sandbox command: $1"
228 esac
229
230 sync_branch="v"
231
232 root=$(repo_root)
233 cd "${root}" || exit 1
234
235 if [[ ! -e .repo/sandbox-url ]] ; then
236 err "Please configure remote url base in ${root}/.repo/sandbox-url"
237 fi
238 remote=$(<.repo/sandbox-url) || exit 1
239
240 echo "pushing projects from ${root}"
241
242 # ssh servers do not like it when you hammer them :)
243 # Received disconnect from 74.125.248.80: 7: Too many concurrent connections
244 # fatal: The remote end hung up unexpectedly
245 mj_init 16
246
247 rlist=$(r l)
248 tcnt=$(echo "${rlist}" | wc -l)
249 cnt=1
250 while read line ; do
251 line=( ${line} )
252 path=${line[0]}
253 export GIT_DIR=${path}/.git
254 proj=${line[2]}
255 printf '### (%*i/%i %3i%%) %s\n' \
256 ${#tcnt} $((cnt++)) ${tcnt} $(( cnt * 100 / tcnt )) ${proj}
257 src="${sync_branch}"
258 case ${sb_cmd} in
259 push)
260 g l -1 ${src} >& /dev/null || src=
261 mj_child g push --force ${remote}/${proj} ${src}:refs/sandbox/${USER}/${sync_branch} >/dev/null
262 ;;
263 pull)
264 ;;
265 fetch)
266 mj_child g fetch ${remote}/${proj} refs/sandbox/${USER}/${sync_branch}:refs/remotes/sb/${sync_branch} >/dev/null
267 ;;
268 esac
269 done < <(echo "${rlist}")
270 mj_finish
271
272 exit 0
273 ;;
274 g-push)
275 # For the times when repo is being stupid, push directly to gerrit myself.
276 if ! branch=$(g symbolic-ref -q HEAD) ; then
277 err "could not figure out active branch"
278 fi
279 branch=${branch#refs/heads/}
280 if ! remote_branch=$(g cfg --get "branch.${branch}.merge") ; then
281 echo "could not figure out remote branch; using ${branch}"
282 remote_branch=${branch}
283 fi
284 if ! remote=$(g cfg --get "branch.${branch}.remote") ; then
285 for remote in cros-internal cros origin ; do
286 g cfg --get "remote.${remote}.url" >/dev/null && break
287 done
288 fi
289 review=$(g cfg --get "remote.${remote}.review")
290 remote_branch=${remote_branch#refs/heads/}
291
292 git_args=()
293 reviewers=""
294 while [[ $# -gt 0 ]] ; do
295 case $1 in
296 --re)
297 process_reviewers "$2"
298 shift
299 ;;
300 -n|--dry-run|--draft)
301 git_args+=( $1 )
302 ;;
303 *)
304 err "unknown option: $1"
305 ;;
306 esac
307 shift
308 done
309
310 ref_spec="${branch}:refs/for/${remote_branch}"
311 if [[ -n ${reviewers} ]] ; then
312 reviewers=( ${reviewers//,/ } )
313 if [[ ${review} != ssh://* ]] ; then
314 gob_args=$(printf 'r=%s,' "${reviewers[@]}")
315 ref_spec+="%${gob_args%,}"
316 else
317 git_args+=( "--receive-pack=git receive-pack ${reviewers[*]/#/--reviewer=}" )
318 fi
319 fi
320
321 vr git push "${git_args[@]}" ${remote} ${ref_spec} && exit
322 err "could not figure out remote to push to"
323 ;;
324 sync)
325 set -- -j16 -c "$@"
326 ;;
327 upload)
328 args=()
329 while [[ $# -gt 0 ]] ; do
330 case $1 in
331 --re)
332 process_reviewers "$2"
333 args+=( --re "${reviewers}" )
334 shift 2
335 continue
336 ;;
337 esac
338 args+=( "$1" )
339 shift
340 done
341 set -- "${args[@]}"
342 ;;
343 email)
344 email=${1:-${USER}@chromium.org}
345
346 root=$(repo_root)
347 git --git-dir="${root}/.repo/manifests.git" cfg user.email "${email}"
348 git --git-dir="${root}/.repo/repo/.git" cfg user.email "${email}"
349
350 cmd='forall'
351 set -- -c "git cfg user.email '${email}'"
352 ;;
353 esac
354
355 exec python2 $(find_repo) ${acmd:-${cmd}} "$@"