Merge branch 'ab/hooks-regression-fix'

In Git 2.36 we revamped the way how hooks are invoked.  One change
that is end-user visible is that the output of a hook is no longer
directly connected to the standard output of "git" that spawns the
hook, which was noticed post release.  This is getting corrected.

* ab/hooks-regression-fix:
  hook API: fix v2.36.0 regression: hooks should be connected to a TTY
  run-command: add an "ungroup" option to run_process_parallel()
This commit is contained in:
Junio C Hamano
2022-06-13 15:53:41 -07:00
6 changed files with 155 additions and 29 deletions

View File

@ -1472,6 +1472,7 @@ enum child_state {
GIT_CP_WAIT_CLEANUP,
};
int run_processes_parallel_ungroup;
struct parallel_processes {
void *data;
@ -1495,6 +1496,7 @@ struct parallel_processes {
struct pollfd *pfd;
unsigned shutdown : 1;
unsigned ungroup : 1;
int output_owner;
struct strbuf buffered_output; /* of finished children */
@ -1538,7 +1540,7 @@ static void pp_init(struct parallel_processes *pp,
get_next_task_fn get_next_task,
start_failure_fn start_failure,
task_finished_fn task_finished,
void *data)
void *data, int ungroup)
{
int i;
@ -1560,15 +1562,21 @@ static void pp_init(struct parallel_processes *pp,
pp->nr_processes = 0;
pp->output_owner = 0;
pp->shutdown = 0;
pp->ungroup = ungroup;
CALLOC_ARRAY(pp->children, n);
CALLOC_ARRAY(pp->pfd, n);
if (pp->ungroup)
pp->pfd = NULL;
else
CALLOC_ARRAY(pp->pfd, n);
strbuf_init(&pp->buffered_output, 0);
for (i = 0; i < n; i++) {
strbuf_init(&pp->children[i].err, 0);
child_process_init(&pp->children[i].process);
pp->pfd[i].events = POLLIN | POLLHUP;
pp->pfd[i].fd = -1;
if (pp->pfd) {
pp->pfd[i].events = POLLIN | POLLHUP;
pp->pfd[i].fd = -1;
}
}
pp_for_signal = pp;
@ -1616,24 +1624,31 @@ static int pp_start_one(struct parallel_processes *pp)
BUG("bookkeeping is hard");
code = pp->get_next_task(&pp->children[i].process,
&pp->children[i].err,
pp->ungroup ? NULL : &pp->children[i].err,
pp->data,
&pp->children[i].data);
if (!code) {
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
if (!pp->ungroup) {
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
}
return 1;
}
pp->children[i].process.err = -1;
pp->children[i].process.stdout_to_stderr = 1;
if (!pp->ungroup) {
pp->children[i].process.err = -1;
pp->children[i].process.stdout_to_stderr = 1;
}
pp->children[i].process.no_stdin = 1;
if (start_command(&pp->children[i].process)) {
code = pp->start_failure(&pp->children[i].err,
code = pp->start_failure(pp->ungroup ? NULL :
&pp->children[i].err,
pp->data,
pp->children[i].data);
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
if (!pp->ungroup) {
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
}
if (code)
pp->shutdown = 1;
return code;
@ -1641,7 +1656,8 @@ static int pp_start_one(struct parallel_processes *pp)
pp->nr_processes++;
pp->children[i].state = GIT_CP_WORKING;
pp->pfd[i].fd = pp->children[i].process.err;
if (pp->pfd)
pp->pfd[i].fd = pp->children[i].process.err;
return 0;
}
@ -1675,6 +1691,7 @@ static void pp_buffer_stderr(struct parallel_processes *pp, int output_timeout)
static void pp_output(struct parallel_processes *pp)
{
int i = pp->output_owner;
if (pp->children[i].state == GIT_CP_WORKING &&
pp->children[i].err.len) {
strbuf_write(&pp->children[i].err, stderr);
@ -1697,7 +1714,7 @@ static int pp_collect_finished(struct parallel_processes *pp)
code = finish_command(&pp->children[i].process);
code = pp->task_finished(code,
code = pp->task_finished(code, pp->ungroup ? NULL :
&pp->children[i].err, pp->data,
pp->children[i].data);
@ -1708,10 +1725,13 @@ static int pp_collect_finished(struct parallel_processes *pp)
pp->nr_processes--;
pp->children[i].state = GIT_CP_FREE;
pp->pfd[i].fd = -1;
if (pp->pfd)
pp->pfd[i].fd = -1;
child_process_init(&pp->children[i].process);
if (i != pp->output_owner) {
if (pp->ungroup) {
; /* no strbuf_*() work to do here */
} else if (i != pp->output_owner) {
strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
strbuf_reset(&pp->children[i].err);
} else {
@ -1748,9 +1768,14 @@ int run_processes_parallel(int n,
int i, code;
int output_timeout = 100;
int spawn_cap = 4;
int ungroup = run_processes_parallel_ungroup;
struct parallel_processes pp;
pp_init(&pp, n, get_next_task, start_failure, task_finished, pp_cb);
/* unset for the next API user */
run_processes_parallel_ungroup = 0;
pp_init(&pp, n, get_next_task, start_failure, task_finished, pp_cb,
ungroup);
while (1) {
for (i = 0;
i < spawn_cap && !pp.shutdown &&
@ -1767,8 +1792,15 @@ int run_processes_parallel(int n,
}
if (!pp.nr_processes)
break;
pp_buffer_stderr(&pp, output_timeout);
pp_output(&pp);
if (ungroup) {
int i;
for (i = 0; i < pp.max_processes; i++)
pp.children[i].state = GIT_CP_WAIT_CLEANUP;
} else {
pp_buffer_stderr(&pp, output_timeout);
pp_output(&pp);
}
code = pp_collect_finished(&pp);
if (code) {
pp.shutdown = 1;