aboutsummaryrefslogtreecommitdiff
path: root/run-command.c
diff options
context:
space:
mode:
authorEmily Shaffer <emilyshaffer@google.com>2025-12-26 14:23:31 +0200
committerJunio C Hamano <gitster@pobox.com>2025-12-28 14:02:07 +0900
commit5ab5872a53296b009cca43d412efd1a74ea4f149 (patch)
tree627ecb21a0ef8e2e5b0a33170f1e13a1b2d3d6a8 /run-command.c
parent857f047e40f796aa43c6e7c754d8a32ee64e4f4d (diff)
downloadgit-5ab5872a53296b009cca43d412efd1a74ea4f149.tar.xz
run-command: allow capturing of collated output
Some callers, for example server-side hooks which wish to relay hook output to clients across a transport, want to capture what would normally print to stderr and do something else with it. Allow that via a callback. By calling the callback regardless of whether there's output available, we allow clients to send e.g. a keepalive if necessary. Because we expose a strbuf, not a fd or FILE*, there's no need to create a temporary pipe or similar - we can just skip the print to stderr and instead hand it to the caller. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'run-command.c')
-rw-r--r--run-command.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/run-command.c b/run-command.c
index a608d37fb2..6b1e4a3453 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1595,7 +1595,10 @@ static void pp_cleanup(struct parallel_processes *pp,
* When get_next_task added messages to the buffer in its last
* iteration, the buffered output is non empty.
*/
- strbuf_write(&pp->buffered_output, stderr);
+ if (opts->consume_output)
+ opts->consume_output(&pp->buffered_output, opts->data);
+ else
+ strbuf_write(&pp->buffered_output, stderr);
strbuf_release(&pp->buffered_output);
sigchain_pop_common();
@@ -1734,13 +1737,17 @@ static void pp_buffer_stderr(struct parallel_processes *pp,
}
}
-static void pp_output(const struct parallel_processes *pp)
+static void pp_output(const struct parallel_processes *pp,
+ const struct run_process_parallel_opts *opts)
{
size_t i = pp->output_owner;
if (child_is_working(&pp->children[i]) &&
pp->children[i].err.len) {
- strbuf_write(&pp->children[i].err, stderr);
+ if (opts->consume_output)
+ opts->consume_output(&pp->children[i].err, opts->data);
+ else
+ strbuf_write(&pp->children[i].err, stderr);
strbuf_reset(&pp->children[i].err);
}
}
@@ -1788,11 +1795,15 @@ static int pp_collect_finished(struct parallel_processes *pp,
} else {
const size_t n = opts->processes;
- strbuf_write(&pp->children[i].err, stderr);
+ /* Output errors, then all other finished child processes */
+ if (opts->consume_output) {
+ opts->consume_output(&pp->children[i].err, opts->data);
+ opts->consume_output(&pp->buffered_output, opts->data);
+ } else {
+ strbuf_write(&pp->children[i].err, stderr);
+ strbuf_write(&pp->buffered_output, stderr);
+ }
strbuf_reset(&pp->children[i].err);
-
- /* Output all other finished child processes */
- strbuf_write(&pp->buffered_output, stderr);
strbuf_reset(&pp->buffered_output);
/*
@@ -1829,7 +1840,7 @@ static void pp_handle_child_IO(struct parallel_processes *pp,
pp->children[i].state = GIT_CP_WAIT_CLEANUP;
} else {
pp_buffer_stderr(pp, opts, output_timeout);
- pp_output(pp);
+ pp_output(pp, opts);
}
}
@@ -1852,6 +1863,9 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
"max:%"PRIuMAX,
(uintmax_t)opts->processes);
+ if (opts->ungroup && opts->consume_output)
+ BUG("ungroup and reading output are mutualy exclusive");
+
/*
* Child tasks might receive input via stdin, terminating early (or not), so
* ignore the default SIGPIPE which gets handled by each feed_pipe_fn which