On Tue, Jun 16, 2015 at 03:49:07PM -0400, Jeff King wrote: > Another option would be to stop trying to intercept stdin in git.c, and > instead make this a feature of run-command.c. That is, right before we > exec a process, tee its stdin there. That means that you cannot do: > > GIT_TRACE_STDIN=/tmp/foo.out git foo > > to collect the stdin of foo. But that is not really an interesting case > anyway. You can run "tee" yourself if you want. The interesting cases > are the ones where git is spawning a sub-process, and you want to > intercept the data moving between the git processes. Hmm. I guess we do not actually have to move the stdin interception there. We can just move the config-checking there, like the patch below. It basically just converts trace.foo.bar into GIT_TRACE_BAR when we are running "foo" as a git command. This does work, but is perhaps potentially confusing to the user, because it only kicks in when _git_ runs "foo". IOW, this works: git config trace.upload-pack.foo /path/to/foo.out git daemon and will trace as you expect. But then running: git upload-pack yourself will do nothing. I dunno. --- run-command.c | 17 +++++++++++++++++ trace.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ trace.h | 9 +++++++++ 3 files changed, 70 insertions(+) diff --git a/run-command.c b/run-command.c index 4d73e90..2febbb5 100644 --- a/run-command.c +++ b/run-command.c @@ -284,6 +284,23 @@ int start_command(struct child_process *cmd) if (!cmd->argv) cmd->argv = cmd->args.argv; + if (cmd->git_cmd) { + /* + * Load any extra variables into env_array. But + * if we weren't going to use it (in favor of "env"), + * then consolidate the two. Make sure the original "env" + * goes after what we add, so that it can override. + * + * We cannot just keep two lists, because we may hand off the + * single list to a spawn() implementation. + */ + trace_config_for(cmd->argv[0], &cmd->env_array); + if (cmd->env_array.argc && cmd->env) { + for (; *cmd->env; cmd->env++) + argv_array_push(&cmd->env_array, *cmd->env); + cmd->env = NULL; + } + } if (!cmd->env) cmd->env = cmd->env_array.argv; diff --git a/trace.c b/trace.c index a7ec484..86c988e 100644 --- a/trace.c +++ b/trace.c @@ -24,6 +24,7 @@ #include "cache.h" #include "quote.h" +#include "argv-array.h" static size_t expand_trace_name(struct strbuf *out, const char *fmt, void *data) @@ -449,3 +450,46 @@ void trace_command_performance(const char **argv) sq_quote_argv(&command_line, argv, 0); command_start_time = getnanotime(); } + +struct trace_config_data { + const char *want_cmd; + struct argv_array *out; +}; + +static int trace_config_cb(const char *var, const char *value, void *vdata) +{ + struct trace_config_data *data = vdata; + const char *have_cmd, *key; + int have_len; + + if (!parse_config_key(var, "trace", &have_cmd, &have_len, &key) && + have_cmd && + !strncmp(data->want_cmd, have_cmd, have_len) && + data->want_cmd[have_len] == '\0') { + struct strbuf buf = STRBUF_INIT; + + strbuf_addstr(&buf, "GIT_TRACE_"); + while (*key) + strbuf_addch(&buf, toupper(*key++)); + + /* + * Environment always takes precedence over config, so do not + * override existing variables. We cannot rely on setenv()'s + * overwrite flag here, because we may pass the list off to + * a spawn() implementation, which always overwrites. + */ + if (!getenv(buf.buf)) + argv_array_pushf(data->out, "%s=%s", buf.buf, value); + + strbuf_release(&buf); + } + return 0; +} + +void trace_config_for(const char *cmd, struct argv_array *out) +{ + struct trace_config_data data; + data.want_cmd = cmd; + data.out = out; + git_config(trace_config_cb, &data); +} diff --git a/trace.h b/trace.h index 179b249..83618e9 100644 --- a/trace.h +++ b/trace.h @@ -4,6 +4,8 @@ #include "git-compat-util.h" #include "strbuf.h" +struct argv_array; + struct trace_key { const char * const key; int fd; @@ -20,6 +22,13 @@ extern uint64_t getnanotime(void); extern void trace_command_performance(const char **argv); extern void trace_verbatim(struct trace_key *key, const void *buf, unsigned len); +/** + * Load any trace-related config for git command "cmd", and insert the matching + * environment variables into "out", which is suitable for use by run-command + * and friends. + */ +void trace_config_for(const char *cmd, struct argv_array *out); + #ifndef HAVE_VARIADIC_MACROS __attribute__((format (printf, 1, 2))) -- 2.4.3.699.g84b4da7 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html