diff options
-rw-r--r-- | run-command.c | 23 | ||||
-rw-r--r-- | run-command.h | 13 | ||||
-rw-r--r-- | submodule.c | 4 | ||||
-rw-r--r-- | trailer.c | 18 | ||||
-rw-r--r-- | wt-status.c | 10 |
5 files changed, 44 insertions, 24 deletions
diff --git a/run-command.c b/run-command.c index 3afb124c79..aad03ab705 100644 --- a/run-command.c +++ b/run-command.c @@ -557,7 +557,12 @@ int finish_command(struct child_process *cmd) int run_command(struct child_process *cmd) { - int code = start_command(cmd); + int code; + + if (cmd->out < 0 || cmd->err < 0) + die("BUG: run_command with a pipe can cause deadlock"); + + code = start_command(cmd); if (code) return code; return finish_command(cmd); @@ -829,3 +834,19 @@ int run_hook_le(const char *const *env, const char *name, ...) return ret; } + +int capture_command(struct child_process *cmd, struct strbuf *buf, size_t hint) +{ + cmd->out = -1; + if (start_command(cmd) < 0) + return -1; + + if (strbuf_read(buf, cmd->out, hint) < 0) { + close(cmd->out); + finish_command(cmd); /* throw away exit code */ + return -1; + } + + close(cmd->out); + return finish_command(cmd); +} diff --git a/run-command.h b/run-command.h index d6868dc8c8..263b9662ad 100644 --- a/run-command.h +++ b/run-command.h @@ -71,6 +71,19 @@ int run_command_v_opt(const char **argv, int opt); */ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env); +/** + * Execute the given command, capturing its stdout in the given strbuf. + * Returns -1 if starting the command fails or reading fails, and otherwise + * returns the exit code of the command. The output collected in the + * buffer is kept even if the command returns a non-zero exit. The hint field + * gives a starting size for the strbuf allocation. + * + * The fields of "cmd" should be set up as they would for a normal run_command + * invocation. But note that there is no need to set cmd->out; the function + * sets it up for the caller. + */ +int capture_command(struct child_process *cmd, struct strbuf *buf, size_t hint); + /* * The purpose of the following functions is to feed a pipe by running * a function asynchronously and providing output that the caller reads. diff --git a/submodule.c b/submodule.c index d37d400b22..c0e6c81fc4 100644 --- a/submodule.c +++ b/submodule.c @@ -576,12 +576,10 @@ static int is_submodule_commit_present(const char *path, unsigned char sha1[20]) cp.env = local_repo_env; cp.git_cmd = 1; cp.no_stdin = 1; - cp.out = -1; cp.dir = path; - if (!run_command(&cp) && !strbuf_read(&buf, cp.out, 1024)) + if (!capture_command(&cp, &buf, 1024) && !buf.len) is_present = 1; - close(cp.out); strbuf_release(&buf); } return is_present; @@ -214,16 +214,6 @@ static struct trailer_item *remove_first(struct trailer_item **first) return item; } -static int read_from_command(struct child_process *cp, struct strbuf *buf) -{ - if (run_command(cp)) - return error("running trailer command '%s' failed", cp->argv[0]); - if (strbuf_read(buf, cp->out, 1024) < 1) - return error("reading from trailer command '%s' failed", cp->argv[0]); - strbuf_trim(buf); - return 0; -} - static const char *apply_command(const char *command, const char *arg) { struct strbuf cmd = STRBUF_INIT; @@ -240,14 +230,16 @@ static const char *apply_command(const char *command, const char *arg) cp.argv = argv; cp.env = local_repo_env; cp.no_stdin = 1; - cp.out = -1; cp.use_shell = 1; - if (read_from_command(&cp, &buf)) { + if (capture_command(&cp, &buf, 1024)) { + error("running trailer command '%s' failed", cmd.buf); strbuf_release(&buf); result = xstrdup(""); - } else + } else { + strbuf_trim(&buf); result = strbuf_detach(&buf, NULL); + } strbuf_release(&cmd); return result; diff --git a/wt-status.c b/wt-status.c index 7036fa28dc..853419f05f 100644 --- a/wt-status.c +++ b/wt-status.c @@ -729,7 +729,6 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt struct strbuf cmd_stdout = STRBUF_INIT; struct strbuf summary = STRBUF_INIT; char *summary_content; - size_t len; argv_array_pushf(&sm_summary.env_array, "GIT_INDEX_FILE=%s", s->index_file); @@ -745,15 +744,11 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt sm_summary.git_cmd = 1; sm_summary.no_stdin = 1; - fflush(s->fp); - sm_summary.out = -1; - run_command(&sm_summary); - - len = strbuf_read(&cmd_stdout, sm_summary.out, 1024); + capture_command(&sm_summary, &cmd_stdout, 1024); /* prepend header, only if there's an actual output */ - if (len) { + if (cmd_stdout.len) { if (uncommitted) strbuf_addstr(&summary, _("Submodules changed but not updated:")); else @@ -764,6 +759,7 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt strbuf_release(&cmd_stdout); if (s->display_comment_prefix) { + size_t len; summary_content = strbuf_detach(&summary, &len); strbuf_add_commented_lines(&summary, summary_content, len); free(summary_content); |