chiark / gitweb /
changelog: start 7.1~
[dgit.git] / tests / tartree-edit
1 #!/bin/sh
2 set -e
3 fail () { echo >&2 "$0: $*"; exit 1; }
4
5 play=.git/tartree-edit-work
6
7 git_manip_play () {
8         local wd; wd=$(pwd)
9         case "$wd" in
10         *.edit) fail "bad idea to run gitfetchinfo into a .edit tree!" ;;
11         esac
12         rm -rf $play
13         mkdir $play
14 }
15
16 gitfetchdiff_list () {
17         git for-each-ref --format '%(refname) %(objectname)' \
18                 refs/remotes/"$1" \
19         | sed 's/^refs\/remotes\/[^\/]*\///' \
20         | t-sort >"$play/$2"
21 }
22
23 gitfetchdiff () {
24         local how="$1"
25         local a="$2"
26         local b="$3"
27         git_manip_play
28
29         rrab=refs/remotes/"$a+$b"
30
31         ulf=\
32 "delete refs/remotes/$a/%l
33 delete refs/remotes/$b/%l
34 "
35         case "$how" in
36         diff)
37                 git for-each-ref --format 'delete %(refname)' $rrab \
38                         | git update-ref --stdin
39                 ;;
40         merge)
41                 ulf=\
42 "create $rrab/%l
43 $ulf"
44                 ;;
45         *)
46                 fail "internal error bad how ($how)"
47                 ;;
48         esac
49
50         gitfetchdiff_list "$a" a
51         gitfetchdiff_list "$b" b
52
53         diff --old-line-format='' --new-line-format='' \
54                 --unchanged-line-format="$ulf" \
55                 $play/a $play/b >$play/updates \
56         || test $? = 1
57
58         git update-ref --stdin <$play/updates
59         exit 0
60 }
61
62 case "$#.$1" in
63 2.edit|2.done)  mode="$1"; arg="$2" ;;
64 3.gitfetchinfo) mode="$1"; arg="$2"; remote="$3" ;;
65 3.gitfetchinfo-diff)    gitfetchdiff diff "$2" "$3"     ;;
66 3.gitfetchinfo-merge)   gitfetchdiff merge "$2" "$3"    ;;
67 ?.-*)   fail "no options understood"                    ;;
68 *)      fail "usage:
69     tartree-edit edit|done DIRECTORY|TARBALL
70     tartree-edit gitfetchinfo DIRECTORY|TARBALL REMOTE
71     tartree-edit gitfetchinfo-merge REMOTE-A REMOTE-B"  ;;
72     # we don't document gitfetchinfo-diff because it's rather poor
73 esac
74
75 case "$arg" in
76 *.tar)          base=${arg%.tar}                        ;;
77 *.edit)         base=${arg%.edit}                       ;;
78 *)              base=${arg}                             ;;
79 esac
80
81 tryat_pre () {
82         local b="$1"
83         rm -rf "$b.tmp"
84         if test -f "$b.tar" && test -f "$b.edit"; then
85                 echo "$b.edit exists, deleting possibly-obsolete $b.tar"
86                 rm "$b.tar"
87         fi
88 }
89
90 tryat_edit () {
91         local b="$1"
92         if test -d "$b.edit"; then
93                 echo "$b.edit already exists"
94                 exit 0
95         fi
96         if test -f "$b.tar"; then
97                 mkdir "$b.tmp"
98                 (set -e; cd "$b.tmp"; tar xf "$b.tar")
99                 mv "$b.tmp" "$b.edit"
100                 rm "$b.tar"
101                 echo "$b.edit ready"
102                 exit 0
103         fi
104 }
105
106 gitfetchinfo_perhaps_commit () {
107         local m="$1"
108         set +e
109         git diff --cached --quiet --exit-code HEAD
110         local rc=$?
111         set -e
112         case "$rc" in
113         0)   return ;;
114         1)   git commit --allow-empty --author='tartree-edit <>' -m "$m" ;;
115         *)   fail "git diff failed ($rc)" ;;
116         esac
117 }
118
119 tryat_gitfetchinfo () {
120         git_manip_play
121
122         if test -d "$b.edit"; then
123                 cp -a "$b.edit"/. "$play"/.
124         else
125                 exec 3<"$b.tar"
126                 tar -C $play -f - <&3 -x
127                 exec 3<&-
128         fi
129
130         local innerwd; innerwd="$(echo $play/*)"
131
132         git for-each-ref --format='%(refname)' refs/remotes >$play/l
133         perl -w -ne '
134             our %remerge;
135             use strict;
136             chomp;
137             next unless m#^refs/remotes/([^/]+)/#;
138             my $old = $_;
139             my $ab = $1;
140             my $rhs = $'\'';
141             my @ab = split /\+/, $ab;
142             next unless @ab == 2;
143             next unless (grep { $_ eq "'"$remote"'" } @ab) == 1;
144             $remerge{"@ab"} = 1;
145             print "update refs/remotes/$_/$rhs $old\n" or die $! foreach @ab;
146             print "delete $old\n" or die $!;
147             END {
148                 open REMERGE, ">&3" or die $!;
149                 print REMERGE "$_\n" or die $! foreach sort keys %remerge;
150                 close REMERGE or die $!;
151             }
152         ' <$play/l >$play/unmerge 3>$play/remerge
153         git update-ref --stdin <$play/unmerge
154
155         git remote remove "$remote" 2>/dev/null ||:
156         git remote add "$remote" $innerwd
157         git fetch --no-tags -p "$remote" \
158                 +"HEAD:refs/remotes/$remote/TT-HEAD"
159         cd $innerwd
160         GIT_AUTHOR_DATE=$(git log -n1 --pretty=format:'%ai')
161         GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE
162         export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
163         git checkout -b WORKTREE
164         gitfetchinfo_perhaps_commit 'UNCOMMITTED INDEX'
165         git add -Af .
166         gitfetchinfo_perhaps_commit 'UNCOMMITTED WORKING TREE'
167         cd ../../..
168         git fetch --no-tags "$remote" --refmap \
169                 +"refs/*:refs/remotes/$remote/*" \
170                 +"refs/*:refs/remotes/$remote/*"
171
172         exec 3<$play/remerge
173         # $play will be destroyed by what follows, but we have
174         # an fd open onto remerge, so this will work
175         while read <&3 a b; do
176               echo "Updating gitfetchinfo-merge $a $b"
177               "$0" gitfetchinfo-merge $a $b
178         done
179
180         exit 0
181 }
182
183 tryat_done () {
184         local b="$1"
185         if test -d "$b.edit"; then
186                 (set -e; cd "$b.edit"; tar cf "$b.tmp" *)
187                 mv "$b.tmp" "$b.tar"
188                 mv "$b.edit" "$b.tmp"
189                 rm -rf "$b.tmp"
190                 echo "$b.tar regenerated"
191                 exit 0
192         fi
193         if test -f "$b.tar"; then
194                 echo "$b.tar already exists and $b.edit doesn't"
195                 exit 0
196         fi
197 }
198
199 tryat () {
200         local b="$1"
201         if ! test -f "$b.tar" && ! test -d "$b.edit"; then
202                 return
203         fi
204         tryat_pre "$b"
205         tryat_$mode "$b"
206         fail "unexpected situation in $b.*"
207 }
208
209 case "$arg" in
210 /*)             tryat "$base"
211                 ;;
212 *)
213                 pwd=`pwd`
214                 tryat "$pwd/$base"
215                 tryat "$pwd/git-srcs/$base"
216                 tryat "$pwd/tests/git-srcs/$base"
217                 fail "could not find $base..."
218                 ;;
219 esac