Merge branch 'sp/maint-push-sideband' into maint
* sp/maint-push-sideband: receive-pack: Send internal errors over side-band #2 t5401: Use a bare repository for the remote peer receive-pack: Send hook output over side band #2 receive-pack: Wrap status reports inside side-band-64k receive-pack: Refactor how capabilities are shown to the client send-pack: demultiplex a sideband stream with status data run-command: support custom fd-set in async run-command: Allow stderr to be a caller supplied pipe Conflicts: builtin-receive-pack.c run-command.c t/t5401-update-hooks.sh
This commit is contained in:
commit
a886ba2801
@ -64,8 +64,8 @@ The functions above do the following:
|
|||||||
`start_async`::
|
`start_async`::
|
||||||
|
|
||||||
Run a function asynchronously. Takes a pointer to a `struct
|
Run a function asynchronously. Takes a pointer to a `struct
|
||||||
async` that specifies the details and returns a pipe FD
|
async` that specifies the details and returns a set of pipe FDs
|
||||||
from which the caller reads. See below for details.
|
for communication with the function. See below for details.
|
||||||
|
|
||||||
`finish_async`::
|
`finish_async`::
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ stderr as follows:
|
|||||||
|
|
||||||
.in: The FD must be readable; it becomes child's stdin.
|
.in: The FD must be readable; it becomes child's stdin.
|
||||||
.out: The FD must be writable; it becomes child's stdout.
|
.out: The FD must be writable; it becomes child's stdout.
|
||||||
.err > 0 is not supported.
|
.err: The FD must be writable; it becomes child's stderr.
|
||||||
|
|
||||||
The specified FD is closed by start_command(), even if it fails to
|
The specified FD is closed by start_command(), even if it fails to
|
||||||
run the sub-process!
|
run the sub-process!
|
||||||
@ -180,17 +180,47 @@ The caller:
|
|||||||
struct async variable;
|
struct async variable;
|
||||||
2. initializes .proc and .data;
|
2. initializes .proc and .data;
|
||||||
3. calls start_async();
|
3. calls start_async();
|
||||||
4. processes the data by reading from the fd in .out;
|
4. processes communicates with proc through .in and .out;
|
||||||
5. closes .out;
|
5. closes .in and .out;
|
||||||
6. calls finish_async().
|
6. calls finish_async().
|
||||||
|
|
||||||
|
The members .in, .out are used to provide a set of fd's for
|
||||||
|
communication between the caller and the callee as follows:
|
||||||
|
|
||||||
|
. Specify 0 to have no file descriptor passed. The callee will
|
||||||
|
receive -1 in the corresponding argument.
|
||||||
|
|
||||||
|
. Specify < 0 to have a pipe allocated; start_async() replaces
|
||||||
|
with the pipe FD in the following way:
|
||||||
|
|
||||||
|
.in: Returns the writable pipe end into which the caller
|
||||||
|
writes; the readable end of the pipe becomes the function's
|
||||||
|
in argument.
|
||||||
|
|
||||||
|
.out: Returns the readable pipe end from which the caller
|
||||||
|
reads; the writable end of the pipe becomes the function's
|
||||||
|
out argument.
|
||||||
|
|
||||||
|
The caller of start_async() must close the returned FDs after it
|
||||||
|
has completed reading from/writing from them.
|
||||||
|
|
||||||
|
. Specify a file descriptor > 0 to be used by the function:
|
||||||
|
|
||||||
|
.in: The FD must be readable; it becomes the function's in.
|
||||||
|
.out: The FD must be writable; it becomes the function's out.
|
||||||
|
|
||||||
|
The specified FD is closed by start_async(), even if it fails to
|
||||||
|
run the function.
|
||||||
|
|
||||||
The function pointer in .proc has the following signature:
|
The function pointer in .proc has the following signature:
|
||||||
|
|
||||||
int proc(int fd, void *data);
|
int proc(int in, int out, void *data);
|
||||||
|
|
||||||
. fd specifies a writable file descriptor to which the function must
|
. in, out specifies a set of file descriptors to which the function
|
||||||
write the data that it produces. The function *must* close this
|
must read/write the data that it needs/produces. The function
|
||||||
descriptor before it returns.
|
*must* close these descriptors before it returns. A descriptor
|
||||||
|
may be -1 if the caller did not configure a descriptor for that
|
||||||
|
direction.
|
||||||
|
|
||||||
. data is the value that the caller has specified in the .data member
|
. data is the value that the caller has specified in the .data member
|
||||||
of struct async.
|
of struct async.
|
||||||
@ -205,8 +235,8 @@ because this facility is implemented by a pipe to a forked process on
|
|||||||
UNIX, but by a thread in the same address space on Windows:
|
UNIX, but by a thread in the same address space on Windows:
|
||||||
|
|
||||||
. It cannot change the program's state (global variables, environment,
|
. It cannot change the program's state (global variables, environment,
|
||||||
etc.) in a way that the caller notices; in other words, .out is the
|
etc.) in a way that the caller notices; in other words, .in and .out
|
||||||
only communication channel to the caller.
|
are the only communication channels to the caller.
|
||||||
|
|
||||||
. It must not change the program's state that the caller of the
|
. It must not change the program's state that the caller of the
|
||||||
facility also uses.
|
facility also uses.
|
||||||
|
@ -586,12 +586,12 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sideband_demux(int fd, void *data)
|
static int sideband_demux(int in, int out, void *data)
|
||||||
{
|
{
|
||||||
int *xd = data;
|
int *xd = data;
|
||||||
|
|
||||||
int ret = recv_sideband("fetch-pack", xd[0], fd);
|
int ret = recv_sideband("fetch-pack", xd[0], out);
|
||||||
close(fd);
|
close(out);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,6 +613,7 @@ static int get_pack(int xd[2], char **pack_lockfile)
|
|||||||
*/
|
*/
|
||||||
demux.proc = sideband_demux;
|
demux.proc = sideband_demux;
|
||||||
demux.data = xd;
|
demux.data = xd;
|
||||||
|
demux.out = -1;
|
||||||
if (start_async(&demux))
|
if (start_async(&demux))
|
||||||
die("fetch-pack: unable to fork off sideband"
|
die("fetch-pack: unable to fork off sideband"
|
||||||
" demultiplexer");
|
" demultiplexer");
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "pack.h"
|
#include "pack.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "pkt-line.h"
|
#include "pkt-line.h"
|
||||||
|
#include "sideband.h"
|
||||||
#include "run-command.h"
|
#include "run-command.h"
|
||||||
#include "exec_cmd.h"
|
#include "exec_cmd.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
@ -27,11 +28,12 @@ static int receive_unpack_limit = -1;
|
|||||||
static int transfer_unpack_limit = -1;
|
static int transfer_unpack_limit = -1;
|
||||||
static int unpack_limit = 100;
|
static int unpack_limit = 100;
|
||||||
static int report_status;
|
static int report_status;
|
||||||
|
static int use_sideband;
|
||||||
static int prefer_ofs_delta = 1;
|
static int prefer_ofs_delta = 1;
|
||||||
static int auto_update_server_info;
|
static int auto_update_server_info;
|
||||||
static int auto_gc = 1;
|
static int auto_gc = 1;
|
||||||
static const char *head_name;
|
static const char *head_name;
|
||||||
static char *capabilities_to_send;
|
static int sent_capabilities;
|
||||||
|
|
||||||
static enum deny_action parse_deny_action(const char *var, const char *value)
|
static enum deny_action parse_deny_action(const char *var, const char *value)
|
||||||
{
|
{
|
||||||
@ -105,19 +107,21 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
|
|||||||
|
|
||||||
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
if (!capabilities_to_send)
|
if (sent_capabilities)
|
||||||
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
|
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
|
||||||
else
|
else
|
||||||
packet_write(1, "%s %s%c%s\n",
|
packet_write(1, "%s %s%c%s%s\n",
|
||||||
sha1_to_hex(sha1), path, 0, capabilities_to_send);
|
sha1_to_hex(sha1), path, 0,
|
||||||
capabilities_to_send = NULL;
|
" report-status delete-refs side-band-64k",
|
||||||
|
prefer_ofs_delta ? " ofs-delta" : "");
|
||||||
|
sent_capabilities = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_head_info(void)
|
static void write_head_info(void)
|
||||||
{
|
{
|
||||||
for_each_ref(show_ref, NULL);
|
for_each_ref(show_ref, NULL);
|
||||||
if (capabilities_to_send)
|
if (!sent_capabilities)
|
||||||
show_ref("capabilities^{}", null_sha1, 0, NULL);
|
show_ref("capabilities^{}", null_sha1, 0, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -135,11 +139,61 @@ static struct command *commands;
|
|||||||
static const char pre_receive_hook[] = "hooks/pre-receive";
|
static const char pre_receive_hook[] = "hooks/pre-receive";
|
||||||
static const char post_receive_hook[] = "hooks/post-receive";
|
static const char post_receive_hook[] = "hooks/post-receive";
|
||||||
|
|
||||||
|
static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
||||||
|
static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
||||||
|
|
||||||
|
static void report_message(const char *prefix, const char *err, va_list params)
|
||||||
|
{
|
||||||
|
int sz = strlen(prefix);
|
||||||
|
char msg[4096];
|
||||||
|
|
||||||
|
strncpy(msg, prefix, sz);
|
||||||
|
sz += vsnprintf(msg + sz, sizeof(msg) - sz, err, params);
|
||||||
|
if (sz > (sizeof(msg) - 1))
|
||||||
|
sz = sizeof(msg) - 1;
|
||||||
|
msg[sz++] = '\n';
|
||||||
|
|
||||||
|
if (use_sideband)
|
||||||
|
send_sideband(1, 2, msg, sz, use_sideband);
|
||||||
|
else
|
||||||
|
xwrite(2, msg, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rp_warning(const char *err, ...)
|
||||||
|
{
|
||||||
|
va_list params;
|
||||||
|
va_start(params, err);
|
||||||
|
report_message("warning: ", err, params);
|
||||||
|
va_end(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rp_error(const char *err, ...)
|
||||||
|
{
|
||||||
|
va_list params;
|
||||||
|
va_start(params, err);
|
||||||
|
report_message("error: ", err, params);
|
||||||
|
va_end(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int copy_to_sideband(int in, int out, void *arg)
|
||||||
|
{
|
||||||
|
char data[128];
|
||||||
|
while (1) {
|
||||||
|
ssize_t sz = xread(in, data, sizeof(data));
|
||||||
|
if (sz <= 0)
|
||||||
|
break;
|
||||||
|
send_sideband(1, 2, data, sz, use_sideband);
|
||||||
|
}
|
||||||
|
close(in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int run_receive_hook(const char *hook_name)
|
static int run_receive_hook(const char *hook_name)
|
||||||
{
|
{
|
||||||
static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
|
static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
|
||||||
struct command *cmd;
|
struct command *cmd;
|
||||||
struct child_process proc;
|
struct child_process proc;
|
||||||
|
struct async muxer;
|
||||||
const char *argv[2];
|
const char *argv[2];
|
||||||
int have_input = 0, code;
|
int have_input = 0, code;
|
||||||
|
|
||||||
@ -159,9 +213,23 @@ static int run_receive_hook(const char *hook_name)
|
|||||||
proc.in = -1;
|
proc.in = -1;
|
||||||
proc.stdout_to_stderr = 1;
|
proc.stdout_to_stderr = 1;
|
||||||
|
|
||||||
|
if (use_sideband) {
|
||||||
|
memset(&muxer, 0, sizeof(muxer));
|
||||||
|
muxer.proc = copy_to_sideband;
|
||||||
|
muxer.in = -1;
|
||||||
|
code = start_async(&muxer);
|
||||||
|
if (code)
|
||||||
|
return code;
|
||||||
|
proc.err = muxer.in;
|
||||||
|
}
|
||||||
|
|
||||||
code = start_command(&proc);
|
code = start_command(&proc);
|
||||||
if (code)
|
if (code) {
|
||||||
|
if (use_sideband)
|
||||||
|
finish_async(&muxer);
|
||||||
return code;
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||||
if (!cmd->error_string) {
|
if (!cmd->error_string) {
|
||||||
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
|
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
|
||||||
@ -173,6 +241,8 @@ static int run_receive_hook(const char *hook_name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(proc.in);
|
close(proc.in);
|
||||||
|
if (use_sideband)
|
||||||
|
finish_async(&muxer);
|
||||||
return finish_command(&proc);
|
return finish_command(&proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +250,8 @@ static int run_update_hook(struct command *cmd)
|
|||||||
{
|
{
|
||||||
static const char update_hook[] = "hooks/update";
|
static const char update_hook[] = "hooks/update";
|
||||||
const char *argv[5];
|
const char *argv[5];
|
||||||
|
struct child_process proc;
|
||||||
|
int code;
|
||||||
|
|
||||||
if (access(update_hook, X_OK) < 0)
|
if (access(update_hook, X_OK) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -190,8 +262,18 @@ static int run_update_hook(struct command *cmd)
|
|||||||
argv[3] = sha1_to_hex(cmd->new_sha1);
|
argv[3] = sha1_to_hex(cmd->new_sha1);
|
||||||
argv[4] = NULL;
|
argv[4] = NULL;
|
||||||
|
|
||||||
return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
|
memset(&proc, 0, sizeof(proc));
|
||||||
RUN_COMMAND_STDOUT_TO_STDERR);
|
proc.no_stdin = 1;
|
||||||
|
proc.stdout_to_stderr = 1;
|
||||||
|
proc.err = use_sideband ? -1 : 0;
|
||||||
|
proc.argv = argv;
|
||||||
|
|
||||||
|
code = start_command(&proc);
|
||||||
|
if (code)
|
||||||
|
return code;
|
||||||
|
if (use_sideband)
|
||||||
|
copy_to_sideband(proc.err, -1, NULL);
|
||||||
|
return finish_command(&proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_ref_checked_out(const char *ref)
|
static int is_ref_checked_out(const char *ref)
|
||||||
@ -224,7 +306,7 @@ static void refuse_unconfigured_deny(void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
|
for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
|
||||||
error("%s", refuse_unconfigured_deny_msg[i]);
|
rp_error("%s", refuse_unconfigured_deny_msg[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *refuse_unconfigured_deny_delete_current_msg[] = {
|
static char *refuse_unconfigured_deny_delete_current_msg[] = {
|
||||||
@ -244,7 +326,7 @@ static void refuse_unconfigured_deny_delete_current(void)
|
|||||||
for (i = 0;
|
for (i = 0;
|
||||||
i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
|
i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
|
||||||
i++)
|
i++)
|
||||||
error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
|
rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *update(struct command *cmd)
|
static const char *update(struct command *cmd)
|
||||||
@ -256,7 +338,7 @@ static const char *update(struct command *cmd)
|
|||||||
|
|
||||||
/* only refs/... are allowed */
|
/* only refs/... are allowed */
|
||||||
if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
|
if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
|
||||||
error("refusing to create funny ref '%s' remotely", name);
|
rp_error("refusing to create funny ref '%s' remotely", name);
|
||||||
return "funny refname";
|
return "funny refname";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,11 +347,11 @@ static const char *update(struct command *cmd)
|
|||||||
case DENY_IGNORE:
|
case DENY_IGNORE:
|
||||||
break;
|
break;
|
||||||
case DENY_WARN:
|
case DENY_WARN:
|
||||||
warning("updating the current branch");
|
rp_warning("updating the current branch");
|
||||||
break;
|
break;
|
||||||
case DENY_REFUSE:
|
case DENY_REFUSE:
|
||||||
case DENY_UNCONFIGURED:
|
case DENY_UNCONFIGURED:
|
||||||
error("refusing to update checked out branch: %s", name);
|
rp_error("refusing to update checked out branch: %s", name);
|
||||||
if (deny_current_branch == DENY_UNCONFIGURED)
|
if (deny_current_branch == DENY_UNCONFIGURED)
|
||||||
refuse_unconfigured_deny();
|
refuse_unconfigured_deny();
|
||||||
return "branch is currently checked out";
|
return "branch is currently checked out";
|
||||||
@ -284,7 +366,7 @@ static const char *update(struct command *cmd)
|
|||||||
|
|
||||||
if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
|
if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
|
||||||
if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
|
if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
|
||||||
error("denying ref deletion for %s", name);
|
rp_error("denying ref deletion for %s", name);
|
||||||
return "deletion prohibited";
|
return "deletion prohibited";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,13 +375,13 @@ static const char *update(struct command *cmd)
|
|||||||
case DENY_IGNORE:
|
case DENY_IGNORE:
|
||||||
break;
|
break;
|
||||||
case DENY_WARN:
|
case DENY_WARN:
|
||||||
warning("deleting the current branch");
|
rp_warning("deleting the current branch");
|
||||||
break;
|
break;
|
||||||
case DENY_REFUSE:
|
case DENY_REFUSE:
|
||||||
case DENY_UNCONFIGURED:
|
case DENY_UNCONFIGURED:
|
||||||
if (deny_delete_current == DENY_UNCONFIGURED)
|
if (deny_delete_current == DENY_UNCONFIGURED)
|
||||||
refuse_unconfigured_deny_delete_current();
|
refuse_unconfigured_deny_delete_current();
|
||||||
error("refusing to delete the current branch: %s", name);
|
rp_error("refusing to delete the current branch: %s", name);
|
||||||
return "deletion of the current branch prohibited";
|
return "deletion of the current branch prohibited";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,23 +411,23 @@ static const char *update(struct command *cmd)
|
|||||||
break;
|
break;
|
||||||
free_commit_list(bases);
|
free_commit_list(bases);
|
||||||
if (!ent) {
|
if (!ent) {
|
||||||
error("denying non-fast-forward %s"
|
rp_error("denying non-fast-forward %s"
|
||||||
" (you should pull first)", name);
|
" (you should pull first)", name);
|
||||||
return "non-fast-forward";
|
return "non-fast-forward";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (run_update_hook(cmd)) {
|
if (run_update_hook(cmd)) {
|
||||||
error("hook declined to update %s", name);
|
rp_error("hook declined to update %s", name);
|
||||||
return "hook declined";
|
return "hook declined";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_null_sha1(new_sha1)) {
|
if (is_null_sha1(new_sha1)) {
|
||||||
if (!parse_object(old_sha1)) {
|
if (!parse_object(old_sha1)) {
|
||||||
warning ("Allowing deletion of corrupt ref.");
|
rp_warning("Allowing deletion of corrupt ref.");
|
||||||
old_sha1 = NULL;
|
old_sha1 = NULL;
|
||||||
}
|
}
|
||||||
if (delete_ref(name, old_sha1, 0)) {
|
if (delete_ref(name, old_sha1, 0)) {
|
||||||
error("failed to delete %s", name);
|
rp_error("failed to delete %s", name);
|
||||||
return "failed to delete";
|
return "failed to delete";
|
||||||
}
|
}
|
||||||
return NULL; /* good */
|
return NULL; /* good */
|
||||||
@ -353,7 +435,7 @@ static const char *update(struct command *cmd)
|
|||||||
else {
|
else {
|
||||||
lock = lock_any_ref_for_update(name, old_sha1, 0);
|
lock = lock_any_ref_for_update(name, old_sha1, 0);
|
||||||
if (!lock) {
|
if (!lock) {
|
||||||
error("failed to lock %s", name);
|
rp_error("failed to lock %s", name);
|
||||||
return "failed to lock";
|
return "failed to lock";
|
||||||
}
|
}
|
||||||
if (write_ref_sha1(lock, new_sha1, "push")) {
|
if (write_ref_sha1(lock, new_sha1, "push")) {
|
||||||
@ -368,8 +450,9 @@ static char update_post_hook[] = "hooks/post-update";
|
|||||||
static void run_update_post_hook(struct command *cmd)
|
static void run_update_post_hook(struct command *cmd)
|
||||||
{
|
{
|
||||||
struct command *cmd_p;
|
struct command *cmd_p;
|
||||||
int argc, status;
|
int argc;
|
||||||
const char **argv;
|
const char **argv;
|
||||||
|
struct child_process proc;
|
||||||
|
|
||||||
for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
|
for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
|
||||||
if (cmd_p->error_string)
|
if (cmd_p->error_string)
|
||||||
@ -391,8 +474,18 @@ static void run_update_post_hook(struct command *cmd)
|
|||||||
argc++;
|
argc++;
|
||||||
}
|
}
|
||||||
argv[argc] = NULL;
|
argv[argc] = NULL;
|
||||||
status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
|
|
||||||
| RUN_COMMAND_STDOUT_TO_STDERR);
|
memset(&proc, 0, sizeof(proc));
|
||||||
|
proc.no_stdin = 1;
|
||||||
|
proc.stdout_to_stderr = 1;
|
||||||
|
proc.err = use_sideband ? -1 : 0;
|
||||||
|
proc.argv = argv;
|
||||||
|
|
||||||
|
if (!start_command(&proc)) {
|
||||||
|
if (use_sideband)
|
||||||
|
copy_to_sideband(proc.err, -1, NULL);
|
||||||
|
finish_command(&proc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute_commands(const char *unpacker_error)
|
static void execute_commands(const char *unpacker_error)
|
||||||
@ -452,6 +545,8 @@ static void read_head_info(void)
|
|||||||
if (reflen + 82 < len) {
|
if (reflen + 82 < len) {
|
||||||
if (strstr(refname + reflen + 1, "report-status"))
|
if (strstr(refname + reflen + 1, "report-status"))
|
||||||
report_status = 1;
|
report_status = 1;
|
||||||
|
if (strstr(refname + reflen + 1, "side-band-64k"))
|
||||||
|
use_sideband = LARGE_PACKET_MAX;
|
||||||
}
|
}
|
||||||
cmd = xmalloc(sizeof(struct command) + len - 80);
|
cmd = xmalloc(sizeof(struct command) + len - 80);
|
||||||
hashcpy(cmd->old_sha1, old_sha1);
|
hashcpy(cmd->old_sha1, old_sha1);
|
||||||
@ -551,17 +646,25 @@ static const char *unpack(void)
|
|||||||
static void report(const char *unpack_status)
|
static void report(const char *unpack_status)
|
||||||
{
|
{
|
||||||
struct command *cmd;
|
struct command *cmd;
|
||||||
packet_write(1, "unpack %s\n",
|
struct strbuf buf = STRBUF_INIT;
|
||||||
unpack_status ? unpack_status : "ok");
|
|
||||||
|
packet_buf_write(&buf, "unpack %s\n",
|
||||||
|
unpack_status ? unpack_status : "ok");
|
||||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||||
if (!cmd->error_string)
|
if (!cmd->error_string)
|
||||||
packet_write(1, "ok %s\n",
|
packet_buf_write(&buf, "ok %s\n",
|
||||||
cmd->ref_name);
|
cmd->ref_name);
|
||||||
else
|
else
|
||||||
packet_write(1, "ng %s %s\n",
|
packet_buf_write(&buf, "ng %s %s\n",
|
||||||
cmd->ref_name, cmd->error_string);
|
cmd->ref_name, cmd->error_string);
|
||||||
}
|
}
|
||||||
packet_flush(1);
|
packet_buf_flush(&buf);
|
||||||
|
|
||||||
|
if (use_sideband)
|
||||||
|
send_sideband(1, 1, buf.buf, buf.len, use_sideband);
|
||||||
|
else
|
||||||
|
safe_write(1, buf.buf, buf.len);
|
||||||
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int delete_only(struct command *cmd)
|
static int delete_only(struct command *cmd)
|
||||||
@ -658,10 +761,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
|
|||||||
else if (0 <= receive_unpack_limit)
|
else if (0 <= receive_unpack_limit)
|
||||||
unpack_limit = receive_unpack_limit;
|
unpack_limit = receive_unpack_limit;
|
||||||
|
|
||||||
capabilities_to_send = (prefer_ofs_delta) ?
|
|
||||||
" report-status delete-refs ofs-delta " :
|
|
||||||
" report-status delete-refs ";
|
|
||||||
|
|
||||||
if (advertise_refs || !stateless_rpc) {
|
if (advertise_refs || !stateless_rpc) {
|
||||||
add_alternate_refs();
|
add_alternate_refs();
|
||||||
write_head_info();
|
write_head_info();
|
||||||
@ -695,5 +794,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
|
|||||||
if (auto_update_server_info)
|
if (auto_update_server_info)
|
||||||
update_server_info(0);
|
update_server_info(0);
|
||||||
}
|
}
|
||||||
|
if (use_sideband)
|
||||||
|
packet_flush(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -372,6 +372,14 @@ static void print_helper_status(struct ref *ref)
|
|||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sideband_demux(int in, int out, void *data)
|
||||||
|
{
|
||||||
|
int *fd = data;
|
||||||
|
int ret = recv_sideband("send-pack", fd[0], out);
|
||||||
|
close(out);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int send_pack(struct send_pack_args *args,
|
int send_pack(struct send_pack_args *args,
|
||||||
int fd[], struct child_process *conn,
|
int fd[], struct child_process *conn,
|
||||||
struct ref *remote_refs,
|
struct ref *remote_refs,
|
||||||
@ -382,18 +390,22 @@ int send_pack(struct send_pack_args *args,
|
|||||||
struct strbuf req_buf = STRBUF_INIT;
|
struct strbuf req_buf = STRBUF_INIT;
|
||||||
struct ref *ref;
|
struct ref *ref;
|
||||||
int new_refs;
|
int new_refs;
|
||||||
int ask_for_status_report = 0;
|
|
||||||
int allow_deleting_refs = 0;
|
int allow_deleting_refs = 0;
|
||||||
int expect_status_report = 0;
|
int status_report = 0;
|
||||||
|
int use_sideband = 0;
|
||||||
|
unsigned cmds_sent = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct async demux;
|
||||||
|
|
||||||
/* Does the other end support the reporting? */
|
/* Does the other end support the reporting? */
|
||||||
if (server_supports("report-status"))
|
if (server_supports("report-status"))
|
||||||
ask_for_status_report = 1;
|
status_report = 1;
|
||||||
if (server_supports("delete-refs"))
|
if (server_supports("delete-refs"))
|
||||||
allow_deleting_refs = 1;
|
allow_deleting_refs = 1;
|
||||||
if (server_supports("ofs-delta"))
|
if (server_supports("ofs-delta"))
|
||||||
args->use_ofs_delta = 1;
|
args->use_ofs_delta = 1;
|
||||||
|
if (server_supports("side-band-64k"))
|
||||||
|
use_sideband = 1;
|
||||||
|
|
||||||
if (!remote_refs) {
|
if (!remote_refs) {
|
||||||
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
|
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
|
||||||
@ -426,28 +438,30 @@ int send_pack(struct send_pack_args *args,
|
|||||||
if (!ref->deletion)
|
if (!ref->deletion)
|
||||||
new_refs++;
|
new_refs++;
|
||||||
|
|
||||||
if (!args->dry_run) {
|
if (args->dry_run) {
|
||||||
|
ref->status = REF_STATUS_OK;
|
||||||
|
} else {
|
||||||
char *old_hex = sha1_to_hex(ref->old_sha1);
|
char *old_hex = sha1_to_hex(ref->old_sha1);
|
||||||
char *new_hex = sha1_to_hex(ref->new_sha1);
|
char *new_hex = sha1_to_hex(ref->new_sha1);
|
||||||
|
|
||||||
if (ask_for_status_report) {
|
if (!cmds_sent && (status_report || use_sideband)) {
|
||||||
packet_buf_write(&req_buf, "%s %s %s%c%s",
|
packet_buf_write(&req_buf, "%s %s %s%c%s%s",
|
||||||
old_hex, new_hex, ref->name, 0,
|
old_hex, new_hex, ref->name, 0,
|
||||||
"report-status");
|
status_report ? " report-status" : "",
|
||||||
ask_for_status_report = 0;
|
use_sideband ? " side-band-64k" : "");
|
||||||
expect_status_report = 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
packet_buf_write(&req_buf, "%s %s %s",
|
packet_buf_write(&req_buf, "%s %s %s",
|
||||||
old_hex, new_hex, ref->name);
|
old_hex, new_hex, ref->name);
|
||||||
|
ref->status = status_report ?
|
||||||
|
REF_STATUS_EXPECTING_REPORT :
|
||||||
|
REF_STATUS_OK;
|
||||||
|
cmds_sent++;
|
||||||
}
|
}
|
||||||
ref->status = expect_status_report ?
|
|
||||||
REF_STATUS_EXPECTING_REPORT :
|
|
||||||
REF_STATUS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args->stateless_rpc) {
|
if (args->stateless_rpc) {
|
||||||
if (!args->dry_run) {
|
if (!args->dry_run && cmds_sent) {
|
||||||
packet_buf_flush(&req_buf);
|
packet_buf_flush(&req_buf);
|
||||||
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
|
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
|
||||||
}
|
}
|
||||||
@ -457,23 +471,43 @@ int send_pack(struct send_pack_args *args,
|
|||||||
}
|
}
|
||||||
strbuf_release(&req_buf);
|
strbuf_release(&req_buf);
|
||||||
|
|
||||||
if (new_refs && !args->dry_run) {
|
if (use_sideband && cmds_sent) {
|
||||||
|
memset(&demux, 0, sizeof(demux));
|
||||||
|
demux.proc = sideband_demux;
|
||||||
|
demux.data = fd;
|
||||||
|
demux.out = -1;
|
||||||
|
if (start_async(&demux))
|
||||||
|
die("receive-pack: unable to fork off sideband demultiplexer");
|
||||||
|
in = demux.out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_refs && cmds_sent) {
|
||||||
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
|
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
|
||||||
for (ref = remote_refs; ref; ref = ref->next)
|
for (ref = remote_refs; ref; ref = ref->next)
|
||||||
ref->status = REF_STATUS_NONE;
|
ref->status = REF_STATUS_NONE;
|
||||||
|
if (use_sideband)
|
||||||
|
finish_async(&demux);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args->stateless_rpc && !args->dry_run)
|
if (args->stateless_rpc && cmds_sent)
|
||||||
packet_flush(out);
|
packet_flush(out);
|
||||||
|
|
||||||
if (expect_status_report)
|
if (status_report && cmds_sent)
|
||||||
ret = receive_status(in, remote_refs);
|
ret = receive_status(in, remote_refs);
|
||||||
else
|
else
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (args->stateless_rpc)
|
if (args->stateless_rpc)
|
||||||
packet_flush(out);
|
packet_flush(out);
|
||||||
|
|
||||||
|
if (use_sideband && cmds_sent) {
|
||||||
|
if (finish_async(&demux)) {
|
||||||
|
error("error in sideband demultiplexer");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
close(demux.out);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
for (ref = remote_refs; ref; ref = ref->next) {
|
for (ref = remote_refs; ref; ref = ref->next) {
|
||||||
|
@ -241,7 +241,7 @@ struct filter_params {
|
|||||||
const char *cmd;
|
const char *cmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int filter_buffer(int fd, void *data)
|
static int filter_buffer(int in, int out, void *data)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Spawn cmd and feed the buffer contents through its stdin.
|
* Spawn cmd and feed the buffer contents through its stdin.
|
||||||
@ -255,7 +255,7 @@ static int filter_buffer(int fd, void *data)
|
|||||||
child_process.argv = argv;
|
child_process.argv = argv;
|
||||||
child_process.use_shell = 1;
|
child_process.use_shell = 1;
|
||||||
child_process.in = -1;
|
child_process.in = -1;
|
||||||
child_process.out = fd;
|
child_process.out = out;
|
||||||
|
|
||||||
if (start_command(&child_process))
|
if (start_command(&child_process))
|
||||||
return error("cannot fork to run external filter %s", params->cmd);
|
return error("cannot fork to run external filter %s", params->cmd);
|
||||||
@ -292,6 +292,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
|
|||||||
memset(&async, 0, sizeof(async));
|
memset(&async, 0, sizeof(async));
|
||||||
async.proc = filter_buffer;
|
async.proc = filter_buffer;
|
||||||
async.data = ¶ms;
|
async.data = ¶ms;
|
||||||
|
async.out = -1;
|
||||||
params.src = src;
|
params.src = src;
|
||||||
params.size = len;
|
params.size = len;
|
||||||
params.cmd = cmd;
|
params.cmd = cmd;
|
||||||
|
@ -184,13 +184,13 @@ static struct discovery* discover_refs(const char *service)
|
|||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_discovery(int fd, void *data)
|
static int write_discovery(int in, int out, void *data)
|
||||||
{
|
{
|
||||||
struct discovery *heads = data;
|
struct discovery *heads = data;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
if (write_in_full(fd, heads->buf, heads->len) != heads->len)
|
if (write_in_full(out, heads->buf, heads->len) != heads->len)
|
||||||
err = 1;
|
err = 1;
|
||||||
close(fd);
|
close(out);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,6 +202,7 @@ static struct ref *parse_git_refs(struct discovery *heads)
|
|||||||
memset(&async, 0, sizeof(async));
|
memset(&async, 0, sizeof(async));
|
||||||
async.proc = write_discovery;
|
async.proc = write_discovery;
|
||||||
async.data = heads;
|
async.data = heads;
|
||||||
|
async.out = -1;
|
||||||
|
|
||||||
if (start_async(&async))
|
if (start_async(&async))
|
||||||
die("cannot start thread to parse advertised refs");
|
die("cannot start thread to parse advertised refs");
|
||||||
|
@ -233,6 +233,9 @@ fail_pipe:
|
|||||||
else if (need_err) {
|
else if (need_err) {
|
||||||
dup2(fderr[1], 2);
|
dup2(fderr[1], 2);
|
||||||
close_pair(fderr);
|
close_pair(fderr);
|
||||||
|
} else if (cmd->err > 1) {
|
||||||
|
dup2(cmd->err, 2);
|
||||||
|
close(cmd->err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd->no_stdout)
|
if (cmd->no_stdout)
|
||||||
@ -325,6 +328,8 @@ fail_pipe:
|
|||||||
fherr = open("/dev/null", O_RDWR);
|
fherr = open("/dev/null", O_RDWR);
|
||||||
else if (need_err)
|
else if (need_err)
|
||||||
fherr = dup(fderr[1]);
|
fherr = dup(fderr[1]);
|
||||||
|
else if (cmd->err > 2)
|
||||||
|
fherr = dup(cmd->err);
|
||||||
|
|
||||||
if (cmd->no_stdout)
|
if (cmd->no_stdout)
|
||||||
fhout = open("/dev/null", O_RDWR);
|
fhout = open("/dev/null", O_RDWR);
|
||||||
@ -394,6 +399,8 @@ fail_pipe:
|
|||||||
|
|
||||||
if (need_err)
|
if (need_err)
|
||||||
close(fderr[1]);
|
close(fderr[1]);
|
||||||
|
else if (cmd->err)
|
||||||
|
close(cmd->err);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -444,17 +451,51 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
|
|||||||
static unsigned __stdcall run_thread(void *data)
|
static unsigned __stdcall run_thread(void *data)
|
||||||
{
|
{
|
||||||
struct async *async = data;
|
struct async *async = data;
|
||||||
return async->proc(async->fd_for_proc, async->data);
|
return async->proc(async->proc_in, async->proc_out, async->data);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int start_async(struct async *async)
|
int start_async(struct async *async)
|
||||||
{
|
{
|
||||||
int pipe_out[2];
|
int need_in, need_out;
|
||||||
|
int fdin[2], fdout[2];
|
||||||
|
int proc_in, proc_out;
|
||||||
|
|
||||||
if (pipe(pipe_out) < 0)
|
need_in = async->in < 0;
|
||||||
return error("cannot create pipe: %s", strerror(errno));
|
if (need_in) {
|
||||||
async->out = pipe_out[0];
|
if (pipe(fdin) < 0) {
|
||||||
|
if (async->out > 0)
|
||||||
|
close(async->out);
|
||||||
|
return error("cannot create pipe: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
async->in = fdin[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
need_out = async->out < 0;
|
||||||
|
if (need_out) {
|
||||||
|
if (pipe(fdout) < 0) {
|
||||||
|
if (need_in)
|
||||||
|
close_pair(fdin);
|
||||||
|
else if (async->in)
|
||||||
|
close(async->in);
|
||||||
|
return error("cannot create pipe: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
async->out = fdout[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_in)
|
||||||
|
proc_in = fdin[0];
|
||||||
|
else if (async->in)
|
||||||
|
proc_in = async->in;
|
||||||
|
else
|
||||||
|
proc_in = -1;
|
||||||
|
|
||||||
|
if (need_out)
|
||||||
|
proc_out = fdout[1];
|
||||||
|
else if (async->out)
|
||||||
|
proc_out = async->out;
|
||||||
|
else
|
||||||
|
proc_out = -1;
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
/* Flush stdio before fork() to avoid cloning buffers */
|
/* Flush stdio before fork() to avoid cloning buffers */
|
||||||
@ -463,24 +504,47 @@ int start_async(struct async *async)
|
|||||||
async->pid = fork();
|
async->pid = fork();
|
||||||
if (async->pid < 0) {
|
if (async->pid < 0) {
|
||||||
error("fork (async) failed: %s", strerror(errno));
|
error("fork (async) failed: %s", strerror(errno));
|
||||||
close_pair(pipe_out);
|
goto error;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
if (!async->pid) {
|
if (!async->pid) {
|
||||||
close(pipe_out[0]);
|
if (need_in)
|
||||||
exit(!!async->proc(pipe_out[1], async->data));
|
close(fdin[1]);
|
||||||
|
if (need_out)
|
||||||
|
close(fdout[0]);
|
||||||
|
exit(!!async->proc(proc_in, proc_out, async->data));
|
||||||
}
|
}
|
||||||
close(pipe_out[1]);
|
|
||||||
|
if (need_in)
|
||||||
|
close(fdin[0]);
|
||||||
|
else if (async->in)
|
||||||
|
close(async->in);
|
||||||
|
|
||||||
|
if (need_out)
|
||||||
|
close(fdout[1]);
|
||||||
|
else if (async->out)
|
||||||
|
close(async->out);
|
||||||
#else
|
#else
|
||||||
async->fd_for_proc = pipe_out[1];
|
async->proc_in = proc_in;
|
||||||
|
async->proc_out = proc_out;
|
||||||
async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
|
async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
|
||||||
if (!async->tid) {
|
if (!async->tid) {
|
||||||
error("cannot create thread: %s", strerror(errno));
|
error("cannot create thread: %s", strerror(errno));
|
||||||
close_pair(pipe_out);
|
goto error;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (need_in)
|
||||||
|
close_pair(fdin);
|
||||||
|
else if (async->in)
|
||||||
|
close(async->in);
|
||||||
|
|
||||||
|
if (need_out)
|
||||||
|
close_pair(fdout);
|
||||||
|
else if (async->out)
|
||||||
|
close(async->out);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int finish_async(struct async *async)
|
int finish_async(struct async *async)
|
||||||
|
@ -18,7 +18,7 @@ struct child_process {
|
|||||||
* - Specify > 0 to set a channel to a particular FD as follows:
|
* - Specify > 0 to set a channel to a particular FD as follows:
|
||||||
* .in: a readable FD, becomes child's stdin
|
* .in: a readable FD, becomes child's stdin
|
||||||
* .out: a writable FD, becomes child's stdout/stderr
|
* .out: a writable FD, becomes child's stdout/stderr
|
||||||
* .err > 0 not supported
|
* .err: a writable FD, becomes child's stderr
|
||||||
* The specified FD is closed by start_command(), even in case
|
* The specified FD is closed by start_command(), even in case
|
||||||
* of errors!
|
* of errors!
|
||||||
*/
|
*/
|
||||||
@ -66,17 +66,20 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
|
|||||||
*/
|
*/
|
||||||
struct async {
|
struct async {
|
||||||
/*
|
/*
|
||||||
* proc writes to fd and closes it;
|
* proc reads from in; closes it before return
|
||||||
|
* proc writes to out; closes it before return
|
||||||
* returns 0 on success, non-zero on failure
|
* returns 0 on success, non-zero on failure
|
||||||
*/
|
*/
|
||||||
int (*proc)(int fd, void *data);
|
int (*proc)(int in, int out, void *data);
|
||||||
void *data;
|
void *data;
|
||||||
|
int in; /* caller writes here and closes it */
|
||||||
int out; /* caller reads from here and closes it */
|
int out; /* caller reads from here and closes it */
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
#else
|
#else
|
||||||
HANDLE tid;
|
HANDLE tid;
|
||||||
int fd_for_proc;
|
int proc_in;
|
||||||
|
int proc_out;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,23 +17,22 @@ test_expect_success setup '
|
|||||||
commit1=$(echo modify | git commit-tree $tree1 -p $commit0) &&
|
commit1=$(echo modify | git commit-tree $tree1 -p $commit0) &&
|
||||||
git update-ref refs/heads/master $commit0 &&
|
git update-ref refs/heads/master $commit0 &&
|
||||||
git update-ref refs/heads/tofail $commit1 &&
|
git update-ref refs/heads/tofail $commit1 &&
|
||||||
git clone ./. victim &&
|
git clone --bare ./. victim.git &&
|
||||||
GIT_DIR=victim/.git git config receive.denyCurrentBranch warn &&
|
GIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&
|
||||||
GIT_DIR=victim/.git git update-ref refs/heads/tofail $commit1 &&
|
|
||||||
git update-ref refs/heads/master $commit1 &&
|
git update-ref refs/heads/master $commit1 &&
|
||||||
git update-ref refs/heads/tofail $commit0
|
git update-ref refs/heads/tofail $commit0
|
||||||
'
|
'
|
||||||
|
|
||||||
cat >victim/.git/hooks/pre-receive <<'EOF'
|
cat >victim.git/hooks/pre-receive <<'EOF'
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
printf %s "$@" >>$GIT_DIR/pre-receive.args
|
printf %s "$@" >>$GIT_DIR/pre-receive.args
|
||||||
cat - >$GIT_DIR/pre-receive.stdin
|
cat - >$GIT_DIR/pre-receive.stdin
|
||||||
echo STDOUT pre-receive
|
echo STDOUT pre-receive
|
||||||
echo STDERR pre-receive >&2
|
echo STDERR pre-receive >&2
|
||||||
EOF
|
EOF
|
||||||
chmod u+x victim/.git/hooks/pre-receive
|
chmod u+x victim.git/hooks/pre-receive
|
||||||
|
|
||||||
cat >victim/.git/hooks/update <<'EOF'
|
cat >victim.git/hooks/update <<'EOF'
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
echo "$@" >>$GIT_DIR/update.args
|
echo "$@" >>$GIT_DIR/update.args
|
||||||
read x; printf %s "$x" >$GIT_DIR/update.stdin
|
read x; printf %s "$x" >$GIT_DIR/update.stdin
|
||||||
@ -41,77 +40,77 @@ echo STDOUT update $1
|
|||||||
echo STDERR update $1 >&2
|
echo STDERR update $1 >&2
|
||||||
test "$1" = refs/heads/master || exit
|
test "$1" = refs/heads/master || exit
|
||||||
EOF
|
EOF
|
||||||
chmod u+x victim/.git/hooks/update
|
chmod u+x victim.git/hooks/update
|
||||||
|
|
||||||
cat >victim/.git/hooks/post-receive <<'EOF'
|
cat >victim.git/hooks/post-receive <<'EOF'
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
printf %s "$@" >>$GIT_DIR/post-receive.args
|
printf %s "$@" >>$GIT_DIR/post-receive.args
|
||||||
cat - >$GIT_DIR/post-receive.stdin
|
cat - >$GIT_DIR/post-receive.stdin
|
||||||
echo STDOUT post-receive
|
echo STDOUT post-receive
|
||||||
echo STDERR post-receive >&2
|
echo STDERR post-receive >&2
|
||||||
EOF
|
EOF
|
||||||
chmod u+x victim/.git/hooks/post-receive
|
chmod u+x victim.git/hooks/post-receive
|
||||||
|
|
||||||
cat >victim/.git/hooks/post-update <<'EOF'
|
cat >victim.git/hooks/post-update <<'EOF'
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
echo "$@" >>$GIT_DIR/post-update.args
|
echo "$@" >>$GIT_DIR/post-update.args
|
||||||
read x; printf %s "$x" >$GIT_DIR/post-update.stdin
|
read x; printf %s "$x" >$GIT_DIR/post-update.stdin
|
||||||
echo STDOUT post-update
|
echo STDOUT post-update
|
||||||
echo STDERR post-update >&2
|
echo STDERR post-update >&2
|
||||||
EOF
|
EOF
|
||||||
chmod u+x victim/.git/hooks/post-update
|
chmod u+x victim.git/hooks/post-update
|
||||||
|
|
||||||
test_expect_success push '
|
test_expect_success push '
|
||||||
test_must_fail git send-pack --force ./victim/.git \
|
test_must_fail git send-pack --force ./victim.git \
|
||||||
master tofail >send.out 2>send.err
|
master tofail >send.out 2>send.err
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'updated as expected' '
|
test_expect_success 'updated as expected' '
|
||||||
test $(GIT_DIR=victim/.git git rev-parse master) = $commit1 &&
|
test $(GIT_DIR=victim.git git rev-parse master) = $commit1 &&
|
||||||
test $(GIT_DIR=victim/.git git rev-parse tofail) = $commit1
|
test $(GIT_DIR=victim.git git rev-parse tofail) = $commit1
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'hooks ran' '
|
test_expect_success 'hooks ran' '
|
||||||
test -f victim/.git/pre-receive.args &&
|
test -f victim.git/pre-receive.args &&
|
||||||
test -f victim/.git/pre-receive.stdin &&
|
test -f victim.git/pre-receive.stdin &&
|
||||||
test -f victim/.git/update.args &&
|
test -f victim.git/update.args &&
|
||||||
test -f victim/.git/update.stdin &&
|
test -f victim.git/update.stdin &&
|
||||||
test -f victim/.git/post-receive.args &&
|
test -f victim.git/post-receive.args &&
|
||||||
test -f victim/.git/post-receive.stdin &&
|
test -f victim.git/post-receive.stdin &&
|
||||||
test -f victim/.git/post-update.args &&
|
test -f victim.git/post-update.args &&
|
||||||
test -f victim/.git/post-update.stdin
|
test -f victim.git/post-update.stdin
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'pre-receive hook input' '
|
test_expect_success 'pre-receive hook input' '
|
||||||
(echo $commit0 $commit1 refs/heads/master;
|
(echo $commit0 $commit1 refs/heads/master;
|
||||||
echo $commit1 $commit0 refs/heads/tofail
|
echo $commit1 $commit0 refs/heads/tofail
|
||||||
) | test_cmp - victim/.git/pre-receive.stdin
|
) | test_cmp - victim.git/pre-receive.stdin
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'update hook arguments' '
|
test_expect_success 'update hook arguments' '
|
||||||
(echo refs/heads/master $commit0 $commit1;
|
(echo refs/heads/master $commit0 $commit1;
|
||||||
echo refs/heads/tofail $commit1 $commit0
|
echo refs/heads/tofail $commit1 $commit0
|
||||||
) | test_cmp - victim/.git/update.args
|
) | test_cmp - victim.git/update.args
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'post-receive hook input' '
|
test_expect_success 'post-receive hook input' '
|
||||||
echo $commit0 $commit1 refs/heads/master |
|
echo $commit0 $commit1 refs/heads/master |
|
||||||
test_cmp - victim/.git/post-receive.stdin
|
test_cmp - victim.git/post-receive.stdin
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'post-update hook arguments' '
|
test_expect_success 'post-update hook arguments' '
|
||||||
echo refs/heads/master |
|
echo refs/heads/master |
|
||||||
test_cmp - victim/.git/post-update.args
|
test_cmp - victim.git/post-update.args
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'all hook stdin is /dev/null' '
|
test_expect_success 'all hook stdin is /dev/null' '
|
||||||
! test -s victim/.git/update.stdin &&
|
! test -s victim.git/update.stdin &&
|
||||||
! test -s victim/.git/post-update.stdin
|
! test -s victim.git/post-update.stdin
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'all *-receive hook args are empty' '
|
test_expect_success 'all *-receive hook args are empty' '
|
||||||
! test -s victim/.git/pre-receive.args &&
|
! test -s victim.git/pre-receive.args &&
|
||||||
! test -s victim/.git/post-receive.args
|
! test -s victim.git/post-receive.args
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'send-pack produced no output' '
|
test_expect_success 'send-pack produced no output' '
|
||||||
@ -119,20 +118,21 @@ test_expect_success 'send-pack produced no output' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
cat <<EOF >expect
|
cat <<EOF >expect
|
||||||
STDOUT pre-receive
|
remote: STDOUT pre-receive
|
||||||
STDERR pre-receive
|
remote: STDERR pre-receive
|
||||||
STDOUT update refs/heads/master
|
remote: STDOUT update refs/heads/master
|
||||||
STDERR update refs/heads/master
|
remote: STDERR update refs/heads/master
|
||||||
STDOUT update refs/heads/tofail
|
remote: STDOUT update refs/heads/tofail
|
||||||
STDERR update refs/heads/tofail
|
remote: STDERR update refs/heads/tofail
|
||||||
STDOUT post-receive
|
remote: error: hook declined to update refs/heads/tofail
|
||||||
STDERR post-receive
|
remote: STDOUT post-receive
|
||||||
STDOUT post-update
|
remote: STDERR post-receive
|
||||||
STDERR post-update
|
remote: STDOUT post-update
|
||||||
|
remote: STDERR post-update
|
||||||
EOF
|
EOF
|
||||||
test_expect_success 'send-pack stderr contains hook messages' '
|
test_expect_success 'send-pack stderr contains hook messages' '
|
||||||
grep ^STD send.err >actual &&
|
grep ^remote: send.err | sed "s/ *\$//" >actual &&
|
||||||
test_cmp - actual <expect
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
@ -105,12 +105,12 @@ static void show_edge(struct commit *commit)
|
|||||||
fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
|
fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_rev_list(int fd, void *create_full_pack)
|
static int do_rev_list(int in, int out, void *create_full_pack)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct rev_info revs;
|
struct rev_info revs;
|
||||||
|
|
||||||
pack_pipe = xfdopen(fd, "w");
|
pack_pipe = xfdopen(out, "w");
|
||||||
init_revisions(&revs, NULL);
|
init_revisions(&revs, NULL);
|
||||||
revs.tag_objects = 1;
|
revs.tag_objects = 1;
|
||||||
revs.tree_objects = 1;
|
revs.tree_objects = 1;
|
||||||
@ -162,8 +162,9 @@ static void create_pack_file(void)
|
|||||||
int arg = 0;
|
int arg = 0;
|
||||||
|
|
||||||
if (shallow_nr) {
|
if (shallow_nr) {
|
||||||
|
memset(&rev_list, 0, sizeof(rev_list));
|
||||||
rev_list.proc = do_rev_list;
|
rev_list.proc = do_rev_list;
|
||||||
rev_list.data = 0;
|
rev_list.out = -1;
|
||||||
if (start_async(&rev_list))
|
if (start_async(&rev_list))
|
||||||
die("git upload-pack: unable to fork git-rev-list");
|
die("git upload-pack: unable to fork git-rev-list");
|
||||||
argv[arg++] = "pack-objects";
|
argv[arg++] = "pack-objects";
|
||||||
|
Loading…
Reference in New Issue
Block a user