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
This commit is contained in:
commit
81b4f18fb8
1
.gitignore
vendored
1
.gitignore
vendored
@ -125,6 +125,7 @@
|
|||||||
/git-remote-ftps
|
/git-remote-ftps
|
||||||
/git-remote-fd
|
/git-remote-fd
|
||||||
/git-remote-ext
|
/git-remote-ext
|
||||||
|
/git-remote-testgit
|
||||||
/git-remote-testpy
|
/git-remote-testpy
|
||||||
/git-remote-testsvn
|
/git-remote-testsvn
|
||||||
/git-repack
|
/git-repack
|
||||||
|
@ -159,11 +159,11 @@ Miscellaneous capabilities
|
|||||||
carried out.
|
carried out.
|
||||||
|
|
||||||
'refspec' <refspec>::
|
'refspec' <refspec>::
|
||||||
This modifies the 'import' capability, allowing the produced
|
For remote helpers that implement 'import' or 'export', this capability
|
||||||
fast-import stream to modify refs in a private namespace
|
allows the refs to be constrained to a private namespace, instead of
|
||||||
instead of writing to refs/heads or refs/remotes directly.
|
writing to refs/heads or refs/remotes directly.
|
||||||
It is recommended that all importers providing the 'import'
|
It is recommended that all importers providing the 'import'
|
||||||
capability use this.
|
capability use this. It's mandatory for 'export'.
|
||||||
+
|
+
|
||||||
A helper advertising the capability
|
A helper advertising the capability
|
||||||
`refspec refs/heads/*:refs/svn/origin/branches/*`
|
`refspec refs/heads/*:refs/svn/origin/branches/*`
|
||||||
@ -174,8 +174,8 @@ ref.
|
|||||||
This capability can be advertised multiple times. The first
|
This capability can be advertised multiple times. The first
|
||||||
applicable refspec takes precedence. The left-hand of refspecs
|
applicable refspec takes precedence. The left-hand of refspecs
|
||||||
advertised with this capability must cover all refs reported by
|
advertised with this capability must cover all refs reported by
|
||||||
the list command. If a helper does not need a specific 'refspec'
|
the list command. If no 'refspec' capability is advertised,
|
||||||
capability then it should advertise `refspec *:*`.
|
there is an implied `refspec *:*`.
|
||||||
|
|
||||||
'bidi-import'::
|
'bidi-import'::
|
||||||
This modifies the 'import' capability.
|
This modifies the 'import' capability.
|
||||||
|
1
Makefile
1
Makefile
@ -460,6 +460,7 @@ SCRIPT_SH += git-mergetool.sh
|
|||||||
SCRIPT_SH += git-pull.sh
|
SCRIPT_SH += git-pull.sh
|
||||||
SCRIPT_SH += git-quiltimport.sh
|
SCRIPT_SH += git-quiltimport.sh
|
||||||
SCRIPT_SH += git-rebase.sh
|
SCRIPT_SH += git-rebase.sh
|
||||||
|
SCRIPT_SH += git-remote-testgit.sh
|
||||||
SCRIPT_SH += git-repack.sh
|
SCRIPT_SH += git-repack.sh
|
||||||
SCRIPT_SH += git-request-pull.sh
|
SCRIPT_SH += git-request-pull.sh
|
||||||
SCRIPT_SH += git-stash.sh
|
SCRIPT_SH += git-stash.sh
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
# Copyright (c) 2012 Felipe Contreras
|
# Copyright (c) 2012 Felipe Contreras
|
||||||
|
|
||||||
alias=$1
|
alias=$1
|
||||||
@ -23,7 +23,6 @@ then
|
|||||||
testgitmarks="$dir/testgit.marks"
|
testgitmarks="$dir/testgit.marks"
|
||||||
test -e "$gitmarks" || >"$gitmarks"
|
test -e "$gitmarks" || >"$gitmarks"
|
||||||
test -e "$testgitmarks" || >"$testgitmarks"
|
test -e "$testgitmarks" || >"$testgitmarks"
|
||||||
testgitmarks_args=( "--"{import,export}"-marks=$testgitmarks" )
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while read line
|
while read line
|
||||||
@ -62,23 +61,49 @@ do
|
|||||||
echo "feature import-marks=$gitmarks"
|
echo "feature import-marks=$gitmarks"
|
||||||
echo "feature export-marks=$gitmarks"
|
echo "feature export-marks=$gitmarks"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
|
||||||
|
then
|
||||||
|
echo "feature done"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "feature done"
|
echo "feature done"
|
||||||
git fast-export "${testgitmarks_args[@]}" $refs |
|
git fast-export \
|
||||||
|
${testgitmarks:+"--import-marks=$testgitmarks"} \
|
||||||
|
${testgitmarks:+"--export-marks=$testgitmarks"} \
|
||||||
|
$refs |
|
||||||
sed -e "s#refs/heads/#${prefix}/heads/#g"
|
sed -e "s#refs/heads/#${prefix}/heads/#g"
|
||||||
echo "done"
|
echo "done"
|
||||||
;;
|
;;
|
||||||
export)
|
export)
|
||||||
before=$(git for-each-ref --format='%(refname) %(objectname)')
|
if test -n "$GIT_REMOTE_TESTGIT_FAILURE"
|
||||||
|
then
|
||||||
|
# consume input so fast-export doesn't get SIGPIPE;
|
||||||
|
# git would also notice that case, but we want
|
||||||
|
# to make sure we are exercising the later
|
||||||
|
# error checks
|
||||||
|
while read line; do
|
||||||
|
test "done" = "$line" && break
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
git fast-import "${testgitmarks_args[@]}" --quiet
|
before=$(git for-each-ref --format=' %(refname) %(objectname) ')
|
||||||
|
|
||||||
after=$(git for-each-ref --format='%(refname) %(objectname)')
|
git fast-import \
|
||||||
|
${testgitmarks:+"--import-marks=$testgitmarks"} \
|
||||||
|
${testgitmarks:+"--export-marks=$testgitmarks"} \
|
||||||
|
--quiet
|
||||||
|
|
||||||
# figure out which refs were updated
|
# figure out which refs were updated
|
||||||
join -e 0 -o '0 1.2 2.2' -a 2 <(echo "$before") <(echo "$after") |
|
git for-each-ref --format='%(refname) %(objectname)' |
|
||||||
while read ref a b
|
while read ref a
|
||||||
do
|
do
|
||||||
test $a == $b && continue
|
case "$before" in
|
||||||
|
*" $ref $a "*)
|
||||||
|
continue ;; # unchanged
|
||||||
|
esac
|
||||||
echo "ok $ref"
|
echo "ok $ref"
|
||||||
done
|
done
|
||||||
|
|
@ -8,11 +8,6 @@ test_description='Test remote-helper import and export commands'
|
|||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
. "$TEST_DIRECTORY"/lib-gpg.sh
|
. "$TEST_DIRECTORY"/lib-gpg.sh
|
||||||
|
|
||||||
if ! type "${BASH-bash}" >/dev/null 2>&1; then
|
|
||||||
skip_all='skipping remote-testgit tests, bash not available'
|
|
||||||
test_done
|
|
||||||
fi
|
|
||||||
|
|
||||||
compare_refs() {
|
compare_refs() {
|
||||||
git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
|
git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
|
||||||
git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
|
git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
|
||||||
@ -101,39 +96,28 @@ test_expect_failure 'push new branch with old:new refspec' '
|
|||||||
|
|
||||||
test_expect_success 'cloning without refspec' '
|
test_expect_success 'cloning without refspec' '
|
||||||
GIT_REMOTE_TESTGIT_REFSPEC="" \
|
GIT_REMOTE_TESTGIT_REFSPEC="" \
|
||||||
git clone "testgit::${PWD}/server" local2 &&
|
git clone "testgit::${PWD}/server" local2 2>error &&
|
||||||
|
grep "This remote helper should implement refspec capability" error &&
|
||||||
compare_refs local2 HEAD server HEAD
|
compare_refs local2 HEAD server HEAD
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'pulling without refspecs' '
|
test_expect_success 'pulling without refspecs' '
|
||||||
(cd local2 &&
|
(cd local2 &&
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
GIT_REMOTE_TESTGIT_REFSPEC="" git pull) &&
|
GIT_REMOTE_TESTGIT_REFSPEC="" git pull 2>../error) &&
|
||||||
|
grep "This remote helper should implement refspec capability" error &&
|
||||||
compare_refs local2 HEAD server HEAD
|
compare_refs local2 HEAD server HEAD
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_failure 'pushing without refspecs' '
|
test_expect_success 'pushing without refspecs' '
|
||||||
test_when_finished "(cd local2 && git reset --hard origin)" &&
|
test_when_finished "(cd local2 && git reset --hard origin)" &&
|
||||||
(cd local2 &&
|
(cd local2 &&
|
||||||
echo content >>file &&
|
echo content >>file &&
|
||||||
git commit -a -m ten &&
|
git commit -a -m ten &&
|
||||||
GIT_REMOTE_TESTGIT_REFSPEC="" git push) &&
|
GIT_REMOTE_TESTGIT_REFSPEC="" &&
|
||||||
compare_refs local2 HEAD server HEAD
|
export GIT_REMOTE_TESTGIT_REFSPEC &&
|
||||||
'
|
test_must_fail git push 2>../error) &&
|
||||||
|
grep "remote-helper doesn.t support push; refspec needed" error
|
||||||
test_expect_success 'pulling with straight refspec' '
|
|
||||||
(cd local2 &&
|
|
||||||
GIT_REMOTE_TESTGIT_REFSPEC="*:*" git pull) &&
|
|
||||||
compare_refs local2 HEAD server HEAD
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_failure 'pushing with straight refspec' '
|
|
||||||
test_when_finished "(cd local2 && git reset --hard origin)" &&
|
|
||||||
(cd local2 &&
|
|
||||||
echo content >>file &&
|
|
||||||
git commit -a -m eleven &&
|
|
||||||
GIT_REMOTE_TESTGIT_REFSPEC="*:*" git push) &&
|
|
||||||
compare_refs local2 HEAD server HEAD
|
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'pulling without marks' '
|
test_expect_success 'pulling without marks' '
|
||||||
@ -186,6 +170,38 @@ test_expect_success GPG 'push signed tag with signed-tags capability' '
|
|||||||
compare_refs local signed-tag-2 server signed-tag-2
|
compare_refs local signed-tag-2 server signed-tag-2
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'push update refs' '
|
||||||
|
(cd local &&
|
||||||
|
git checkout -b update master &&
|
||||||
|
echo update >>file &&
|
||||||
|
git commit -a -m update &&
|
||||||
|
git push origin update
|
||||||
|
git rev-parse --verify remotes/origin/update >expect &&
|
||||||
|
git rev-parse --verify testgit/origin/heads/update >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'proper failure checks for fetching' '
|
||||||
|
(GIT_REMOTE_TESTGIT_FAILURE=1 &&
|
||||||
|
export GIT_REMOTE_TESTGIT_FAILURE &&
|
||||||
|
cd local &&
|
||||||
|
test_must_fail git fetch 2> error &&
|
||||||
|
cat error &&
|
||||||
|
grep -q "Error while running fast-import" error
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'proper failure checks for pushing' '
|
||||||
|
(GIT_REMOTE_TESTGIT_FAILURE=1 &&
|
||||||
|
export GIT_REMOTE_TESTGIT_FAILURE &&
|
||||||
|
cd local &&
|
||||||
|
test_must_fail git push --all 2> error &&
|
||||||
|
cat error &&
|
||||||
|
grep -q "Reading from helper .git-remote-testgit. failed" error
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'push messages' '
|
test_expect_success 'push messages' '
|
||||||
(cd local &&
|
(cd local &&
|
||||||
git checkout -b new_branch master &&
|
git checkout -b new_branch master &&
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "thread-utils.h"
|
#include "thread-utils.h"
|
||||||
#include "sigchain.h"
|
#include "sigchain.h"
|
||||||
#include "argv-array.h"
|
#include "argv-array.h"
|
||||||
|
#include "refs.h"
|
||||||
|
|
||||||
static int debug;
|
static int debug;
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ static void sendline(struct helper_data *helper, struct strbuf *buffer)
|
|||||||
die_errno("Full write to remote helper failed");
|
die_errno("Full write to remote helper failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int recvline_fh(FILE *helper, struct strbuf *buffer)
|
static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)
|
||||||
{
|
{
|
||||||
strbuf_reset(buffer);
|
strbuf_reset(buffer);
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -55,7 +56,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer)
|
|||||||
if (strbuf_getline(buffer, helper, '\n') == EOF) {
|
if (strbuf_getline(buffer, helper, '\n') == EOF) {
|
||||||
if (debug)
|
if (debug)
|
||||||
fprintf(stderr, "Debug: Remote helper quit.\n");
|
fprintf(stderr, "Debug: Remote helper quit.\n");
|
||||||
exit(128);
|
die("Reading from helper 'git-remote-%s' failed", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -65,7 +66,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer)
|
|||||||
|
|
||||||
static int recvline(struct helper_data *helper, struct strbuf *buffer)
|
static int recvline(struct helper_data *helper, struct strbuf *buffer)
|
||||||
{
|
{
|
||||||
return recvline_fh(helper->out, buffer);
|
return recvline_fh(helper->out, buffer, helper->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xchgline(struct helper_data *helper, struct strbuf *buffer)
|
static void xchgline(struct helper_data *helper, struct strbuf *buffer)
|
||||||
@ -217,6 +218,8 @@ static struct child_process *get_helper(struct transport *transport)
|
|||||||
for (i = 0; i < refspec_nr; i++)
|
for (i = 0; i < refspec_nr; i++)
|
||||||
free((char *)refspecs[i]);
|
free((char *)refspecs[i]);
|
||||||
free(refspecs);
|
free(refspecs);
|
||||||
|
} else if (data->import || data->bidi_import || data->export) {
|
||||||
|
warning("This remote helper should implement refspec capability.");
|
||||||
}
|
}
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -473,7 +476,7 @@ static int fetch_with_import(struct transport *transport,
|
|||||||
* were fetching.
|
* were fetching.
|
||||||
*
|
*
|
||||||
* (If no "refspec" capability was specified, for historical
|
* (If no "refspec" capability was specified, for historical
|
||||||
* reasons we default to *:*.)
|
* reasons we default to the equivalent of *:*.)
|
||||||
*
|
*
|
||||||
* Store the result in to_fetch[i].old_sha1. Callers such
|
* Store the result in to_fetch[i].old_sha1. Callers such
|
||||||
* as "git fetch" can use the value to write feedback to the
|
* as "git fetch" can use the value to write feedback to the
|
||||||
@ -540,7 +543,7 @@ static int process_connect_service(struct transport *transport,
|
|||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
sendline(data, &cmdbuf);
|
sendline(data, &cmdbuf);
|
||||||
recvline_fh(input, &cmdbuf);
|
recvline_fh(input, &cmdbuf, name);
|
||||||
if (!strcmp(cmdbuf.buf, "")) {
|
if (!strcmp(cmdbuf.buf, "")) {
|
||||||
data->no_disconnect_req = 1;
|
data->no_disconnect_req = 1;
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -622,7 +625,7 @@ static int fetch(struct transport *transport,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void push_update_ref_status(struct strbuf *buf,
|
static int push_update_ref_status(struct strbuf *buf,
|
||||||
struct ref **ref,
|
struct ref **ref,
|
||||||
struct ref *remote_refs)
|
struct ref *remote_refs)
|
||||||
{
|
{
|
||||||
@ -688,7 +691,7 @@ static void push_update_ref_status(struct strbuf *buf,
|
|||||||
*ref = find_ref_by_name(remote_refs, refname);
|
*ref = find_ref_by_name(remote_refs, refname);
|
||||||
if (!*ref) {
|
if (!*ref) {
|
||||||
warning("helper reported unexpected status of %s", refname);
|
warning("helper reported unexpected status of %s", refname);
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*ref)->status != REF_STATUS_NONE) {
|
if ((*ref)->status != REF_STATUS_NONE) {
|
||||||
@ -697,11 +700,12 @@ static void push_update_ref_status(struct strbuf *buf,
|
|||||||
* status reported by the remote helper if the latter is 'no match'.
|
* status reported by the remote helper if the latter is 'no match'.
|
||||||
*/
|
*/
|
||||||
if (status == REF_STATUS_NONE)
|
if (status == REF_STATUS_NONE)
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*ref)->status = status;
|
(*ref)->status = status;
|
||||||
(*ref)->remote_status = msg;
|
(*ref)->remote_status = msg;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void push_update_refs_status(struct helper_data *data,
|
static void push_update_refs_status(struct helper_data *data,
|
||||||
@ -710,11 +714,24 @@ static void push_update_refs_status(struct helper_data *data,
|
|||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
struct ref *ref = remote_refs;
|
struct ref *ref = remote_refs;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
char *private;
|
||||||
|
|
||||||
recvline(data, &buf);
|
recvline(data, &buf);
|
||||||
if (!buf.len)
|
if (!buf.len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
push_update_ref_status(&buf, &ref, remote_refs);
|
if (push_update_ref_status(&buf, &ref, remote_refs))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!data->refspecs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* propagate back the update to the remote namespace */
|
||||||
|
private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
|
||||||
|
if (!private)
|
||||||
|
continue;
|
||||||
|
update_ref("update by helper", private, ref->new_sha1, NULL, 0, 0);
|
||||||
|
free(private);
|
||||||
}
|
}
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
@ -789,6 +806,9 @@ static int push_refs_with_export(struct transport *transport,
|
|||||||
struct string_list revlist_args = STRING_LIST_INIT_NODUP;
|
struct string_list revlist_args = STRING_LIST_INIT_NODUP;
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
|
||||||
|
if (!data->refspecs)
|
||||||
|
die("remote-helper doesn't support push; refspec needed");
|
||||||
|
|
||||||
helper = get_helper(transport);
|
helper = get_helper(transport);
|
||||||
|
|
||||||
write_constant(helper->in, "export\n");
|
write_constant(helper->in, "export\n");
|
||||||
@ -799,8 +819,9 @@ static int push_refs_with_export(struct transport *transport,
|
|||||||
char *private;
|
char *private;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
|
||||||
if (!data->refspecs)
|
if (ref->deletion)
|
||||||
continue;
|
die("remote-helpers do not support ref deletion");
|
||||||
|
|
||||||
private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
|
private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
|
||||||
if (private && !get_sha1(private, sha1)) {
|
if (private && !get_sha1(private, sha1)) {
|
||||||
strbuf_addf(&buf, "^%s", private);
|
strbuf_addf(&buf, "^%s", private);
|
||||||
@ -809,13 +830,8 @@ static int push_refs_with_export(struct transport *transport,
|
|||||||
}
|
}
|
||||||
free(private);
|
free(private);
|
||||||
|
|
||||||
if (ref->deletion) {
|
|
||||||
die("remote-helpers do not support ref deletion");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ref->peer_ref)
|
if (ref->peer_ref)
|
||||||
string_list_append(&revlist_args, ref->peer_ref->name);
|
string_list_append(&revlist_args, ref->peer_ref->name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_exporter(transport, &exporter, &revlist_args))
|
if (get_exporter(transport, &exporter, &revlist_args))
|
||||||
|
Loading…
Reference in New Issue
Block a user