|
6 | 6 | #include "thread-utils.h" |
7 | 7 | #include "strbuf.h" |
8 | 8 | #include "string-list.h" |
| 9 | +#include "quote.h" |
9 | 10 |
|
10 | 11 | void child_process_init(struct child_process *child) |
11 | 12 | { |
@@ -556,6 +557,90 @@ static int wait_or_whine(pid_t pid, const char *argv0, int in_signal) |
556 | 557 | return code; |
557 | 558 | } |
558 | 559 |
|
| 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 | + |
559 | 644 | int start_command(struct child_process *cmd) |
560 | 645 | { |
561 | 646 | int need_in, need_out, need_err; |
@@ -624,7 +709,8 @@ int start_command(struct child_process *cmd) |
624 | 709 | cmd->err = fderr[0]; |
625 | 710 | } |
626 | 711 |
|
627 | | - trace_argv_printf(cmd->argv, "trace: run_command:"); |
| 712 | + trace_run_command(cmd); |
| 713 | + |
628 | 714 | fflush(NULL); |
629 | 715 |
|
630 | 716 | #ifndef GIT_WINDOWS_NATIVE |
|
0 commit comments