}
write_state_text(state, "scissors", str);
- sq_quote_argv(&sb, state->git_apply_opts.argv, 0);
+ sq_quote_argv(&sb, state->git_apply_opts.argv);
write_state_text(state, "apply-opt", sb.buf);
if (state->rebasing)
PARSE_OPT_SHELL_EVAL);
strbuf_addstr(&parsed, " --");
- sq_quote_argv(&parsed, argv, 0);
+ sq_quote_argv(&parsed, argv);
puts(parsed.buf);
return 0;
}
struct strbuf buf = STRBUF_INIT;
if (argc)
- sq_quote_argv(&buf, argv, 0);
+ sq_quote_argv(&buf, argv);
printf("%s\n", buf.buf);
strbuf_release(&buf);
free(to_free);
}
+void sq_quote_buf_pretty(struct strbuf *dst, const char *src)
+{
+ static const char ok_punct[] = "+,-./:=@_^";
+ const char *p;
+
+ for (p = src; *p; p++) {
+ if (!isalpha(*p) && !isdigit(*p) && !strchr(ok_punct, *p)) {
+ sq_quote_buf(dst, src);
+ return;
+ }
+ }
+
+ /* if we get here, we did not need quoting */
+ strbuf_addstr(dst, src);
+}
+
void sq_quotef(struct strbuf *dst, const char *fmt, ...)
{
struct strbuf src = STRBUF_INIT;
strbuf_release(&src);
}
-void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
+void sq_quote_argv(struct strbuf *dst, const char **argv)
{
int i;
for (i = 0; argv[i]; ++i) {
strbuf_addch(dst, ' ');
sq_quote_buf(dst, argv[i]);
- if (maxlen && dst->len > maxlen)
- die("Too many or long arguments");
+ }
+}
+
+void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
+{
+ int i;
+
+ for (i = 0; argv[i]; i++) {
+ strbuf_addch(dst, ' ');
+ sq_quote_buf_pretty(dst, argv[i]);
}
}
*/
extern void sq_quote_buf(struct strbuf *, const char *src);
-extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
+extern void sq_quote_argv(struct strbuf *, const char **argv);
extern void sq_quotef(struct strbuf *, const char *fmt, ...);
+/*
+ * These match their non-pretty variants, except that they avoid
+ * quoting when there are no exotic characters. These should only be used for
+ * human-readable output, as sq_dequote() is not smart enough to dequote it.
+ */
+void sq_quote_buf_pretty(struct strbuf *, const char *src);
+void sq_quote_argv_pretty(struct strbuf *, const char **argv);
+
/* This unwraps what sq_quote() produces in place, but returns
* NULL if the input does not look like what sq_quote would have
* produced.
#include "thread-utils.h"
#include "strbuf.h"
#include "string-list.h"
+#include "quote.h"
void child_process_init(struct child_process *child)
{
return code;
}
+static void trace_add_env(struct strbuf *dst, const char *const *deltaenv)
+{
+ struct string_list envs = STRING_LIST_INIT_DUP;
+ const char *const *e;
+ int i;
+ int printed_unset = 0;
+
+ /* Last one wins, see run-command.c:prep_childenv() for context */
+ for (e = deltaenv; e && *e; e++) {
+ struct strbuf key = STRBUF_INIT;
+ char *equals = strchr(*e, '=');
+
+ if (equals) {
+ strbuf_add(&key, *e, equals - *e);
+ string_list_insert(&envs, key.buf)->util = equals + 1;
+ } else {
+ string_list_insert(&envs, *e)->util = NULL;
+ }
+ strbuf_release(&key);
+ }
+
+ /* "unset X Y...;" */
+ for (i = 0; i < envs.nr; i++) {
+ const char *var = envs.items[i].string;
+ const char *val = envs.items[i].util;
+
+ if (val || !getenv(var))
+ continue;
+
+ if (!printed_unset) {
+ strbuf_addstr(dst, " unset");
+ printed_unset = 1;
+ }
+ strbuf_addf(dst, " %s", var);
+ }
+ if (printed_unset)
+ strbuf_addch(dst, ';');
+
+ /* ... followed by "A=B C=D ..." */
+ for (i = 0; i < envs.nr; i++) {
+ const char *var = envs.items[i].string;
+ const char *val = envs.items[i].util;
+ const char *oldval;
+
+ if (!val)
+ continue;
+
+ oldval = getenv(var);
+ if (oldval && !strcmp(val, oldval))
+ continue;
+
+ strbuf_addf(dst, " %s=", var);
+ sq_quote_buf_pretty(dst, val);
+ }
+ string_list_clear(&envs, 0);
+}
+
+static void trace_run_command(const struct child_process *cp)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ if (!trace_want(&trace_default_key))
+ return;
+
+ strbuf_addf(&buf, "trace: run_command:");
+ if (cp->dir) {
+ strbuf_addstr(&buf, " cd ");
+ sq_quote_buf_pretty(&buf, cp->dir);
+ strbuf_addch(&buf, ';');
+ }
+ /*
+ * The caller is responsible for initializing cp->env from
+ * cp->env_array if needed. We only check one place.
+ */
+ if (cp->env)
+ trace_add_env(&buf, cp->env);
+ if (cp->git_cmd)
+ strbuf_addstr(&buf, " git");
+ sq_quote_argv_pretty(&buf, cp->argv);
+
+ trace_printf("%s", buf.buf);
+ strbuf_release(&buf);
+}
+
int start_command(struct child_process *cmd)
{
int need_in, need_out, need_err;
cmd->err = fderr[0];
}
- trace_argv_printf(cmd->argv, "trace: run_command:");
+ trace_run_command(cmd);
+
fflush(NULL);
#ifndef GIT_WINDOWS_NATIVE
struct child_process proc = CHILD_PROCESS_INIT;
int jobs;
+ if (argc < 3)
+ return 1;
+ while (!strcmp(argv[1], "env")) {
+ if (!argv[2])
+ die("env specifier without a value");
+ argv_array_push(&proc.env_array, argv[2]);
+ argv += 2;
+ argc -= 2;
+ }
if (argc < 3)
return 1;
proc.argv = (const char **)argv + 2;
test_cmp expect actual
'
+test_trace () {
+ expect="$1"
+ shift
+ GIT_TRACE=1 test-run-command "$@" run-command true 2>&1 >/dev/null | \
+ sed 's/.* run_command: //' >actual &&
+ echo "$expect true" >expect &&
+ test_cmp expect actual
+}
+
+test_expect_success 'GIT_TRACE with environment variables' '
+ test_trace "abc=1 def=2" env abc=1 env def=2 &&
+ test_trace "abc=2" env abc env abc=1 env abc=2 &&
+ test_trace "abc=2" env abc env abc=2 &&
+ (
+ abc=1 && export abc &&
+ test_trace "def=1" env abc=1 env def=1
+ ) &&
+ (
+ abc=1 && export abc &&
+ test_trace "def=1" env abc env abc=1 env def=1
+ ) &&
+ test_trace "def=1" env non-exist env def=1 &&
+ test_trace "abc=2" env abc=1 env abc env abc=2 &&
+ (
+ abc=1 def=2 && export abc def &&
+ test_trace "unset abc def;" env abc env def
+ ) &&
+ (
+ abc=1 def=2 && export abc def &&
+ test_trace "unset def; abc=3" env abc env def env abc=3
+ ) &&
+ (
+ abc=1 && export abc &&
+ test_trace "unset abc;" env abc=2 env abc
+ )
+'
+
test_done
{
strbuf_complete_line(buf);
trace_write(key, buf->buf, buf->len);
- strbuf_release(buf);
}
static void trace_vprintf_fl(const char *file, int line, struct trace_key *key,
strbuf_vaddf(&buf, format, ap);
print_trace_line(key, &buf);
+ strbuf_release(&buf);
}
static void trace_argv_vprintf_fl(const char *file, int line,
strbuf_vaddf(&buf, format, ap);
- sq_quote_argv(&buf, argv, 0);
+ sq_quote_argv_pretty(&buf, argv);
print_trace_line(&trace_default_key, &buf);
+ strbuf_release(&buf);
}
void trace_strbuf_fl(const char *file, int line, struct trace_key *key,
strbuf_addbuf(&buf, data);
print_trace_line(key, &buf);
+ strbuf_release(&buf);
}
static void trace_performance_vprintf_fl(const char *file, int line,
}
print_trace_line(&trace_perf_key, &buf);
+ strbuf_release(&buf);
}
#ifndef HAVE_VARIADIC_MACROS
atexit(print_command_performance_atexit);
strbuf_reset(&command_line);
- sq_quote_argv(&command_line, argv, 0);
+ sq_quote_argv_pretty(&command_line, argv);
command_start_time = getnanotime();
}