Skip to content

Commit

Permalink
Merge branch 'sp/maint-push-sideband' into sp/push-sideband
Browse files Browse the repository at this point in the history
* sp/maint-push-sideband:
  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
  Update git fsck --full short description to mention packs

Conflicts:
	run-command.c
  • Loading branch information
Junio C Hamano committed Feb 6, 2010
2 parents b0883aa + 6d525d3 commit 76d44c8
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 90 deletions.
52 changes: 41 additions & 11 deletions Documentation/technical/api-run-command.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ The functions above do the following:
`start_async`::

Run a function asynchronously. Takes a pointer to a `struct
async` that specifies the details and returns a pipe FD
from which the caller reads. See below for details.
async` that specifies the details and returns a set of pipe FDs
for communication with the function. See below for details.

`finish_async`::

Expand Down Expand Up @@ -135,7 +135,7 @@ stderr as follows:

.in: The FD must be readable; it becomes child's stdin.
.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
run the sub-process!
Expand Down Expand Up @@ -180,17 +180,47 @@ The caller:
struct async variable;
2. initializes .proc and .data;
3. calls start_async();
4. processes the data by reading from the fd in .out;
5. closes .out;
4. processes communicates with proc through .in and .out;
5. closes .in and .out;
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:

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
write the data that it produces. The function *must* close this
descriptor before it returns.
. in, out specifies a set of file descriptors to which the function
must read/write the data that it needs/produces. The function
*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
of struct async.
Expand All @@ -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:

. It cannot change the program's state (global variables, environment,
etc.) in a way that the caller notices; in other words, .out is the
only communication channel to the caller.
etc.) in a way that the caller notices; in other words, .in and .out
are the only communication channels to the caller.

. It must not change the program's state that the caller of the
facility also uses.
7 changes: 4 additions & 3 deletions builtin-fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -586,12 +586,12 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
return retval;
}

static int sideband_demux(int fd, void *data)
static int sideband_demux(int in, int out, void *data)
{
int *xd = data;

int ret = recv_sideband("fetch-pack", xd[0], fd);
close(fd);
int ret = recv_sideband("fetch-pack", xd[0], out);
close(out);
return ret;
}

Expand All @@ -613,6 +613,7 @@ static int get_pack(int xd[2], char **pack_lockfile)
*/
demux.proc = sideband_demux;
demux.data = xd;
demux.out = -1;
if (start_async(&demux))
die("fetch-pack: unable to fork off sideband"
" demultiplexer");
Expand Down
2 changes: 1 addition & 1 deletion builtin-fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ static struct option fsck_opts[] = {
OPT_BOOLEAN(0, "root", &show_root, "report root nodes"),
OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"),
OPT_BOOLEAN(0, "reflogs", &include_reflogs, "make reflogs head nodes (default)"),
OPT_BOOLEAN(0, "full", &check_full, "also consider alternate objects"),
OPT_BOOLEAN(0, "full", &check_full, "also consider packs and alternate objects"),
OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
"write dangling objects in .git/lost-found"),
Expand Down
111 changes: 88 additions & 23 deletions builtin-receive-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "pack.h"
#include "refs.h"
#include "pkt-line.h"
#include "sideband.h"
#include "run-command.h"
#include "exec_cmd.h"
#include "commit.h"
Expand All @@ -27,11 +28,12 @@ static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
static int report_status;
static int use_sideband;
static int prefer_ofs_delta = 1;
static int auto_update_server_info;
static int auto_gc = 1;
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)
{
Expand Down Expand Up @@ -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)
{
if (!capabilities_to_send)
if (sent_capabilities)
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
else
packet_write(1, "%s %s%c%s\n",
sha1_to_hex(sha1), path, 0, capabilities_to_send);
capabilities_to_send = NULL;
packet_write(1, "%s %s%c%s%s\n",
sha1_to_hex(sha1), path, 0,
" report-status delete-refs side-band-64k",
prefer_ofs_delta ? " ofs-delta" : "");
sent_capabilities = 1;
return 0;
}

static void write_head_info(void)
{
for_each_ref(show_ref, NULL);
if (capabilities_to_send)
if (!sent_capabilities)
show_ref("capabilities^{}", null_sha1, 0, NULL);

}
Expand All @@ -135,11 +139,25 @@ static struct command *commands;
static const char pre_receive_hook[] = "hooks/pre-receive";
static const char post_receive_hook[] = "hooks/post-receive";

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 char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
struct command *cmd;
struct child_process proc;
struct async muxer;
const char *argv[2];
int have_input = 0, code;

Expand All @@ -159,9 +177,23 @@ static int run_receive_hook(const char *hook_name)
proc.in = -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);
if (code)
if (code) {
if (use_sideband)
finish_async(&muxer);
return code;
}

for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string) {
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
Expand All @@ -173,13 +205,17 @@ static int run_receive_hook(const char *hook_name)
}
}
close(proc.in);
if (use_sideband)
finish_async(&muxer);
return finish_command(&proc);
}

static int run_update_hook(struct command *cmd)
{
static const char update_hook[] = "hooks/update";
const char *argv[5];
struct child_process proc;
int code;

if (access(update_hook, X_OK) < 0)
return 0;
Expand All @@ -190,8 +226,18 @@ static int run_update_hook(struct command *cmd)
argv[3] = sha1_to_hex(cmd->new_sha1);
argv[4] = NULL;

return 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;

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)
Expand Down Expand Up @@ -368,8 +414,9 @@ static char update_post_hook[] = "hooks/post-update";
static void run_update_post_hook(struct command *cmd)
{
struct command *cmd_p;
int argc, status;
int argc;
const char **argv;
struct child_process proc;

for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
if (cmd_p->error_string)
Expand All @@ -391,8 +438,18 @@ static void run_update_post_hook(struct command *cmd)
argc++;
}
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)
Expand Down Expand Up @@ -452,6 +509,8 @@ static void read_head_info(void)
if (reflen + 82 < len) {
if (strstr(refname + reflen + 1, "report-status"))
report_status = 1;
if (strstr(refname + reflen + 1, "side-band-64k"))
use_sideband = LARGE_PACKET_MAX;
}
cmd = xmalloc(sizeof(struct command) + len - 80);
hashcpy(cmd->old_sha1, old_sha1);
Expand Down Expand Up @@ -551,17 +610,25 @@ static const char *unpack(void)
static void report(const char *unpack_status)
{
struct command *cmd;
packet_write(1, "unpack %s\n",
unpack_status ? unpack_status : "ok");
struct strbuf buf = STRBUF_INIT;

packet_buf_write(&buf, "unpack %s\n",
unpack_status ? unpack_status : "ok");
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string)
packet_write(1, "ok %s\n",
cmd->ref_name);
packet_buf_write(&buf, "ok %s\n",
cmd->ref_name);
else
packet_write(1, "ng %s %s\n",
cmd->ref_name, cmd->error_string);
packet_buf_write(&buf, "ng %s %s\n",
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)
Expand Down Expand Up @@ -658,10 +725,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
else if (0 <= 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) {
add_alternate_refs();
write_head_info();
Expand Down Expand Up @@ -695,5 +758,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (auto_update_server_info)
update_server_info(0);
}
if (use_sideband)
packet_flush(1);
return 0;
}
Loading

0 comments on commit 76d44c8

Please sign in to comment.