admin-merge-2 attempt
[xonotic/xonotic.git] / all
1 #!/bin/sh
2 # vim: filetype=zsh
3
4 set -e
5
6 d00=`pwd`
7 while ! [ -f ./all ]; do
8         if [ x"`pwd`" = x"/" ]; then
9                 echo "Cannot find myself."
10                 echo "Please run this script with the working directory inside a Xonotic checkout."
11                 exit 1
12         fi
13         cd ..
14 done
15 d0=`pwd`
16 SELF="$d0/all"
17
18 # If we are on WINDOWS:
19 case "$0" in
20         all|*/all)
21                 case "`uname`" in
22                         MINGW*|Win*)
23                                 # Windows hates users. So this script has to copy itself elsewhere first...
24                                 tname=
25                                 cp "$SELF" ../all.xonotic.sh
26                                 export WE_HATE_OUR_USERS=1
27                                 exec ../all.xonotic.sh "$@"
28                                 ;;
29                 esac
30                 ;;
31 esac
32
33 msg()
34 {
35         echo "\e[1m$*\e[m"
36 }
37
38 checksum()
39 {
40         if [ -x /usr/bin/md5sum ]; then
41                 /usr/bin/md5sum "$@"
42         elif [ -x /bin/md5sum ]; then
43                 /bin/md5sum "$@"
44         elif [ -x /usr/bin/cksum ]; then
45                 /usr/bin/cksum "$@"
46         else
47                 echo "NOCHECKSUM"
48         fi
49 }
50
51 self=`checksum "$SELF"`
52 checkself()
53 {
54         self_new=`checksum "$SELF"`
55         if [ x"$self" != x"$self_new" ]; then
56                 msg "./all has changed."
57                 if [ -z "$XONOTIC_FORBID_RERUN_ALL" ]; then
58                         msg "Rerunning the requested operation to make sure."
59                         export XONOTIC_FORBID_RERUN_ALL=1
60                         exec "$SELF" "$@"
61                 else
62                         msg "Please try $SELF update, and then retry your requested operation."
63                         exit 1
64                 fi
65         fi
66         return 0
67 }
68
69 verbose()
70 {
71         msg "+ $*"
72         "$@"
73 }
74
75 visible_repo_name()
76 {
77         case "$1" in
78                 .)
79                         echo "the root directory"
80                         ;;
81                 *)
82                         echo "\"$1\""
83                         ;;
84         esac
85 }
86
87 check_mergeconflict()
88 {
89         if git ls-files -u | grep ' 1   '; then
90                 echo
91                 echo "MERGE CONFLICT."
92                 echo "change into the \"$1\" project directory, and then:"
93                 echo "- edit the files mentioned above with your favorite editor,"
94                 echo "  and fix the conflicts (marked with <<<<<<< blocks)"
95                 echo "- for binary files, you can select the files using"
96                 echo "  git checkout --ours or git checkout --theirs"
97                 echo "- when done with a file, 'git add' the file"
98                 echo "- when done, 'git commit'"
99                 echo
100                 exit 1
101         fi
102 }
103
104 yesno()
105 {
106         yesno=
107         while [ x"$yesno" != x"y" -a x"$yesno" != x"n" ]; do
108                 echo "$1"
109                 IFS= read -r yesno
110         done
111         [ x"$yesno" = x"y" ]
112 }
113
114 enter()
115 {
116         $2 cd "$1"
117         check_mergeconflict "$1"
118 }
119
120 repos_urls="
121 .                             |                                                   | master
122 data/xonotic-data.pk3dir      |                                                   | master
123 data/xonotic-maps.pk3dir      |                                                   | master
124 data/xonotic-music.pk3dir     |                                                   | master
125 data/xonotic-nexcompat.pk3dir |                                                   | master
126 mediasource                   |                                                   | master
127 darkplaces                    |                                                   | div0-stable
128 fteqcc                        | git://github.com/Blub/qclib.git                   | master
129 div0-gittools                 | git://git.icculus.org/divverent/div0-gittools.git | master
130 netradiant                    |                                                   | master
131 "
132 # todo: in darkplaces, change repobranch to div0-stable
133
134 repos=`echo "$repos_urls" | grep . | cut -d '|' -f 1 | tr -d ' '`
135
136 base=`git config remote.origin.url`
137 base=${base%xonotic.git}
138
139 repourl()
140 {
141         t=`echo "$repos_urls" | grep "^$1 " | cut -d '|' -f 2 | tr -d ' '`
142         if [ -n "$t" ]; then
143                 case "$t" in
144                         *://*)
145                                 echo "$t"
146                                 ;;
147                         *)
148                                 echo "$base$t"
149                                 ;;
150                 esac
151         else
152                 if [ x"$1" = x"." ]; then
153                         echo "$base""xonotic.git"
154                 else
155                         echo "$base${1##*/}.git"
156                 fi
157         fi
158 }
159
160 repobranch()
161 {
162         t=`echo "$repos_urls" | grep "^$1 " | cut -d '|' -f 3 | tr -d ' '`
163         if [ -n "$t" ]; then
164                 echo "$t"
165         else
166                 echo "master"
167         fi
168 }
169
170 repos=`for d in $repos; do
171         p="${d%dir}"
172         if [ x"$p" = x"$d" ] || [ -d "$d" ] || ! [ -f "$p" ]; then
173                 echo "$d"
174         fi
175 done`
176
177 if [ "$#" = 0 ]; then
178         set -- help
179 fi
180 cmd=$1
181 shift
182
183 case "$cmd" in
184         update|pull)
185                 allow_pull=true
186                 if [ x"$1" = x"-N" ]; then
187                         allow_pull=false
188                 fi
189                 for d in $repos; do
190                         url=`repourl "$d"`
191                         branch=`repobranch "$d"`
192                         if [ -d "$d0/$d" ]; then
193                                 if $allow_pull; then
194                                         enter "$d0/$d" verbose
195                                         verbose git config remote.origin.url "$url"
196                                         verbose git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
197                                                 # TODO remove this line later
198
199                                         verbose git config core.autocrlf false
200                                         verbose git config core.safecrlf false # we don't NEED that...
201
202                                         r=`git symbolic-ref HEAD`
203                                         r=${r#refs/heads/}
204                                         if git config branch.$r.remote >/dev/null 2>&1; then
205                                                 if ! verbose git pull; then
206                                                         check_mergeconflict "$d"
207                                                         echo "Pulling failed. Press ENTER to continue, or Ctrl-C to abort."
208                                                         read -r DUMMY
209                                                 fi
210                                         fi
211
212                                         cd "$d00"
213                                         checkself "$cmd" "$@"
214                                         cd "$d0/$d"
215                                         verbose git remote prune origin
216                                         cd "$d0"
217                                 fi
218                         else
219                                 verbose git clone "$url" "$d0/$d"
220                                 enter "$d0/$d" verbose
221                                 verbose git checkout "$branch"
222                                 cd "$d0"
223                         fi
224                 done
225                 ;;
226         checkout|switch)
227                 remote=$1
228                 branch=$2
229                 if [ -z "$branch" ]; then
230                         branch=$remote
231                         remote=origin
232                 fi
233                 exists=false
234                 for d in $repos; do
235                         enter "$d0/$d" verbose
236                         if git rev-parse "refs/heads/$branch" >/dev/null 2>&1; then
237                                 exists=true
238                                 verbose git checkout "$branch"
239                         elif git rev-parse "refs/remotes/$remote/$branch" >/dev/null 2>&1; then
240                                 exists=true
241                                 verbose git checkout --track -b "$branch" "$remote/$branch"
242                         else
243                                 verbose git checkout "`repobranch "$d"`"
244                         fi
245                         cd "$d00"
246                         checkself "$cmd" "$@"
247                         cd "$d0"
248                 done
249                 if ! $exists; then
250                         echo "The requested branch was not found in any repository."
251                 fi
252                 exec "$SELF" branch
253                 ;;
254         branch)
255                 remote=$1
256                 branch=$2
257                 srcbranch=$3
258                 if [ -z "$branch" ]; then
259                         branch=$remote
260                         remote=origin
261                 fi
262                 if [ -z "$branch" ]; then
263                         for d in $repos; do
264                                 enter "$d0/$d"
265                                 r=`git symbolic-ref HEAD`
266                                 r=${r#refs/heads/}
267                                 echo "$d is at $r"
268                                 cd "$d0"
269                         done
270                 else
271                         for d in $repos; do
272                                 dv=`visible_repo_name "$d"`
273                                 enter "$d0/$d" verbose
274                                 if git rev-parse "refs/heads/$branch" >/dev/null 2>&1; then
275                                         echo "Already having this branch in $dv."
276                                 else
277                                         if yesno "Branch in $dv?"; then
278                                                 if [ -n "$srcbranch" ]; then
279                                                         b=$srcbranch
280                                                 else
281                                                         b="`repobranch "$d"`"
282                                                 fi
283                                                 # TODO do this without pushing
284                                                 verbose git push "$remote" "$b":"$branch"
285                                                 verbose git checkout --track -b "$branch" "$remote/$branch"
286                                         fi
287                                 fi
288                                 cd "$d0"
289                         done
290                         "$SELF" branch
291                 fi
292                 ;;
293         branches)
294                 for d in $repos; do
295                         enter "$d0/$d"
296                         echo "In $d:"
297                         git branch -a -v -v | cut -c 3- | while read -r BRANCH REV UPSTREAM TEXT; do
298                                 case "$UPSTREAM" in
299                                         \[*)
300                                                 UPSTREAM=${UPSTREAM#\[}
301                                                 UPSTREAM=${UPSTREAM%\]}
302                                                 UPSTREAM=${UPSTREAM%:*}
303                                                 ;;
304                                         *)
305                                                 TEXT="$UPSTREAM $TEXT"
306                                                 UPSTREAM=
307                                                 ;;
308                                 esac
309                                 if [ x"$REV" = x"->" ]; then
310                                         continue
311                                 fi
312                                 BRANCH=${BRANCH#remotes/}
313                                 echo -n "  $BRANCH"
314                                 if [ -n "$UPSTREAM" ]; then
315                                         echo -n " (tracking $UPSTREAM)"
316                                 fi
317                                 #echo " $TEXT"
318                                 echo
319                         done
320                 done
321                 ;;
322         branches_short)
323                 for d in $repos; do
324                         cd "$d0/$d" # am in a pipe, shouldn't use enter
325                         git branch -a -v -v | cut -c 3- | sed "s,^,$d ,"
326                         cd "$d0"
327                 done | {
328                         branches_list=
329                         # branches_repos_*=
330                         while read -r d BRANCH REV UPSTREAM TEXT; do
331                                 case "$UPSTREAM" in
332                                         \[*)
333                                                 UPSTREAM=${UPSTREAM#\[}
334                                                 UPSTREAM=${UPSTREAM%\]}
335                                                 UPSTREAM=${UPSTREAM%:*}
336                                                 ;;
337                                         *)
338                                                 TEXT="$UPSTREAM $TEXT"
339                                                 UPSTREAM=
340                                                 ;;
341                                 esac
342                                 if [ x"$REV" = x"->" ]; then
343                                         continue
344                                 fi
345                                 BRANCH=${BRANCH#remotes/}
346                                 ID=`echo "$BRANCH" | tr -c "A-Za-z0-9." "_"`
347                                 branches_list="$branches_list $BRANCH" # TEH SORT MAKEZ IT UNIEQ
348                                 eval "r=\$branches_repos_$ID"
349                                 r="$r $d:$UPSTREAM"
350                                 eval "branches_repos_$ID=\$r"
351                         done
352                         echo -n "$branches_list" | xargs -n 1 echo | sort -u | while IFS= read -r BRANCH; do
353                                 ID=`echo "$BRANCH" | tr -c "A-Za-z0-9." "_"`
354                                 eval "r=\$branches_repos_$ID"
355                                 echo "$BRANCH: $r"
356                         done
357                 }
358                 ;;
359         merge)
360                 for d in $repos; do
361                         dv=`visible_repo_name "$d"`
362                         enter "$d0/$d" verbose
363                         r=`git symbolic-ref HEAD`
364                         r=${r#refs/heads/}
365                         if git log HEAD..origin/"`repobranch "$d"`" | grep .; then
366                                 # we have uncommitted changes
367                                 if yesno "Could merge from \"`repobranch "$d"`\" into \"$r\" in $dv. Do it?"; then
368                                         if ! verbose git merge origin/"`repobranch "$d"`"; then
369                                                 check_mergeconflict "$d"
370                                                 exit 1 # this should ALWAYS be fatal
371                                         fi
372                                 fi
373                         fi
374                         cd "$d0"
375                 done
376                 ;;
377         push|commit)
378                 submit=$1
379                 for d in $repos; do
380                         dv=`visible_repo_name "$d"`
381                         enter "$d0/$d" verbose
382                         r=`git symbolic-ref HEAD`
383                         r=${r#refs/heads/}
384                         if git diff HEAD | grep .; then
385                                 # we have uncommitted changes
386                                 if yesno "Uncommitted changes in \"$r\" in $dv. Commit?"; then
387                                         verbose git commit -a
388                                 fi
389                         fi
390                         rem=`git config "branch.$r.remote" || echo origin`
391                         if { git log "$rem/$r".."$r" || git log origin/"`repobranch "$d"`".."$r"; } | grep .; then
392                                 if yesno "Push \"$r\" in $dv?"; then
393                                         verbose git push "$rem" HEAD
394                                 fi
395                         fi
396                         if [ x"$submit" = x"-s" ]; then
397                                 case "$r" in
398                                         */*)
399                                                 verbose git push "$rem" HEAD:"${r%%/*}/finished/${r#*/}"
400                                                 ;;
401                                 esac
402                         fi
403                         cd "$d0"
404                 done
405                 ;;
406         compile)
407                 if [ -n "$WE_HATE_OUR_USERS" ]; then
408                         TARGETS="sv-debug cl-debug"
409                 else
410                         TARGETS="sv-debug cl-debug sdl-debug"
411                 fi
412                 case "$1" in
413                         -c)
414                                 clean=true
415                                 shift
416                                 ;;
417                         *)
418                                 clean=false
419                                 ;;
420                 esac
421                 case "$1" in
422                         sdl)
423                                 TARGETS="sdl-debug"
424                                 shift
425                                 ;;
426                         glx|agl|wgl)
427                                 TARGETS="cl-debug"
428                                 shift
429                                 ;;
430                         dedicated)
431                                 TARGETS="sv-debug"
432                                 shift
433                                 ;;
434                 esac
435                 if [ -z "$MAKEFLAGS" ]; then
436                         if [ -f /proc/cpuinfo ]; then
437                                 ncpus=$((`grep -c '^processor   :' /proc/cpuinfo`+0))
438                                 if [ $ncpus -gt 1 ]; then
439                                         MAKEFLAGS=-j$ncpus
440                                 fi
441                         fi
442                         case "`uname`" in
443                                 Linux|*BSD)
444                                         MAKEFLAGS="$MAKEFLAGS DP_LINK_TO_LIBJPEG=1"
445                                         ;;
446                         esac
447                         if [ -n "$WE_HATE_OUR_USERS" ]; then
448                                 MAKEFLAGS="$MAKEFLAGS DP_MAKE_TARGET=mingw"
449                         fi
450                 fi
451                 enter "$d0/fteqcc" verbose
452                 if $clean; then
453                         verbose make $MAKEFLAGS clean
454                 fi
455                 verbose make $MAKEFLAGS
456                 enter "$d0/data/xonotic-data.pk3dir" verbose
457                 if $clean; then
458                         verbose make $MAKEFLAGS clean
459                 fi
460                 verbose make FTEQCC="$d0/fteqcc/fteqcc.bin" "$@" $MAKEFLAGS
461                 enter "$d0/darkplaces" verbose
462                 if $clean; then
463                         verbose make $MAKEFLAGS clean
464                 fi
465                 for T in $TARGETS; do
466                         verbose make $MAKEFLAGS "$@" "$T"
467                 done
468                 ;;
469         run)
470                 if [ -n "$WE_HATE_OUR_USERS" ]; then
471                         client=
472                         export PATH="$d0/misc/buildfiles/w32:$PATH"
473                 elif [ x"`uname`" = x"Darwin" ]; then
474                         export DYLD_LIBRARY_PATH="$d0/misc/buildfiles/osx/Nexuiz.app/Contents/MacOS"
475                         client=-sdl
476                 else
477                         client=-sdl
478                 fi
479                 case "$1" in
480                         sdl|glx|agl|dedicated)
481                                 client=-$1
482                                 shift
483                                 ;;
484                         wgl)
485                                 client=
486                                 shift
487                                 ;;
488                 esac
489                 if ! [ -x "darkplaces/darkplaces$client" ]; then
490                         if [ -x "darkplaces/darkplaces$client.exe" ]; then
491                                 client=$client.exe
492                         else
493                                 echo "Client darkplaces/darkplaces$client not found, aborting"
494                                 exit 1
495                         fi
496                 fi
497                 set -- "darkplaces/darkplaces$client" -nexuiz -customgamename Xonotic -customgamedirname1 data -customgamedirname2 "" -customgamescreenshotname xonotic -customgameuserdirname xonotic "$@"
498                 if [ -n "$USE_GDB" ]; then
499                         set -- gdb --args "$@"
500                 fi
501                 "$@"
502                 ;;
503         each|foreach)
504                 for d in $repos; do
505                         if verbose cd "$d0/$d"; then
506                                 verbose "$@"
507                                 cd "$d0"
508                         fi
509                 done
510                 ;;
511         save-patches)
512                 outfile=$1
513                 patchdir=`mktemp -d -t save-patches.XXXXXX`
514                 for d in $repos; do
515                         enter "$d0/$d" verbose
516                         git branch -v -v | cut -c 3- | {
517                                 i=0
518                                 while read -r BRANCH REV UPSTREAM TEXT; do
519                                         case "$UPSTREAM" in
520                                                 \[*)
521                                                         UPSTREAM=${UPSTREAM#\[}
522                                                         UPSTREAM=${UPSTREAM%\]}
523                                                         UPSTREAM=${UPSTREAM%:*}
524                                                         TRACK=true
525                                                         ;;
526                                                 *)
527                                                         UPSTREAM=origin/"`repobranch "$d"`"
528                                                         TRACK=false
529                                                         ;;
530                                         esac
531                                         if [ x"$REV" = x"->" ]; then
532                                                 continue
533                                         fi
534                                         if git format-patch -o "$patchdir/$i" "$UPSTREAM".."$BRANCH"; then
535                                                 echo "$d" > "$patchdir/$i/info.txt"
536                                                 echo "$BRANCH" >> "$patchdir/$i/info.txt"
537                                                 echo "$UPSTREAM" >> "$patchdir/$i/info.txt"
538                                                 echo "$TRACK" >> "$patchdir/$i/info.txt"
539                                                 i=$(($i+1))
540                                         else
541                                                 rm -rf "$patchdir/$i"
542                                         fi
543                                 done
544                         }
545                 done
546                 ( cd "$patchdir" && tar cvzf - . ) > "$outfile"
547                 rm -rf "$patchdir"
548                 ;;
549         restore-patches)
550                 infile=$1
551                 patchdir=`mktemp -d -t restore-patches.XXXXXX`
552                 ( cd "$patchdir" && tar xvzf - ) < "$infile"
553                 # detach the head
554                 for P in "$patchdir"/*/info.txt; do
555                         D=${P%/info.txt}
556                         exec 3<"$P"
557                         read -r d <&3
558                         read -r BRANCH <&3
559                         read -r UPSTREAM <&3
560                         read -r TRACK <&3
561                         verbose git checkout HEAD^0
562                         verbose git branch -D "$BRANCH"
563                         if [ x"$TRACK" = x"true" ]; then
564                                 verbose git checkout --track -b "$BRANCH" "$UPSTREAM"
565                         else
566                                 verbose git branch -b "$BRANCH" "$UPSTREAM"
567                         fi
568                         verbose git am "$D"
569                 done
570                 rm -rf "$patchdir"
571                 ;;
572         admin-merge)
573                 if [ "$#" = 1 ]; then
574                         set -- "${1%%/*}" "${1#*/}"
575                 fi
576                 for d in $repos; do
577                         enter "$d0/$d" verbose
578                         git rev-parse "$1/$2" || continue
579                         # 1. review
580                         {
581                                 git log HEAD.."$1/$2"
582                                 git diff HEAD..."$1/$2"
583                         } | less
584                         if yesno "Merge \"$1/$2\" into `git symbolic-ref HEAD` of $d?"; then
585                                 git merge "$1/$2"
586                                 if "$SELF" compile && yesno "Still merge \"$1/$2\" into `git symbolic-ref HEAD` of $d? Maybe you want to test first."; then
587                                         git push origin HEAD
588                                         git push "$1" :"$2"
589                                 else
590                                         git reset --hard HEAD@{1}
591                                 fi
592                         fi
593                 done
594                 ;;
595         admin-merge-2)
596                 t=`mktemp`
597                 for d in $repos; do
598                         enter "$d0/$d" verbose
599                         for ref in `git for-each-ref --format='%(refname)' refs/remotes/origin/`; do
600                                 case "${ref#refs/remotes/origin/}" in
601                                         "`repobranch "$d"`")
602                                                 continue
603                                                 ;;
604                                         HEAD|master)
605                                                 continue
606                                                 ;;
607                                 esac
608                                 echo "$ref"
609                                 if git notes --ref "refs/notes/admin-merge" show "$ref" 2>/dev/null; then
610                                         echo "Not merging, already had this one"
611                                 elif yesno "Branch \"$ref\" may want to get merged. Do it?" '{ git log HEAD.."$ref"; git diff HEAD.."$ref"; } | less'; then
612                                         org=`git rev-parse HEAD`
613                                         if ! git merge "$ref" 2>&1 | tee "$t"; then
614                                                 git reset --hard "$org"
615                                                 git notes --ref "refs/notes/admin-merge" add -m "Merge failed:
616 `cat "$t"`" "$ref"
617                                         elif ! "$SELF" compile 2>&1 | tee "$t"; then
618                                                 git reset --hard "$org"
619                                                 git notes --ref "refs/notes/admin-merge" add -m "Compile failed:
620 `cat "$t"`" "$ref"
621                                         elif ! yesno "Still merge \"$ref\" into `git symbolic-ref HEAD` of $d? Maybe you want to test first."; then
622                                                 git reset --hard HEAD@{1}
623                                                 git notes --ref "refs/notes/admin-merge" add "$ref"
624                                         else
625                                                 git push origin HEAD
626                                                 git push origin :"${ref#refs/remotes/origin/}"
627                                         fi
628                                 else
629                                         git reset --hard HEAD@{1}
630                                         git notes --ref "refs/notes/admin-merge" add "$ref"
631                                 fi
632                         done
633                 done
634                 rm -f "$t"
635                 ;;
636         *)
637                 echo "Usage:"
638                 echo "  $SELF pull"
639                 echo "  $SELF merge"
640                 echo "  $SELF push [-s]"
641                 echo "  $SELF branches"
642                 echo "  $SELF branch [<remote>] <branchname>"
643                 echo "  $SELF branch <remote> <branchname> <srcbranchname>"
644                 echo "  $SELF checkout [<remote>] <branchname>"
645                 echo "  $SELF compile [-c] [<client>] <options>"
646                 echo "  $SELF run [<client>] <options>"
647                 echo "  $SELF each <command>"
648                 ;;
649 esac