Skip to content

Commit 766f0f8

Browse files
committed
Merge branch 'fc/transport-helper-error-reporting'
Update transport helper to report errors and maintain ref hierarchy used to keep track of remote helper state better. * fc/transport-helper-error-reporting: transport-helper: fix remote helper namespace regression test: remote-helper: add missing and t5801: "VAR=VAL shell_func args" is forbidden transport-helper: update remote helper namespace transport-helper: trivial code shuffle transport-helper: warn when refspec is not used transport-helper: clarify pushing without refspecs transport-helper: update refspec documentation transport-helper: clarify *:* refspec transport-helper: improve push messages transport-helper: mention helper name when it dies transport-helper: report errors properly
2 parents edca415 + 126aac5 commit 766f0f8

File tree

4 files changed

+118
-43
lines changed

4 files changed

+118
-43
lines changed

Documentation/gitremote-helpers.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,11 @@ Miscellaneous capabilities
159159
carried out.
160160

161161
'refspec' <refspec>::
162-
This modifies the 'import' capability, allowing the produced
163-
fast-import stream to modify refs in a private namespace
164-
instead of writing to refs/heads or refs/remotes directly.
162+
For remote helpers that implement 'import' or 'export', this capability
163+
allows the refs to be constrained to a private namespace, instead of
164+
writing to refs/heads or refs/remotes directly.
165165
It is recommended that all importers providing the 'import'
166-
capability use this.
166+
capability use this. It's mandatory for 'export'.
167167
+
168168
A helper advertising the capability
169169
`refspec refs/heads/*:refs/svn/origin/branches/*`
@@ -174,8 +174,8 @@ ref.
174174
This capability can be advertised multiple times. The first
175175
applicable refspec takes precedence. The left-hand of refspecs
176176
advertised with this capability must cover all refs reported by
177-
the list command. If a helper does not need a specific 'refspec'
178-
capability then it should advertise `refspec *:*`.
177+
the list command. If no 'refspec' capability is advertised,
178+
there is an implied `refspec *:*`.
179179

180180
'bidi-import'::
181181
This modifies the 'import' capability.

git-remote-testgit

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,31 @@ do
6262
echo "feature import-marks=$gitmarks"
6363
echo "feature export-marks=$gitmarks"
6464
fi
65+
66+
if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
67+
then
68+
echo "feature done"
69+
exit 1
70+
fi
71+
6572
echo "feature done"
6673
git fast-export "${testgitmarks_args[@]}" $refs |
6774
sed -e "s#refs/heads/#${prefix}/heads/#g"
6875
echo "done"
6976
;;
7077
export)
78+
if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
79+
then
80+
# consume input so fast-export doesn't get SIGPIPE;
81+
# git would also notice that case, but we want
82+
# to make sure we are exercising the later
83+
# error checks
84+
while read line; do
85+
test "done" = "$line" && break
86+
done
87+
exit 1
88+
fi
89+
7190
before=$(git for-each-ref --format='%(refname) %(objectname)')
7291

7392
git fast-import "${testgitmarks_args[@]}" --quiet
@@ -79,7 +98,12 @@ do
7998
while read ref a b
8099
do
81100
test $a == $b && continue
82-
echo "ok $ref"
101+
if test -z "$GIT_REMOTE_TESTGIT_PUSH_ERROR"
102+
then
103+
echo "ok $ref"
104+
else
105+
echo "error $ref $GIT_REMOTE_TESTGIT_PUSH_ERROR"
106+
fi
83107
done
84108

85109
echo

t/t5801-remote-helpers.sh

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,39 +101,28 @@ test_expect_failure 'push new branch with old:new refspec' '
101101

102102
test_expect_success 'cloning without refspec' '
103103
GIT_REMOTE_TESTGIT_REFSPEC="" \
104-
git clone "testgit::${PWD}/server" local2 &&
104+
git clone "testgit::${PWD}/server" local2 2>error &&
105+
grep "This remote helper should implement refspec capability" error &&
105106
compare_refs local2 HEAD server HEAD
106107
'
107108

108109
test_expect_success 'pulling without refspecs' '
109110
(cd local2 &&
110111
git reset --hard &&
111-
GIT_REMOTE_TESTGIT_REFSPEC="" git pull) &&
112+
GIT_REMOTE_TESTGIT_REFSPEC="" git pull 2>../error) &&
113+
grep "This remote helper should implement refspec capability" error &&
112114
compare_refs local2 HEAD server HEAD
113115
'
114116

115-
test_expect_failure 'pushing without refspecs' '
117+
test_expect_success 'pushing without refspecs' '
116118
test_when_finished "(cd local2 && git reset --hard origin)" &&
117119
(cd local2 &&
118120
echo content >>file &&
119121
git commit -a -m ten &&
120-
GIT_REMOTE_TESTGIT_REFSPEC="" git push) &&
121-
compare_refs local2 HEAD server HEAD
122-
'
123-
124-
test_expect_success 'pulling with straight refspec' '
125-
(cd local2 &&
126-
GIT_REMOTE_TESTGIT_REFSPEC="*:*" git pull) &&
127-
compare_refs local2 HEAD server HEAD
128-
'
129-
130-
test_expect_failure 'pushing with straight refspec' '
131-
test_when_finished "(cd local2 && git reset --hard origin)" &&
132-
(cd local2 &&
133-
echo content >>file &&
134-
git commit -a -m eleven &&
135-
GIT_REMOTE_TESTGIT_REFSPEC="*:*" git push) &&
136-
compare_refs local2 HEAD server HEAD
122+
GIT_REMOTE_TESTGIT_REFSPEC="" &&
123+
export GIT_REMOTE_TESTGIT_REFSPEC &&
124+
test_must_fail git push 2>../error) &&
125+
grep "remote-helper doesn.t support push; refspec needed" error
137126
'
138127

139128
test_expect_success 'pulling without marks' '
@@ -186,6 +175,52 @@ test_expect_success GPG 'push signed tag with signed-tags capability' '
186175
compare_refs local signed-tag-2 server signed-tag-2
187176
'
188177

178+
test_expect_success 'push update refs' '
179+
(cd local &&
180+
git checkout -b update master &&
181+
echo update >>file &&
182+
git commit -a -m update &&
183+
git push origin update &&
184+
git rev-parse --verify remotes/origin/update >expect &&
185+
git rev-parse --verify testgit/origin/heads/update >actual &&
186+
test_cmp expect actual
187+
)
188+
'
189+
190+
test_expect_success 'push update refs failure' '
191+
(cd local &&
192+
git checkout update &&
193+
echo "update fail" >>file &&
194+
git commit -a -m "update fail" &&
195+
git rev-parse --verify testgit/origin/heads/update >expect &&
196+
GIT_REMOTE_TESTGIT_PUSH_ERROR="non-fast forward" &&
197+
export GIT_REMOTE_TESTGIT_PUSH_ERROR &&
198+
test_expect_code 1 git push origin update &&
199+
git rev-parse --verify testgit/origin/heads/update >actual &&
200+
test_cmp expect actual
201+
)
202+
'
203+
204+
test_expect_success 'proper failure checks for fetching' '
205+
(GIT_REMOTE_TESTGIT_FAILURE=1 &&
206+
export GIT_REMOTE_TESTGIT_FAILURE &&
207+
cd local &&
208+
test_must_fail git fetch 2> error &&
209+
cat error &&
210+
grep -q "Error while running fast-import" error
211+
)
212+
'
213+
214+
test_expect_success 'proper failure checks for pushing' '
215+
(GIT_REMOTE_TESTGIT_FAILURE=1 &&
216+
export GIT_REMOTE_TESTGIT_FAILURE &&
217+
cd local &&
218+
test_must_fail git push --all 2> error &&
219+
cat error &&
220+
grep -q "Reading from helper .git-remote-testgit. failed" error
221+
)
222+
'
223+
189224
test_expect_success 'push messages' '
190225
(cd local &&
191226
git checkout -b new_branch master &&

transport-helper.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "thread-utils.h"
1212
#include "sigchain.h"
1313
#include "argv-array.h"
14+
#include "refs.h"
1415

1516
static int debug;
1617

@@ -47,15 +48,15 @@ static void sendline(struct helper_data *helper, struct strbuf *buffer)
4748
die_errno("Full write to remote helper failed");
4849
}
4950

50-
static int recvline_fh(FILE *helper, struct strbuf *buffer)
51+
static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)
5152
{
5253
strbuf_reset(buffer);
5354
if (debug)
5455
fprintf(stderr, "Debug: Remote helper: Waiting...\n");
5556
if (strbuf_getline(buffer, helper, '\n') == EOF) {
5657
if (debug)
5758
fprintf(stderr, "Debug: Remote helper quit.\n");
58-
exit(128);
59+
die("Reading from helper 'git-remote-%s' failed", name);
5960
}
6061

6162
if (debug)
@@ -65,7 +66,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer)
6566

6667
static int recvline(struct helper_data *helper, struct strbuf *buffer)
6768
{
68-
return recvline_fh(helper->out, buffer);
69+
return recvline_fh(helper->out, buffer, helper->name);
6970
}
7071

7172
static void xchgline(struct helper_data *helper, struct strbuf *buffer)
@@ -217,6 +218,8 @@ static struct child_process *get_helper(struct transport *transport)
217218
for (i = 0; i < refspec_nr; i++)
218219
free((char *)refspecs[i]);
219220
free(refspecs);
221+
} else if (data->import || data->bidi_import || data->export) {
222+
warning("This remote helper should implement refspec capability.");
220223
}
221224
strbuf_release(&buf);
222225
if (debug)
@@ -473,7 +476,7 @@ static int fetch_with_import(struct transport *transport,
473476
* were fetching.
474477
*
475478
* (If no "refspec" capability was specified, for historical
476-
* reasons we default to *:*.)
479+
* reasons we default to the equivalent of *:*.)
477480
*
478481
* Store the result in to_fetch[i].old_sha1. Callers such
479482
* as "git fetch" can use the value to write feedback to the
@@ -540,7 +543,7 @@ static int process_connect_service(struct transport *transport,
540543
goto exit;
541544

542545
sendline(data, &cmdbuf);
543-
recvline_fh(input, &cmdbuf);
546+
recvline_fh(input, &cmdbuf, name);
544547
if (!strcmp(cmdbuf.buf, "")) {
545548
data->no_disconnect_req = 1;
546549
if (debug)
@@ -622,7 +625,7 @@ static int fetch(struct transport *transport,
622625
return -1;
623626
}
624627

625-
static void push_update_ref_status(struct strbuf *buf,
628+
static int push_update_ref_status(struct strbuf *buf,
626629
struct ref **ref,
627630
struct ref *remote_refs)
628631
{
@@ -688,7 +691,7 @@ static void push_update_ref_status(struct strbuf *buf,
688691
*ref = find_ref_by_name(remote_refs, refname);
689692
if (!*ref) {
690693
warning("helper reported unexpected status of %s", refname);
691-
return;
694+
return 1;
692695
}
693696

694697
if ((*ref)->status != REF_STATUS_NONE) {
@@ -697,11 +700,12 @@ static void push_update_ref_status(struct strbuf *buf,
697700
* status reported by the remote helper if the latter is 'no match'.
698701
*/
699702
if (status == REF_STATUS_NONE)
700-
return;
703+
return 1;
701704
}
702705

703706
(*ref)->status = status;
704707
(*ref)->remote_status = msg;
708+
return !(status == REF_STATUS_OK);
705709
}
706710

707711
static void push_update_refs_status(struct helper_data *data,
@@ -710,11 +714,24 @@ static void push_update_refs_status(struct helper_data *data,
710714
struct strbuf buf = STRBUF_INIT;
711715
struct ref *ref = remote_refs;
712716
for (;;) {
717+
char *private;
718+
713719
recvline(data, &buf);
714720
if (!buf.len)
715721
break;
716722

717-
push_update_ref_status(&buf, &ref, remote_refs);
723+
if (push_update_ref_status(&buf, &ref, remote_refs))
724+
continue;
725+
726+
if (!data->refspecs)
727+
continue;
728+
729+
/* propagate back the update to the remote namespace */
730+
private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
731+
if (!private)
732+
continue;
733+
update_ref("update by helper", private, ref->new_sha1, NULL, 0, 0);
734+
free(private);
718735
}
719736
strbuf_release(&buf);
720737
}
@@ -789,6 +806,9 @@ static int push_refs_with_export(struct transport *transport,
789806
struct string_list revlist_args = STRING_LIST_INIT_NODUP;
790807
struct strbuf buf = STRBUF_INIT;
791808

809+
if (!data->refspecs)
810+
die("remote-helper doesn't support push; refspec needed");
811+
792812
helper = get_helper(transport);
793813

794814
write_constant(helper->in, "export\n");
@@ -799,8 +819,9 @@ static int push_refs_with_export(struct transport *transport,
799819
char *private;
800820
unsigned char sha1[20];
801821

802-
if (!data->refspecs)
803-
continue;
822+
if (ref->deletion)
823+
die("remote-helpers do not support ref deletion");
824+
804825
private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
805826
if (private && !get_sha1(private, sha1)) {
806827
strbuf_addf(&buf, "^%s", private);
@@ -809,13 +830,8 @@ static int push_refs_with_export(struct transport *transport,
809830
}
810831
free(private);
811832

812-
if (ref->deletion) {
813-
die("remote-helpers do not support ref deletion");
814-
}
815-
816833
if (ref->peer_ref)
817834
string_list_append(&revlist_args, ref->peer_ref->name);
818-
819835
}
820836

821837
if (get_exporter(transport, &exporter, &revlist_args))

0 commit comments

Comments
 (0)