Skip to content

Commit 81b4f18

Browse files
committed
Merge branch 'js/transport-helper-error-reporting-fix' into fc/makefile
* js/transport-helper-error-reporting-fix: git-remote-testgit: build it to run under $SHELL_PATH git-remote-testgit: further remove some bashisms git-remote-testgit: avoid process substitution 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 Conflicts: t/t5801-remote-helpers.sh
2 parents 416fda6 + 709a957 commit 81b4f18

File tree

6 files changed

+115
-56
lines changed

6 files changed

+115
-56
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
/git-remote-ftps
126126
/git-remote-fd
127127
/git-remote-ext
128+
/git-remote-testgit
128129
/git-remote-testpy
129130
/git-remote-testsvn
130131
/git-repack

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.

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ SCRIPT_SH += git-mergetool.sh
460460
SCRIPT_SH += git-pull.sh
461461
SCRIPT_SH += git-quiltimport.sh
462462
SCRIPT_SH += git-rebase.sh
463+
SCRIPT_SH += git-remote-testgit.sh
463464
SCRIPT_SH += git-repack.sh
464465
SCRIPT_SH += git-request-pull.sh
465466
SCRIPT_SH += git-stash.sh

git-remote-testgit renamed to git-remote-testgit.sh

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env bash
1+
#!/bin/sh
22
# Copyright (c) 2012 Felipe Contreras
33

44
alias=$1
@@ -23,7 +23,6 @@ then
2323
testgitmarks="$dir/testgit.marks"
2424
test -e "$gitmarks" || >"$gitmarks"
2525
test -e "$testgitmarks" || >"$testgitmarks"
26-
testgitmarks_args=( "--"{import,export}"-marks=$testgitmarks" )
2726
fi
2827

2928
while read line
@@ -62,23 +61,49 @@ do
6261
echo "feature import-marks=$gitmarks"
6362
echo "feature export-marks=$gitmarks"
6463
fi
64+
65+
if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
66+
then
67+
echo "feature done"
68+
exit 1
69+
fi
70+
6571
echo "feature done"
66-
git fast-export "${testgitmarks_args[@]}" $refs |
72+
git fast-export \
73+
${testgitmarks:+"--import-marks=$testgitmarks"} \
74+
${testgitmarks:+"--export-marks=$testgitmarks"} \
75+
$refs |
6776
sed -e "s#refs/heads/#${prefix}/heads/#g"
6877
echo "done"
6978
;;
7079
export)
71-
before=$(git for-each-ref --format='%(refname) %(objectname)')
80+
if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
81+
then
82+
# consume input so fast-export doesn't get SIGPIPE;
83+
# git would also notice that case, but we want
84+
# to make sure we are exercising the later
85+
# error checks
86+
while read line; do
87+
test "done" = "$line" && break
88+
done
89+
exit 1
90+
fi
7291

73-
git fast-import "${testgitmarks_args[@]}" --quiet
92+
before=$(git for-each-ref --format=' %(refname) %(objectname) ')
7493

75-
after=$(git for-each-ref --format='%(refname) %(objectname)')
94+
git fast-import \
95+
${testgitmarks:+"--import-marks=$testgitmarks"} \
96+
${testgitmarks:+"--export-marks=$testgitmarks"} \
97+
--quiet
7698

7799
# figure out which refs were updated
78-
join -e 0 -o '0 1.2 2.2' -a 2 <(echo "$before") <(echo "$after") |
79-
while read ref a b
100+
git for-each-ref --format='%(refname) %(objectname)' |
101+
while read ref a
80102
do
81-
test $a == $b && continue
103+
case "$before" in
104+
*" $ref $a "*)
105+
continue ;; # unchanged
106+
esac
82107
echo "ok $ref"
83108
done
84109

t/t5801-remote-helpers.sh

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ test_description='Test remote-helper import and export commands'
88
. ./test-lib.sh
99
. "$TEST_DIRECTORY"/lib-gpg.sh
1010

11-
if ! type "${BASH-bash}" >/dev/null 2>&1; then
12-
skip_all='skipping remote-testgit tests, bash not available'
13-
test_done
14-
fi
15-
1611
compare_refs() {
1712
git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
1813
git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
@@ -101,39 +96,28 @@ test_expect_failure 'push new branch with old:new refspec' '
10196

10297
test_expect_success 'cloning without refspec' '
10398
GIT_REMOTE_TESTGIT_REFSPEC="" \
104-
git clone "testgit::${PWD}/server" local2 &&
99+
git clone "testgit::${PWD}/server" local2 2>error &&
100+
grep "This remote helper should implement refspec capability" error &&
105101
compare_refs local2 HEAD server HEAD
106102
'
107103

108104
test_expect_success 'pulling without refspecs' '
109105
(cd local2 &&
110106
git reset --hard &&
111-
GIT_REMOTE_TESTGIT_REFSPEC="" git pull) &&
107+
GIT_REMOTE_TESTGIT_REFSPEC="" git pull 2>../error) &&
108+
grep "This remote helper should implement refspec capability" error &&
112109
compare_refs local2 HEAD server HEAD
113110
'
114111

115-
test_expect_failure 'pushing without refspecs' '
112+
test_expect_success 'pushing without refspecs' '
116113
test_when_finished "(cd local2 && git reset --hard origin)" &&
117114
(cd local2 &&
118115
echo content >>file &&
119116
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
117+
GIT_REMOTE_TESTGIT_REFSPEC="" &&
118+
export GIT_REMOTE_TESTGIT_REFSPEC &&
119+
test_must_fail git push 2>../error) &&
120+
grep "remote-helper doesn.t support push; refspec needed" error
137121
'
138122

139123
test_expect_success 'pulling without marks' '
@@ -186,6 +170,38 @@ test_expect_success GPG 'push signed tag with signed-tags capability' '
186170
compare_refs local signed-tag-2 server signed-tag-2
187171
'
188172

173+
test_expect_success 'push update refs' '
174+
(cd local &&
175+
git checkout -b update master &&
176+
echo update >>file &&
177+
git commit -a -m update &&
178+
git push origin update
179+
git rev-parse --verify remotes/origin/update >expect &&
180+
git rev-parse --verify testgit/origin/heads/update >actual &&
181+
test_cmp expect actual
182+
)
183+
'
184+
185+
test_expect_success 'proper failure checks for fetching' '
186+
(GIT_REMOTE_TESTGIT_FAILURE=1 &&
187+
export GIT_REMOTE_TESTGIT_FAILURE &&
188+
cd local &&
189+
test_must_fail git fetch 2> error &&
190+
cat error &&
191+
grep -q "Error while running fast-import" error
192+
)
193+
'
194+
195+
test_expect_success 'proper failure checks for pushing' '
196+
(GIT_REMOTE_TESTGIT_FAILURE=1 &&
197+
export GIT_REMOTE_TESTGIT_FAILURE &&
198+
cd local &&
199+
test_must_fail git push --all 2> error &&
200+
cat error &&
201+
grep -q "Reading from helper .git-remote-testgit. failed" error
202+
)
203+
'
204+
189205
test_expect_success 'push messages' '
190206
(cd local &&
191207
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 0;
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)