diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-08-03 11:01:27 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-08-03 11:01:27 -0700 |
commit | d939af12bd96db7ad3e671a0585ad8570aa7e9d3 (patch) | |
tree | 5772ac1192ed299db657ffcfbc71c318521db653 | |
parent | Merge branch 'pt/am-tests' (diff) | |
parent | strbuf: make strbuf_addftime more robust (diff) | |
download | tgif-d939af12bd96db7ad3e671a0585ad8570aa7e9d3.tar.xz |
Merge branch 'jk/date-mode-format'
Teach "git log" and friends a new "--date=format:..." option to
format timestamps using system's strftime(3).
* jk/date-mode-format:
strbuf: make strbuf_addftime more robust
introduce "format" date-mode
convert "enum date_mode" into a struct
show-branch: use DATE_RELATIVE instead of magic number
-rw-r--r-- | Documentation/rev-list-options.txt | 5 | ||||
-rw-r--r-- | archive.c | 2 | ||||
-rw-r--r-- | builtin/blame.c | 13 | ||||
-rw-r--r-- | builtin/commit.c | 4 | ||||
-rw-r--r-- | builtin/log.c | 4 | ||||
-rw-r--r-- | builtin/shortlog.c | 2 | ||||
-rw-r--r-- | builtin/show-branch.c | 3 | ||||
-rw-r--r-- | cache.h | 37 | ||||
-rw-r--r-- | commit.h | 2 | ||||
-rw-r--r-- | date.c | 52 | ||||
-rw-r--r-- | fast-import.c | 2 | ||||
-rw-r--r-- | gettext.c | 1 | ||||
-rw-r--r-- | http-backend.c | 2 | ||||
-rw-r--r-- | log-tree.c | 2 | ||||
-rw-r--r-- | pretty.c | 29 | ||||
-rw-r--r-- | ref-filter.c | 6 | ||||
-rw-r--r-- | reflog-walk.c | 4 | ||||
-rw-r--r-- | reflog-walk.h | 4 | ||||
-rw-r--r-- | refs.c | 4 | ||||
-rw-r--r-- | revision.c | 4 | ||||
-rw-r--r-- | revision.h | 2 | ||||
-rw-r--r-- | sha1_name.c | 2 | ||||
-rw-r--r-- | strbuf.c | 33 | ||||
-rw-r--r-- | strbuf.h | 5 | ||||
-rw-r--r-- | submodule.c | 2 | ||||
-rwxr-xr-x | t/t6300-for-each-ref.sh | 18 | ||||
-rw-r--r-- | test-date.c | 4 | ||||
-rw-r--r-- | test-revision-walking.c | 2 |
28 files changed, 172 insertions, 78 deletions
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 77ac439234..a9b808fab3 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -727,6 +727,11 @@ format, often found in email messages. + `--date=raw` shows the date in the internal raw Git format `%s %z` format. + +`--date=format:...` feeds the format `...` to your system `strftime`. +Use `--date=format:%c` to show the date in your system locale's +preferred format. See the `strftime` manual for a complete list of +format placeholders. ++ `--date=default` shows timestamps in the original time zone (either committer's or author's). @@ -34,7 +34,7 @@ static void format_subst(const struct commit *commit, char *to_free = NULL; struct strbuf fmt = STRBUF_INIT; struct pretty_print_context ctx = {0}; - ctx.date_mode = DATE_NORMAL; + ctx.date_mode.type = DATE_NORMAL; ctx.abbrev = DEFAULT_ABBREV; if (src == buf->buf) diff --git a/builtin/blame.c b/builtin/blame.c index 272a222687..04e4864f8b 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -51,7 +51,7 @@ static int xdl_opts; static int abbrev = -1; static int no_whole_file_rename; -static enum date_mode blame_date_mode = DATE_ISO8601; +static struct date_mode blame_date_mode = { DATE_ISO8601 }; static size_t blame_date_width; static struct string_list mailmap; @@ -1828,7 +1828,7 @@ static const char *format_time(unsigned long time, const char *tz_str, size_t time_width; int tz; tz = atoi(tz_str); - time_str = show_date(time, tz, blame_date_mode); + time_str = show_date(time, tz, &blame_date_mode); strbuf_addstr(&time_buf, time_str); /* * Add space paddings to time_buf to display a fixed width @@ -2188,7 +2188,7 @@ static int git_blame_config(const char *var, const char *value, void *cb) if (!strcmp(var, "blame.date")) { if (!value) return config_error_nonbool(var); - blame_date_mode = parse_date_format(value); + parse_date_format(value, &blame_date_mode); return 0; } @@ -2570,13 +2570,13 @@ parse_done: if (cmd_is_annotate) { output_option |= OUTPUT_ANNOTATE_COMPAT; - blame_date_mode = DATE_ISO8601; + blame_date_mode.type = DATE_ISO8601; } else { blame_date_mode = revs.date_mode; } /* The maximum width used to show the dates */ - switch (blame_date_mode) { + switch (blame_date_mode.type) { case DATE_RFC2822: blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700"); break; @@ -2605,6 +2605,9 @@ parse_done: case DATE_NORMAL: blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700"); break; + case DATE_STRFTIME: + blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */ + break; } blame_date_width -= 1; /* strip the null */ diff --git a/builtin/commit.c b/builtin/commit.c index 254477fd1d..7314f33885 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -856,7 +856,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, _("%s" "Date: %s"), ident_shown++ ? "" : "\n", - show_ident_date(&ai, DATE_NORMAL)); + show_ident_date(&ai, DATE_MODE(NORMAL))); if (!committer_ident_sufficiently_given()) status_printf_ln(s, GIT_COLOR_NORMAL, @@ -1046,7 +1046,7 @@ static const char *find_author_by_nickname(const char *name) commit = get_revision(&revs); if (commit) { struct pretty_print_context ctx = {0}; - ctx.date_mode = DATE_NORMAL; + ctx.date_mode.type = DATE_NORMAL; strbuf_release(&buf); format_commit_message(commit, "%aN <%aE>", &buf, &ctx); clear_mailmap(&mailmap); diff --git a/builtin/log.c b/builtin/log.c index c851c7cc23..b50ef7510c 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -116,7 +116,7 @@ static void cmd_log_init_defaults(struct rev_info *rev) DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV); if (default_date_mode) - rev->date_mode = parse_date_format(default_date_mode); + parse_date_format(default_date_mode, &rev->date_mode); rev->diffopt.touched_flags = 0; } @@ -956,7 +956,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, msg = body; pp.fmt = CMIT_FMT_EMAIL; - pp.date_mode = DATE_RFC2822; + pp.date_mode.type = DATE_RFC2822; pp_user_info(&pp, NULL, &sb, committer, encoding); pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte); pp_remainder(&pp, &msg, &sb, 0); diff --git a/builtin/shortlog.c b/builtin/shortlog.c index c0bab6aaa9..007cc66a03 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -138,7 +138,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) ctx.abbrev = log->abbrev; ctx.subject = ""; ctx.after_subject = ""; - ctx.date_mode = DATE_NORMAL; + ctx.date_mode.type = DATE_NORMAL; ctx.output_encoding = get_log_output_encoding(); pretty_print_commit(&ctx, commit, &ufbuf); buffer = ufbuf.buf; diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 323f857463..c87c46eb38 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -784,7 +784,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) else msg++; reflog_msg[i] = xstrfmt("(%s) %s", - show_date(timestamp, tz, 1), + show_date(timestamp, tz, + DATE_MODE(RELATIVE)), msg); free(logmsg); sprintf(nth_desc, "%s@{%d}", *av, base+i); @@ -1049,18 +1049,30 @@ extern void *read_object_with_reference(const unsigned char *sha1, extern struct object *peel_to_type(const char *name, int namelen, struct object *o, enum object_type); -enum date_mode { - DATE_NORMAL = 0, - DATE_RELATIVE, - DATE_SHORT, - DATE_LOCAL, - DATE_ISO8601, - DATE_ISO8601_STRICT, - DATE_RFC2822, - DATE_RAW +struct date_mode { + enum date_mode_type { + DATE_NORMAL = 0, + DATE_RELATIVE, + DATE_SHORT, + DATE_LOCAL, + DATE_ISO8601, + DATE_ISO8601_STRICT, + DATE_RFC2822, + DATE_STRFTIME, + DATE_RAW + } type; + const char *strftime_fmt; }; -const char *show_date(unsigned long time, int timezone, enum date_mode mode); +/* + * Convenience helper for passing a constant type, like: + * + * show_date(t, tz, DATE_MODE(NORMAL)); + */ +#define DATE_MODE(t) date_mode_from_type(DATE_##t) +struct date_mode *date_mode_from_type(enum date_mode_type type); + +const char *show_date(unsigned long time, int timezone, const struct date_mode *mode); void show_date_relative(unsigned long time, int tz, const struct timeval *now, struct strbuf *timebuf); int parse_date(const char *date, struct strbuf *out); @@ -1070,7 +1082,7 @@ void datestamp(struct strbuf *out); #define approxidate(s) approxidate_careful((s), NULL) unsigned long approxidate_careful(const char *, int *); unsigned long approxidate_relative(const char *date, const struct timeval *now); -enum date_mode parse_date_format(const char *format); +void parse_date_format(const char *format, struct date_mode *mode); int date_overflows(unsigned long date); #define IDENT_STRICT 1 @@ -1107,7 +1119,8 @@ extern int split_ident_line(struct ident_split *, const char *, int); * the ident_split. It will also sanity-check the values and produce * a well-known sentinel date if they appear bogus. */ -const char *show_ident_date(const struct ident_split *id, enum date_mode mode); +const char *show_ident_date(const struct ident_split *id, + const struct date_mode *mode); /* * Compare split idents for equality or strict ordering. Note that we @@ -145,7 +145,7 @@ struct pretty_print_context { const char *subject; const char *after_subject; int preserve_subject; - enum date_mode date_mode; + struct date_mode date_mode; unsigned date_mode_explicit:1; int need_8bit_cte; char *notes_message; @@ -160,18 +160,27 @@ void show_date_relative(unsigned long time, int tz, (diff + 183) / 365); } -const char *show_date(unsigned long time, int tz, enum date_mode mode) +struct date_mode *date_mode_from_type(enum date_mode_type type) +{ + static struct date_mode mode; + if (type == DATE_STRFTIME) + die("BUG: cannot create anonymous strftime date_mode struct"); + mode.type = type; + return &mode; +} + +const char *show_date(unsigned long time, int tz, const struct date_mode *mode) { struct tm *tm; static struct strbuf timebuf = STRBUF_INIT; - if (mode == DATE_RAW) { + if (mode->type == DATE_RAW) { strbuf_reset(&timebuf); strbuf_addf(&timebuf, "%lu %+05d", time, tz); return timebuf.buf; } - if (mode == DATE_RELATIVE) { + if (mode->type == DATE_RELATIVE) { struct timeval now; strbuf_reset(&timebuf); @@ -180,7 +189,7 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) return timebuf.buf; } - if (mode == DATE_LOCAL) + if (mode->type == DATE_LOCAL) tz = local_tzoffset(time); tm = time_to_tm(time, tz); @@ -190,17 +199,17 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) } strbuf_reset(&timebuf); - if (mode == DATE_SHORT) + if (mode->type == DATE_SHORT) strbuf_addf(&timebuf, "%04d-%02d-%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); - else if (mode == DATE_ISO8601) + else if (mode->type == DATE_ISO8601) strbuf_addf(&timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+05d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tz); - else if (mode == DATE_ISO8601_STRICT) { + else if (mode->type == DATE_ISO8601_STRICT) { char sign = (tz >= 0) ? '+' : '-'; tz = abs(tz); strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", @@ -209,11 +218,13 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, sign, tz / 100, tz % 100); - } else if (mode == DATE_RFC2822) + } else if (mode->type == DATE_RFC2822) strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d", weekday_names[tm->tm_wday], tm->tm_mday, month_names[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec, tz); + else if (mode->type == DATE_STRFTIME) + strbuf_addftime(&timebuf, mode->strftime_fmt, tm); else strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d", weekday_names[tm->tm_wday], @@ -221,7 +232,7 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode) tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year + 1900, - (mode == DATE_LOCAL) ? 0 : ' ', + (mode->type == DATE_LOCAL) ? 0 : ' ', tz); return timebuf.buf; } @@ -759,28 +770,31 @@ int parse_date(const char *date, struct strbuf *result) return 0; } -enum date_mode parse_date_format(const char *format) +void parse_date_format(const char *format, struct date_mode *mode) { if (!strcmp(format, "relative")) - return DATE_RELATIVE; + mode->type = DATE_RELATIVE; else if (!strcmp(format, "iso8601") || !strcmp(format, "iso")) - return DATE_ISO8601; + mode->type = DATE_ISO8601; else if (!strcmp(format, "iso8601-strict") || !strcmp(format, "iso-strict")) - return DATE_ISO8601_STRICT; + mode->type = DATE_ISO8601_STRICT; else if (!strcmp(format, "rfc2822") || !strcmp(format, "rfc")) - return DATE_RFC2822; + mode->type = DATE_RFC2822; else if (!strcmp(format, "short")) - return DATE_SHORT; + mode->type = DATE_SHORT; else if (!strcmp(format, "local")) - return DATE_LOCAL; + mode->type = DATE_LOCAL; else if (!strcmp(format, "default")) - return DATE_NORMAL; + mode->type = DATE_NORMAL; else if (!strcmp(format, "raw")) - return DATE_RAW; - else + mode->type = DATE_RAW; + else if (skip_prefix(format, "format:", &format)) { + mode->type = DATE_STRFTIME; + mode->strftime_fmt = xstrdup(format); + } else die("unknown date format %s", format); } diff --git a/fast-import.c b/fast-import.c index 6a0c0ac570..2ad4fee07e 100644 --- a/fast-import.c +++ b/fast-import.c @@ -423,7 +423,7 @@ static void write_crash_report(const char *err) fprintf(rpt, "fast-import crash report:\n"); fprintf(rpt, " fast-import process: %"PRIuMAX"\n", (uintmax_t) getpid()); fprintf(rpt, " parent process : %"PRIuMAX"\n", (uintmax_t) getppid()); - fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL)); + fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_MODE(LOCAL))); fputc('\n', rpt); fputs("fatal: ", rpt); @@ -162,6 +162,7 @@ void git_setup_gettext(void) podir = GIT_LOCALE_PATH; bindtextdomain("git", podir); setlocale(LC_MESSAGES, ""); + setlocale(LC_TIME, ""); init_gettext_charset("git"); textdomain("git"); } diff --git a/http-backend.c b/http-backend.c index 501bf797c0..b977c006a4 100644 --- a/http-backend.c +++ b/http-backend.c @@ -92,7 +92,7 @@ static void hdr_int(const char *name, uintmax_t value) static void hdr_date(const char *name, unsigned long when) { - const char *value = show_date(when, 0, DATE_RFC2822); + const char *value = show_date(when, 0, DATE_MODE(RFC2822)); hdr_str(name, value); } diff --git a/log-tree.c b/log-tree.c index e2f6de73ef..7b1b57aaf6 100644 --- a/log-tree.c +++ b/log-tree.c @@ -640,7 +640,7 @@ void show_log(struct rev_info *opt) */ show_reflog_message(opt->reflog_info, opt->commit_format == CMIT_FMT_ONELINE, - opt->date_mode, + &opt->date_mode, opt->date_mode_explicit); if (opt->commit_format == CMIT_FMT_ONELINE) return; @@ -399,7 +399,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len, } const char *show_ident_date(const struct ident_split *ident, - enum date_mode mode) + const struct date_mode *mode) { unsigned long date = 0; long tz = 0; @@ -489,15 +489,15 @@ void pp_user_info(struct pretty_print_context *pp, switch (pp->fmt) { case CMIT_FMT_MEDIUM: strbuf_addf(sb, "Date: %s\n", - show_ident_date(&ident, pp->date_mode)); + show_ident_date(&ident, &pp->date_mode)); break; case CMIT_FMT_EMAIL: strbuf_addf(sb, "Date: %s\n", - show_ident_date(&ident, DATE_RFC2822)); + show_ident_date(&ident, DATE_MODE(RFC2822))); break; case CMIT_FMT_FULLER: strbuf_addf(sb, "%sDate: %s\n", what, - show_ident_date(&ident, pp->date_mode)); + show_ident_date(&ident, &pp->date_mode)); break; default: /* notin' */ @@ -671,7 +671,8 @@ static int mailmap_name(const char **email, size_t *email_len, } static size_t format_person_part(struct strbuf *sb, char part, - const char *msg, int len, enum date_mode dmode) + const char *msg, int len, + const struct date_mode *dmode) { /* currently all placeholders have same length */ const int placeholder_len = 2; @@ -711,16 +712,16 @@ static size_t format_person_part(struct strbuf *sb, char part, strbuf_addstr(sb, show_ident_date(&s, dmode)); return placeholder_len; case 'D': /* date, RFC2822 style */ - strbuf_addstr(sb, show_ident_date(&s, DATE_RFC2822)); + strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RFC2822))); return placeholder_len; case 'r': /* date, relative */ - strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE)); + strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RELATIVE))); return placeholder_len; case 'i': /* date, ISO 8601-like */ - strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601)); + strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601))); return placeholder_len; case 'I': /* date, ISO 8601 strict */ - strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601_STRICT)); + strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601_STRICT))); return placeholder_len; } @@ -933,7 +934,7 @@ static void rewrap_message_tail(struct strbuf *sb, static int format_reflog_person(struct strbuf *sb, char part, struct reflog_walk_info *log, - enum date_mode dmode) + const struct date_mode *dmode) { const char *ident; @@ -1185,7 +1186,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ if (c->pretty_ctx->reflog_info) get_reflog_selector(sb, c->pretty_ctx->reflog_info, - c->pretty_ctx->date_mode, + &c->pretty_ctx->date_mode, c->pretty_ctx->date_mode_explicit, (placeholder[1] == 'd')); return 2; @@ -1200,7 +1201,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ return format_reflog_person(sb, placeholder[1], c->pretty_ctx->reflog_info, - c->pretty_ctx->date_mode); + &c->pretty_ctx->date_mode); } return 0; /* unknown %g placeholder */ case 'N': @@ -1251,11 +1252,11 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ case 'a': /* author ... */ return format_person_part(sb, placeholder[1], msg + c->author.off, c->author.len, - c->pretty_ctx->date_mode); + &c->pretty_ctx->date_mode); case 'c': /* committer ... */ return format_person_part(sb, placeholder[1], msg + c->committer.off, c->committer.len, - c->pretty_ctx->date_mode); + &c->pretty_ctx->date_mode); case 'e': /* encoding */ if (c->commit_encoding) strbuf_addstr(sb, c->commit_encoding); diff --git a/ref-filter.c b/ref-filter.c index 6e09da88ca..f38dee4f60 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -362,7 +362,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam char *zone; unsigned long timestamp; long tz; - enum date_mode date_mode = DATE_NORMAL; + struct date_mode date_mode = { DATE_NORMAL }; const char *formatp; /* @@ -374,7 +374,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam formatp = strchr(atomname, ':'); if (formatp != NULL) { formatp++; - date_mode = parse_date_format(formatp); + parse_date_format(formatp, &date_mode); } if (!eoemail) @@ -385,7 +385,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam tz = strtol(zone, NULL, 10); if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE) goto bad; - v->s = xstrdup(show_date(timestamp, tz, date_mode)); + v->s = xstrdup(show_date(timestamp, tz, &date_mode)); v->ul = timestamp; return; bad: diff --git a/reflog-walk.c b/reflog-walk.c index 222de762eb..f8e743a23b 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -249,7 +249,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) void get_reflog_selector(struct strbuf *sb, struct reflog_walk_info *reflog_info, - enum date_mode dmode, int force_date, + const struct date_mode *dmode, int force_date, int shorten) { struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog; @@ -311,7 +311,7 @@ const char *get_reflog_ident(struct reflog_walk_info *reflog_info) } void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline, - enum date_mode dmode, int force_date) + const struct date_mode *dmode, int force_date) { if (reflog_info && reflog_info->last_commit_reflog) { struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog; diff --git a/reflog-walk.h b/reflog-walk.h index a9bd60e32d..27886f793e 100644 --- a/reflog-walk.h +++ b/reflog-walk.h @@ -11,13 +11,13 @@ extern int add_reflog_for_walk(struct reflog_walk_info *info, extern void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit); extern void show_reflog_message(struct reflog_walk_info *info, int, - enum date_mode, int force_date); + const struct date_mode *, int force_date); extern void get_reflog_message(struct strbuf *sb, struct reflog_walk_info *reflog_info); extern const char *get_reflog_ident(struct reflog_walk_info *reflog_info); extern void get_reflog_selector(struct strbuf *sb, struct reflog_walk_info *reflog_info, - enum date_mode dmode, int force_date, + const struct date_mode *dmode, int force_date, int shorten); #endif @@ -3436,14 +3436,14 @@ static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1, hashcpy(cb->sha1, nsha1); if (hashcmp(cb->osha1, nsha1)) warning("Log for ref %s has gap after %s.", - cb->refname, show_date(cb->date, cb->tz, DATE_RFC2822)); + cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); } else if (cb->date == cb->at_time) hashcpy(cb->sha1, nsha1); else if (hashcmp(nsha1, cb->sha1)) warning("Log for ref %s unexpectedly ended on %s.", cb->refname, show_date(cb->date, cb->tz, - DATE_RFC2822)); + DATE_MODE(RFC2822))); hashcpy(cb->osha1, osha1); hashcpy(cb->nsha1, nsha1); cb->found_it = 1; diff --git a/revision.c b/revision.c index ab97ffd459..cf60c5d817 100644 --- a/revision.c +++ b/revision.c @@ -1996,10 +1996,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--full-history")) { revs->simplify_history = 0; } else if (!strcmp(arg, "--relative-date")) { - revs->date_mode = DATE_RELATIVE; + revs->date_mode.type = DATE_RELATIVE; revs->date_mode_explicit = 1; } else if ((argcount = parse_long_opt("date", argv, &optarg))) { - revs->date_mode = parse_date_format(optarg); + parse_date_format(optarg, &revs->date_mode); revs->date_mode_explicit = 1; return argcount; } else if (!strcmp(arg, "--log-size")) { diff --git a/revision.h b/revision.h index 0ea8b4e255..5bc9686846 100644 --- a/revision.h +++ b/revision.h @@ -146,7 +146,7 @@ struct rev_info { track_first_time:1, linear:1; - enum date_mode date_mode; + struct date_mode date_mode; unsigned int abbrev; enum cmit_fmt commit_format; diff --git a/sha1_name.c b/sha1_name.c index e57513e610..da6874c15e 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -576,7 +576,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1, if (!(flags & GET_SHA1_QUIETLY)) { warning("Log for '%.*s' only goes " "back to %s.", len, str, - show_date(co_time, co_tz, DATE_RFC2822)); + show_date(co_time, co_tz, DATE_MODE(RFC2822))); } } else { if (flags & GET_SHA1_QUIETLY) { @@ -710,3 +710,36 @@ char *xstrfmt(const char *fmt, ...) return ret; } + +void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm) +{ + size_t hint = 128; + size_t len; + + if (!*fmt) + return; + + strbuf_grow(sb, hint); + len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm); + + if (!len) { + /* + * strftime reports "0" if it could not fit the result in the buffer. + * Unfortunately, it also reports "0" if the requested time string + * takes 0 bytes. So our strategy is to munge the format so that the + * output contains at least one character, and then drop the extra + * character before returning. + */ + struct strbuf munged_fmt = STRBUF_INIT; + strbuf_addf(&munged_fmt, "%s ", fmt); + while (!len) { + hint *= 2; + strbuf_grow(sb, hint); + len = strftime(sb->buf + sb->len, sb->alloc - sb->len, + munged_fmt.buf, tm); + } + strbuf_release(&munged_fmt); + len--; /* drop munged space */ + } + strbuf_setlen(sb, sb->len + len); +} @@ -345,6 +345,11 @@ __attribute__((format (printf,2,0))) extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap); /** + * Add the time specified by `tm`, as formatted by `strftime`. + */ +extern void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm); + +/** * Read a given size of data from a FILE* pointer to the buffer. * * NOTE: The buffer is rewound if the read fails. If -1 is returned, diff --git a/submodule.c b/submodule.c index 15e90d1c10..700bbf4fcb 100644 --- a/submodule.c +++ b/submodule.c @@ -993,7 +993,7 @@ static void print_commit(struct commit *commit) { struct strbuf sb = STRBUF_INIT; struct pretty_print_context ctx = {0}; - ctx.date_mode = DATE_NORMAL; + ctx.date_mode.type = DATE_NORMAL; format_commit_message(commit, " %h: %m %s", &sb, &ctx); fprintf(stderr, "%s\n", sb.buf); strbuf_release(&sb); diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 24fc2ba55d..7c9bec7630 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -227,6 +227,24 @@ test_expect_success 'Check format "rfc2822" date fields output' ' test_cmp expected actual ' +test_expect_success 'Check format of strftime date fields' ' + echo "my date is 2006-07-03" >expected && + git for-each-ref \ + --format="%(authordate:format:my date is %Y-%m-%d)" \ + refs/heads >actual && + test_cmp expected actual +' + +test_expect_success 'exercise strftime with odd fields' ' + echo >expected && + git for-each-ref --format="%(authordate:format:)" refs/heads >actual && + test_cmp expected actual && + long="long format -- $_z40$_z40$_z40$_z40$_z40$_z40$_z40" && + echo $long >expected && + git for-each-ref --format="%(authordate:format:$long)" refs/heads >actual && + test_cmp expected actual +' + cat >expected <<\EOF refs/heads/master refs/remotes/origin/master diff --git a/test-date.c b/test-date.c index 94a6997a8f..63f373557e 100644 --- a/test-date.c +++ b/test-date.c @@ -29,7 +29,7 @@ static void parse_dates(char **argv, struct timeval *now) parse_date(*argv, &result); if (sscanf(result.buf, "%lu %d", &t, &tz) == 2) printf("%s -> %s\n", - *argv, show_date(t, tz, DATE_ISO8601)); + *argv, show_date(t, tz, DATE_MODE(ISO8601))); else printf("%s -> bad\n", *argv); } @@ -41,7 +41,7 @@ static void parse_approxidate(char **argv, struct timeval *now) for (; *argv; argv++) { time_t t; t = approxidate_relative(*argv, now); - printf("%s -> %s\n", *argv, show_date(t, 0, DATE_ISO8601)); + printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601))); } } diff --git a/test-revision-walking.c b/test-revision-walking.c index 3ade02c72d..285f06b7ff 100644 --- a/test-revision-walking.c +++ b/test-revision-walking.c @@ -17,7 +17,7 @@ static void print_commit(struct commit *commit) { struct strbuf sb = STRBUF_INIT; struct pretty_print_context ctx = {0}; - ctx.date_mode = DATE_NORMAL; + ctx.date_mode.type = DATE_NORMAL; format_commit_message(commit, " %m %s", &sb, &ctx); printf("%s\n", sb.buf); strbuf_release(&sb); |