Code

refactor run_receive_hook()
authorJunio C Hamano <gitster@pobox.com>
Thu, 8 Sep 2011 19:17:09 +0000 (12:17 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 12 Sep 2011 23:40:06 +0000 (16:40 -0700)
Running a hook has to make complex set-up to establish web of
communication between child process and multiplexer, which is common
regardless of what kind of data is fed to the hook. Refactor the parts
that is specific to the data fed to the particular set of hooks from the
part that runs the hook, so that the code can be reused to drive hooks
that take different kind of data.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/receive-pack.c

index ae164da4d5a7b7a2c87937ba0983126586f1e646..af429e101777f1c5df09734433278cfb075e978c 100644 (file)
@@ -205,21 +205,15 @@ static int copy_to_sideband(int in, int out, void *arg)
        return 0;
 }
 
-static int run_receive_hook(struct command *commands, const char *hook_name)
+typedef int (*feed_fn)(void *, const char **, size_t *);
+static int run_and_feed_hook(const char *hook_name, feed_fn feed, void *feed_state)
 {
-       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;
-
-       for (cmd = commands; !have_input && cmd; cmd = cmd->next) {
-               if (!cmd->error_string)
-                       have_input = 1;
-       }
+       int code;
 
-       if (!have_input || access(hook_name, X_OK) < 0)
+       if (access(hook_name, X_OK) < 0)
                return 0;
 
        argv[0] = hook_name;
@@ -247,15 +241,13 @@ static int run_receive_hook(struct command *commands, const char *hook_name)
                return code;
        }
 
-       for (cmd = commands; cmd; cmd = cmd->next) {
-               if (!cmd->error_string) {
-                       size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
-                               sha1_to_hex(cmd->old_sha1),
-                               sha1_to_hex(cmd->new_sha1),
-                               cmd->ref_name);
-                       if (write_in_full(proc.in, buf, n) != n)
-                               break;
-               }
+       while (1) {
+               const char *buf;
+               size_t n;
+               if (feed(feed_state, &buf, &n))
+                       break;
+               if (write_in_full(proc.in, buf, n) != n)
+                       break;
        }
        close(proc.in);
        if (use_sideband)
@@ -263,6 +255,47 @@ static int run_receive_hook(struct command *commands, const char *hook_name)
        return finish_command(&proc);
 }
 
+struct receive_hook_feed_state {
+       struct command *cmd;
+       struct strbuf buf;
+};
+
+static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
+{
+       struct receive_hook_feed_state *state = state_;
+       struct command *cmd = state->cmd;
+
+       while (cmd && cmd->error_string)
+               cmd = cmd->next;
+       if (!cmd)
+               return -1; /* EOF */
+       strbuf_reset(&state->buf);
+       strbuf_addf(&state->buf, "%s %s %s\n",
+                   sha1_to_hex(cmd->old_sha1), sha1_to_hex(cmd->new_sha1),
+                   cmd->ref_name);
+       state->cmd = cmd->next;
+       if (bufp) {
+               *bufp = state->buf.buf;
+               *sizep = state->buf.len;
+       }
+       return 0;
+}
+
+static int run_receive_hook(struct command *commands, const char *hook_name)
+{
+       struct receive_hook_feed_state state;
+       int status;
+
+       strbuf_init(&state.buf, 0);
+       state.cmd = commands;
+       if (feed_receive_hook(&state, NULL, NULL))
+               return 0;
+       state.cmd = commands;
+       status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
+       strbuf_release(&state.buf);
+       return status;
+}
+
 static int run_update_hook(struct command *cmd)
 {
        static const char update_hook[] = "hooks/update";