Skip to content

Commit 63641fb

Browse files
committed
Merge branch 'js/log-to-diffopt-file'
The commands in the "log/diff" family have had an FILE* pointer in the data structure they pass around for a long time, but some codepaths used to always write to the standard output. As a preparatory step to make "git format-patch" available to the internal callers, these codepaths have been updated to consistently write into that FILE* instead. * js/log-to-diffopt-file: mingw: fix the shortlog --output=<file> test diff: do not color output when --color=auto and --output=<file> is given t4211: ensure that log respects --output=<file> shortlog: respect the --output=<file> setting format-patch: use stdout directly format-patch: avoid freopen() format-patch: explicitly switch off color when writing to files shortlog: support outputting to streams other than stdout graph: respect the diffopt.file setting line-log: respect diffopt's configured output file stream log-tree: respect diffopt's configured output file stream log: prepare log/log-tree to reuse the diffopt.close_file attribute
2 parents 7725beb + bac233f commit 63641fb

File tree

9 files changed

+144
-107
lines changed

9 files changed

+144
-107
lines changed

builtin/log.c

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -238,16 +238,17 @@ static void show_early_header(struct rev_info *rev, const char *stage, int nr)
238238
if (rev->commit_format != CMIT_FMT_ONELINE)
239239
putchar(rev->diffopt.line_termination);
240240
}
241-
printf(_("Final output: %d %s\n"), nr, stage);
241+
fprintf(rev->diffopt.file, _("Final output: %d %s\n"), nr, stage);
242242
}
243243

244244
static struct itimerval early_output_timer;
245245

246246
static void log_show_early(struct rev_info *revs, struct commit_list *list)
247247
{
248-
int i = revs->early_output;
248+
int i = revs->early_output, close_file = revs->diffopt.close_file;
249249
int show_header = 1;
250250

251+
revs->diffopt.close_file = 0;
251252
sort_in_topological_order(&list, revs->sort_order);
252253
while (list && i) {
253254
struct commit *commit = list->item;
@@ -264,14 +265,19 @@ static void log_show_early(struct rev_info *revs, struct commit_list *list)
264265
case commit_ignore:
265266
break;
266267
case commit_error:
268+
if (close_file)
269+
fclose(revs->diffopt.file);
267270
return;
268271
}
269272
list = list->next;
270273
}
271274

272275
/* Did we already get enough commits for the early output? */
273-
if (!i)
276+
if (!i) {
277+
if (close_file)
278+
fclose(revs->diffopt.file);
274279
return;
280+
}
275281

276282
/*
277283
* ..if no, then repeat it twice a second until we
@@ -333,7 +339,7 @@ static int cmd_log_walk(struct rev_info *rev)
333339
{
334340
struct commit *commit;
335341
int saved_nrl = 0;
336-
int saved_dcctc = 0;
342+
int saved_dcctc = 0, close_file = rev->diffopt.close_file;
337343

338344
if (rev->early_output)
339345
setup_early_output(rev);
@@ -349,6 +355,7 @@ static int cmd_log_walk(struct rev_info *rev)
349355
* and HAS_CHANGES being accumulated in rev->diffopt, so be careful to
350356
* retain that state information if replacing rev->diffopt in this loop
351357
*/
358+
rev->diffopt.close_file = 0;
352359
while ((commit = get_revision(rev)) != NULL) {
353360
if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
354361
/*
@@ -369,6 +376,8 @@ static int cmd_log_walk(struct rev_info *rev)
369376
}
370377
rev->diffopt.degraded_cc_to_c = saved_dcctc;
371378
rev->diffopt.needed_rename_limit = saved_nrl;
379+
if (close_file)
380+
fclose(rev->diffopt.file);
372381

373382
if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
374383
DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
@@ -451,7 +460,7 @@ static void show_tagger(char *buf, int len, struct rev_info *rev)
451460
pp.fmt = rev->commit_format;
452461
pp.date_mode = rev->date_mode;
453462
pp_user_info(&pp, "Tagger", &out, buf, get_log_output_encoding());
454-
printf("%s", out.buf);
463+
fprintf(rev->diffopt.file, "%s", out.buf);
455464
strbuf_release(&out);
456465
}
457466

@@ -462,7 +471,7 @@ static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, con
462471
char *buf;
463472
unsigned long size;
464473

465-
fflush(stdout);
474+
fflush(rev->diffopt.file);
466475
if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
467476
!DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
468477
return stream_blob_to_fd(1, sha1, NULL, 0);
@@ -502,7 +511,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
502511
}
503512

504513
if (offset < size)
505-
fwrite(buf + offset, size - offset, 1, stdout);
514+
fwrite(buf + offset, size - offset, 1, rev->diffopt.file);
506515
free(buf);
507516
return 0;
508517
}
@@ -511,7 +520,8 @@ static int show_tree_object(const unsigned char *sha1,
511520
struct strbuf *base,
512521
const char *pathname, unsigned mode, int stage, void *context)
513522
{
514-
printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
523+
FILE *file = context;
524+
fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
515525
return 0;
516526
}
517527

@@ -571,7 +581,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
571581

572582
if (rev.shown_one)
573583
putchar('\n');
574-
printf("%stag %s%s\n",
584+
fprintf(rev.diffopt.file, "%stag %s%s\n",
575585
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
576586
t->tag,
577587
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
@@ -590,12 +600,12 @@ int cmd_show(int argc, const char **argv, const char *prefix)
590600
case OBJ_TREE:
591601
if (rev.shown_one)
592602
putchar('\n');
593-
printf("%stree %s%s\n\n",
603+
fprintf(rev.diffopt.file, "%stree %s%s\n\n",
594604
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
595605
name,
596606
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
597607
read_tree_recursive((struct tree *)o, "", 0, 0, &match_all,
598-
show_tree_object, NULL);
608+
show_tree_object, rev.diffopt.file);
599609
rev.shown_one = 1;
600610
break;
601611
case OBJ_COMMIT:
@@ -801,11 +811,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
801811
return git_log_config(var, value, cb);
802812
}
803813

804-
static FILE *realstdout = NULL;
805814
static const char *output_directory = NULL;
806815
static int outdir_offset;
807816

808-
static int reopen_stdout(struct commit *commit, const char *subject,
817+
static int open_next_file(struct commit *commit, const char *subject,
809818
struct rev_info *rev, int quiet)
810819
{
811820
struct strbuf filename = STRBUF_INIT;
@@ -827,9 +836,9 @@ static int reopen_stdout(struct commit *commit, const char *subject,
827836
fmt_output_subject(&filename, subject, rev);
828837

829838
if (!quiet)
830-
fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
839+
printf("%s\n", filename.buf + outdir_offset);
831840

832-
if (freopen(filename.buf, "w", stdout) == NULL)
841+
if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL)
833842
return error(_("Cannot open patch file %s"), filename.buf);
834843

835844
strbuf_release(&filename);
@@ -888,15 +897,15 @@ static void gen_message_id(struct rev_info *info, char *base)
888897
info->message_id = strbuf_detach(&buf, NULL);
889898
}
890899

891-
static void print_signature(void)
900+
static void print_signature(FILE *file)
892901
{
893902
if (!signature || !*signature)
894903
return;
895904

896-
printf("-- \n%s", signature);
905+
fprintf(file, "-- \n%s", signature);
897906
if (signature[strlen(signature)-1] != '\n')
898-
putchar('\n');
899-
putchar('\n');
907+
putc('\n', file);
908+
putc('\n', file);
900909
}
901910

902911
static void add_branch_description(struct strbuf *buf, const char *branch_name)
@@ -965,7 +974,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
965974
committer = git_committer_info(0);
966975

967976
if (!use_stdout &&
968-
reopen_stdout(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
977+
open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
969978
return;
970979

971980
log_write_email_headers(rev, head, &pp.subject, &pp.after_subject,
@@ -988,7 +997,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
988997
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
989998
pp_remainder(&pp, &msg, &sb, 0);
990999
add_branch_description(&sb, branch_name);
991-
printf("%s\n", sb.buf);
1000+
fprintf(rev->diffopt.file, "%s\n", sb.buf);
9921001

9931002
strbuf_release(&sb);
9941003

@@ -997,6 +1006,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
9971006
log.wrap = 72;
9981007
log.in1 = 2;
9991008
log.in2 = 4;
1009+
log.file = rev->diffopt.file;
10001010
for (i = 0; i < nr; i++)
10011011
shortlog_add_commit(&log, list[i]);
10021012

@@ -1019,8 +1029,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
10191029
diffcore_std(&opts);
10201030
diff_flush(&opts);
10211031

1022-
printf("\n");
1023-
print_signature();
1032+
fprintf(rev->diffopt.file, "\n");
1033+
print_signature(rev->diffopt.file);
10241034
}
10251035

10261036
static const char *clean_message_id(const char *msg_id)
@@ -1330,7 +1340,7 @@ static void prepare_bases(struct base_tree_info *bases,
13301340
}
13311341
}
13321342

1333-
static void print_bases(struct base_tree_info *bases)
1343+
static void print_bases(struct base_tree_info *bases, FILE *file)
13341344
{
13351345
int i;
13361346

@@ -1339,11 +1349,11 @@ static void print_bases(struct base_tree_info *bases)
13391349
return;
13401350

13411351
/* Show the base commit */
1342-
printf("base-commit: %s\n", oid_to_hex(&bases->base_commit));
1352+
fprintf(file, "base-commit: %s\n", oid_to_hex(&bases->base_commit));
13431353

13441354
/* Show the prerequisite patches */
13451355
for (i = bases->nr_patch_id - 1; i >= 0; i--)
1346-
printf("prerequisite-patch-id: %s\n", oid_to_hex(&bases->patch_id[i]));
1356+
fprintf(file, "prerequisite-patch-id: %s\n", oid_to_hex(&bases->patch_id[i]));
13471357

13481358
free(bases->patch_id);
13491359
bases->nr_patch_id = 0;
@@ -1575,6 +1585,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15751585
setup_pager();
15761586

15771587
if (output_directory) {
1588+
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
1589+
rev.diffopt.use_color = GIT_COLOR_NEVER;
15781590
if (use_stdout)
15791591
die(_("standard output, or directory, which one?"));
15801592
if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
@@ -1632,9 +1644,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
16321644
get_patch_ids(&rev, &ids);
16331645
}
16341646

1635-
if (!use_stdout)
1636-
realstdout = xfdopen(xdup(1), "w");
1637-
16381647
if (prepare_revision_walk(&rev))
16391648
die(_("revision walk setup failed"));
16401649
rev.boundary = 1;
@@ -1699,7 +1708,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
16991708
gen_message_id(&rev, "cover");
17001709
make_cover_letter(&rev, use_stdout,
17011710
origin, nr, list, branch_name, quiet);
1702-
print_bases(&bases);
1711+
print_bases(&bases, rev.diffopt.file);
17031712
total++;
17041713
start_number--;
17051714
}
@@ -1745,7 +1754,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17451754
}
17461755

17471756
if (!use_stdout &&
1748-
reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
1757+
open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
17491758
die(_("Failed to create output files"));
17501759
shown = log_tree_commit(&rev, commit);
17511760
free_commit_buffer(commit);
@@ -1760,15 +1769,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
17601769
rev.shown_one = 0;
17611770
if (shown) {
17621771
if (rev.mime_boundary)
1763-
printf("\n--%s%s--\n\n\n",
1772+
fprintf(rev.diffopt.file, "\n--%s%s--\n\n\n",
17641773
mime_boundary_leader,
17651774
rev.mime_boundary);
17661775
else
1767-
print_signature();
1768-
print_bases(&bases);
1776+
print_signature(rev.diffopt.file);
1777+
print_bases(&bases, rev.diffopt.file);
17691778
}
17701779
if (!use_stdout)
1771-
fclose(stdout);
1780+
fclose(rev.diffopt.file);
17721781
}
17731782
free(list);
17741783
free(branch_name);
@@ -1800,15 +1809,15 @@ static const char * const cherry_usage[] = {
18001809
};
18011810

18021811
static void print_commit(char sign, struct commit *commit, int verbose,
1803-
int abbrev)
1812+
int abbrev, FILE *file)
18041813
{
18051814
if (!verbose) {
1806-
printf("%c %s\n", sign,
1815+
fprintf(file, "%c %s\n", sign,
18071816
find_unique_abbrev(commit->object.oid.hash, abbrev));
18081817
} else {
18091818
struct strbuf buf = STRBUF_INIT;
18101819
pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
1811-
printf("%c %s %s\n", sign,
1820+
fprintf(file, "%c %s %s\n", sign,
18121821
find_unique_abbrev(commit->object.oid.hash, abbrev),
18131822
buf.buf);
18141823
strbuf_release(&buf);
@@ -1889,7 +1898,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
18891898
commit = list->item;
18901899
if (has_commit_patch_id(commit, &ids))
18911900
sign = '-';
1892-
print_commit(sign, commit, verbose, abbrev);
1901+
print_commit(sign, commit, verbose, abbrev, revs.diffopt.file);
18931902
list = list->next;
18941903
}
18951904

builtin/shortlog.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
276276

277277
log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
278278
log.abbrev = rev.abbrev;
279+
log.file = rev.diffopt.file;
279280

280281
/* assume HEAD if from a tty */
281282
if (!nongit && !rev.pending.nr && isatty(0))
@@ -289,6 +290,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
289290
get_from_rev(&rev, &log);
290291

291292
shortlog_output(&log);
293+
if (log.file != stdout)
294+
fclose(log.file);
292295
return 0;
293296
}
294297

@@ -310,22 +313,24 @@ void shortlog_output(struct shortlog *log)
310313
for (i = 0; i < log->list.nr; i++) {
311314
const struct string_list_item *item = &log->list.items[i];
312315
if (log->summary) {
313-
printf("%6d\t%s\n", (int)UTIL_TO_INT(item), item->string);
316+
fprintf(log->file, "%6d\t%s\n",
317+
(int)UTIL_TO_INT(item), item->string);
314318
} else {
315319
struct string_list *onelines = item->util;
316-
printf("%s (%d):\n", item->string, onelines->nr);
320+
fprintf(log->file, "%s (%d):\n",
321+
item->string, onelines->nr);
317322
for (j = onelines->nr - 1; j >= 0; j--) {
318323
const char *msg = onelines->items[j].string;
319324

320325
if (log->wrap_lines) {
321326
strbuf_reset(&sb);
322327
add_wrapped_shortlog_msg(&sb, msg, log);
323-
fwrite(sb.buf, sb.len, 1, stdout);
328+
fwrite(sb.buf, sb.len, 1, log->file);
324329
}
325330
else
326-
printf(" %s\n", msg);
331+
fprintf(log->file, " %s\n", msg);
327332
}
328-
putchar('\n');
333+
putc('\n', log->file);
329334
onelines->strdup_strings = 1;
330335
string_list_clear(onelines, 0);
331336
free(onelines);

diff.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3977,6 +3977,8 @@ int diff_opt_parse(struct diff_options *options,
39773977
if (!options->file)
39783978
die_errno("Could not open '%s'", path);
39793979
options->close_file = 1;
3980+
if (options->use_color != GIT_COLOR_ALWAYS)
3981+
options->use_color = GIT_COLOR_NEVER;
39803982
return argcount;
39813983
} else
39823984
return 0;

0 commit comments

Comments
 (0)