Skip to content

Commit 3efeec3

Browse files
committed
Merge branch 'nd/trace-with-env'
The tracing machinery learned to report tweaking of environment variables as well. * nd/trace-with-env: run-command.c: print new cwd in trace_run_command() run-command.c: print env vars in trace_run_command() run-command.c: print program 'git' when tracing git_cmd mode run-command.c: introduce trace_run_command() trace.c: move strbuf_release() out of print_trace_line() trace: avoid unnecessary quoting sq_quote_argv: drop maxlen parameter
2 parents ead8dbe + 090a092 commit 3efeec3

File tree

8 files changed

+178
-11
lines changed

8 files changed

+178
-11
lines changed

builtin/am.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
10611061
}
10621062
write_state_text(state, "scissors", str);
10631063

1064-
sq_quote_argv(&sb, state->git_apply_opts.argv, 0);
1064+
sq_quote_argv(&sb, state->git_apply_opts.argv);
10651065
write_state_text(state, "apply-opt", sb.buf);
10661066

10671067
if (state->rebasing)

builtin/rev-parse.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
516516
PARSE_OPT_SHELL_EVAL);
517517

518518
strbuf_addstr(&parsed, " --");
519-
sq_quote_argv(&parsed, argv, 0);
519+
sq_quote_argv(&parsed, argv);
520520
puts(parsed.buf);
521521
return 0;
522522
}
@@ -526,7 +526,7 @@ static int cmd_sq_quote(int argc, const char **argv)
526526
struct strbuf buf = STRBUF_INIT;
527527

528528
if (argc)
529-
sq_quote_argv(&buf, argv, 0);
529+
sq_quote_argv(&buf, argv);
530530
printf("%s\n", buf.buf);
531531
strbuf_release(&buf);
532532

quote.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,22 @@ void sq_quote_buf(struct strbuf *dst, const char *src)
4343
free(to_free);
4444
}
4545

46+
void sq_quote_buf_pretty(struct strbuf *dst, const char *src)
47+
{
48+
static const char ok_punct[] = "+,-./:=@_^";
49+
const char *p;
50+
51+
for (p = src; *p; p++) {
52+
if (!isalpha(*p) && !isdigit(*p) && !strchr(ok_punct, *p)) {
53+
sq_quote_buf(dst, src);
54+
return;
55+
}
56+
}
57+
58+
/* if we get here, we did not need quoting */
59+
strbuf_addstr(dst, src);
60+
}
61+
4662
void sq_quotef(struct strbuf *dst, const char *fmt, ...)
4763
{
4864
struct strbuf src = STRBUF_INIT;
@@ -56,7 +72,7 @@ void sq_quotef(struct strbuf *dst, const char *fmt, ...)
5672
strbuf_release(&src);
5773
}
5874

59-
void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
75+
void sq_quote_argv(struct strbuf *dst, const char **argv)
6076
{
6177
int i;
6278

@@ -65,8 +81,16 @@ void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
6581
for (i = 0; argv[i]; ++i) {
6682
strbuf_addch(dst, ' ');
6783
sq_quote_buf(dst, argv[i]);
68-
if (maxlen && dst->len > maxlen)
69-
die("Too many or long arguments");
84+
}
85+
}
86+
87+
void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
88+
{
89+
int i;
90+
91+
for (i = 0; argv[i]; i++) {
92+
strbuf_addch(dst, ' ');
93+
sq_quote_buf_pretty(dst, argv[i]);
7094
}
7195
}
7296

quote.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,17 @@ struct strbuf;
3030
*/
3131

3232
extern void sq_quote_buf(struct strbuf *, const char *src);
33-
extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
33+
extern void sq_quote_argv(struct strbuf *, const char **argv);
3434
extern void sq_quotef(struct strbuf *, const char *fmt, ...);
3535

36+
/*
37+
* These match their non-pretty variants, except that they avoid
38+
* quoting when there are no exotic characters. These should only be used for
39+
* human-readable output, as sq_dequote() is not smart enough to dequote it.
40+
*/
41+
void sq_quote_buf_pretty(struct strbuf *, const char *src);
42+
void sq_quote_argv_pretty(struct strbuf *, const char **argv);
43+
3644
/* This unwraps what sq_quote() produces in place, but returns
3745
* NULL if the input does not look like what sq_quote would have
3846
* produced.

run-command.c

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "thread-utils.h"
77
#include "strbuf.h"
88
#include "string-list.h"
9+
#include "quote.h"
910

1011
void child_process_init(struct child_process *child)
1112
{
@@ -556,6 +557,90 @@ static int wait_or_whine(pid_t pid, const char *argv0, int in_signal)
556557
return code;
557558
}
558559

560+
static void trace_add_env(struct strbuf *dst, const char *const *deltaenv)
561+
{
562+
struct string_list envs = STRING_LIST_INIT_DUP;
563+
const char *const *e;
564+
int i;
565+
int printed_unset = 0;
566+
567+
/* Last one wins, see run-command.c:prep_childenv() for context */
568+
for (e = deltaenv; e && *e; e++) {
569+
struct strbuf key = STRBUF_INIT;
570+
char *equals = strchr(*e, '=');
571+
572+
if (equals) {
573+
strbuf_add(&key, *e, equals - *e);
574+
string_list_insert(&envs, key.buf)->util = equals + 1;
575+
} else {
576+
string_list_insert(&envs, *e)->util = NULL;
577+
}
578+
strbuf_release(&key);
579+
}
580+
581+
/* "unset X Y...;" */
582+
for (i = 0; i < envs.nr; i++) {
583+
const char *var = envs.items[i].string;
584+
const char *val = envs.items[i].util;
585+
586+
if (val || !getenv(var))
587+
continue;
588+
589+
if (!printed_unset) {
590+
strbuf_addstr(dst, " unset");
591+
printed_unset = 1;
592+
}
593+
strbuf_addf(dst, " %s", var);
594+
}
595+
if (printed_unset)
596+
strbuf_addch(dst, ';');
597+
598+
/* ... followed by "A=B C=D ..." */
599+
for (i = 0; i < envs.nr; i++) {
600+
const char *var = envs.items[i].string;
601+
const char *val = envs.items[i].util;
602+
const char *oldval;
603+
604+
if (!val)
605+
continue;
606+
607+
oldval = getenv(var);
608+
if (oldval && !strcmp(val, oldval))
609+
continue;
610+
611+
strbuf_addf(dst, " %s=", var);
612+
sq_quote_buf_pretty(dst, val);
613+
}
614+
string_list_clear(&envs, 0);
615+
}
616+
617+
static void trace_run_command(const struct child_process *cp)
618+
{
619+
struct strbuf buf = STRBUF_INIT;
620+
621+
if (!trace_want(&trace_default_key))
622+
return;
623+
624+
strbuf_addf(&buf, "trace: run_command:");
625+
if (cp->dir) {
626+
strbuf_addstr(&buf, " cd ");
627+
sq_quote_buf_pretty(&buf, cp->dir);
628+
strbuf_addch(&buf, ';');
629+
}
630+
/*
631+
* The caller is responsible for initializing cp->env from
632+
* cp->env_array if needed. We only check one place.
633+
*/
634+
if (cp->env)
635+
trace_add_env(&buf, cp->env);
636+
if (cp->git_cmd)
637+
strbuf_addstr(&buf, " git");
638+
sq_quote_argv_pretty(&buf, cp->argv);
639+
640+
trace_printf("%s", buf.buf);
641+
strbuf_release(&buf);
642+
}
643+
559644
int start_command(struct child_process *cmd)
560645
{
561646
int need_in, need_out, need_err;
@@ -624,7 +709,8 @@ int start_command(struct child_process *cmd)
624709
cmd->err = fderr[0];
625710
}
626711

627-
trace_argv_printf(cmd->argv, "trace: run_command:");
712+
trace_run_command(cmd);
713+
628714
fflush(NULL);
629715

630716
#ifndef GIT_WINDOWS_NATIVE

t/helper/test-run-command.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ int cmd_main(int argc, const char **argv)
5454
struct child_process proc = CHILD_PROCESS_INIT;
5555
int jobs;
5656

57+
if (argc < 3)
58+
return 1;
59+
while (!strcmp(argv[1], "env")) {
60+
if (!argv[2])
61+
die("env specifier without a value");
62+
argv_array_push(&proc.env_array, argv[2]);
63+
argv += 2;
64+
argc -= 2;
65+
}
5766
if (argc < 3)
5867
return 1;
5968
proc.argv = (const char **)argv + 2;

t/t0061-run-command.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,41 @@ test_expect_success 'run_command outputs ' '
141141
test_cmp expect actual
142142
'
143143

144+
test_trace () {
145+
expect="$1"
146+
shift
147+
GIT_TRACE=1 test-run-command "$@" run-command true 2>&1 >/dev/null | \
148+
sed 's/.* run_command: //' >actual &&
149+
echo "$expect true" >expect &&
150+
test_cmp expect actual
151+
}
152+
153+
test_expect_success 'GIT_TRACE with environment variables' '
154+
test_trace "abc=1 def=2" env abc=1 env def=2 &&
155+
test_trace "abc=2" env abc env abc=1 env abc=2 &&
156+
test_trace "abc=2" env abc env abc=2 &&
157+
(
158+
abc=1 && export abc &&
159+
test_trace "def=1" env abc=1 env def=1
160+
) &&
161+
(
162+
abc=1 && export abc &&
163+
test_trace "def=1" env abc env abc=1 env def=1
164+
) &&
165+
test_trace "def=1" env non-exist env def=1 &&
166+
test_trace "abc=2" env abc=1 env abc env abc=2 &&
167+
(
168+
abc=1 def=2 && export abc def &&
169+
test_trace "unset abc def;" env abc env def
170+
) &&
171+
(
172+
abc=1 def=2 && export abc def &&
173+
test_trace "unset def; abc=3" env abc env def env abc=3
174+
) &&
175+
(
176+
abc=1 && export abc &&
177+
test_trace "unset abc;" env abc=2 env abc
178+
)
179+
'
180+
144181
test_done

trace.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ static void print_trace_line(struct trace_key *key, struct strbuf *buf)
131131
{
132132
strbuf_complete_line(buf);
133133
trace_write(key, buf->buf, buf->len);
134-
strbuf_release(buf);
135134
}
136135

137136
static void trace_vprintf_fl(const char *file, int line, struct trace_key *key,
@@ -144,6 +143,7 @@ static void trace_vprintf_fl(const char *file, int line, struct trace_key *key,
144143

145144
strbuf_vaddf(&buf, format, ap);
146145
print_trace_line(key, &buf);
146+
strbuf_release(&buf);
147147
}
148148

149149
static void trace_argv_vprintf_fl(const char *file, int line,
@@ -157,8 +157,9 @@ static void trace_argv_vprintf_fl(const char *file, int line,
157157

158158
strbuf_vaddf(&buf, format, ap);
159159

160-
sq_quote_argv(&buf, argv, 0);
160+
sq_quote_argv_pretty(&buf, argv);
161161
print_trace_line(&trace_default_key, &buf);
162+
strbuf_release(&buf);
162163
}
163164

164165
void trace_strbuf_fl(const char *file, int line, struct trace_key *key,
@@ -171,6 +172,7 @@ void trace_strbuf_fl(const char *file, int line, struct trace_key *key,
171172

172173
strbuf_addbuf(&buf, data);
173174
print_trace_line(key, &buf);
175+
strbuf_release(&buf);
174176
}
175177

176178
static void trace_performance_vprintf_fl(const char *file, int line,
@@ -190,6 +192,7 @@ static void trace_performance_vprintf_fl(const char *file, int line,
190192
}
191193

192194
print_trace_line(&trace_perf_key, &buf);
195+
strbuf_release(&buf);
193196
}
194197

195198
#ifndef HAVE_VARIADIC_MACROS
@@ -426,6 +429,6 @@ void trace_command_performance(const char **argv)
426429
atexit(print_command_performance_atexit);
427430

428431
strbuf_reset(&command_line);
429-
sq_quote_argv(&command_line, argv, 0);
432+
sq_quote_argv_pretty(&command_line, argv);
430433
command_start_time = getnanotime();
431434
}

0 commit comments

Comments
 (0)