Merge branch 'rs/pretty-add-again'
authorJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 21:28:38 +0000 (14:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 21:28:38 +0000 (14:28 -0700)
The pretty-format specifiers like '%h', '%t', etc. had an
optimization that no longer works correctly. In preparation/hope
of getting it correctly implemented, first discard the optimization
that is broken.

* rs/pretty-add-again:
pretty: recalculate duplicate short hashes

1  2 
pretty.c
strbuf.c
strbuf.h
diff --combined pretty.c
index 09701bd2ffef3eb6d9104916e4119f757c06c244,37b37d0f9d435d40ab00f9b297d7935234106269..cc099dfdd1b1081fa142255c172bff8ee06c25b8
+++ b/pretty.c
@@@ -10,7 -10,6 +10,7 @@@
  #include "color.h"
  #include "reflog-walk.h"
  #include "gpg-interface.h"
 +#include "trailer.h"
  
  static char *user_format;
  static struct cmt_fmt_map {
@@@ -405,11 -404,11 +405,11 @@@ static void add_rfc2047(struct strbuf *
  const char *show_ident_date(const struct ident_split *ident,
                            const struct date_mode *mode)
  {
 -      unsigned long date = 0;
 +      timestamp_t date = 0;
        long tz = 0;
  
        if (ident->date_begin && ident->date_end)
 -              date = strtoul(ident->date_begin, NULL, 10);
 +              date = parse_timestamp(ident->date_begin, NULL, 10);
        if (date_overflows(date))
                date = 0;
        else {
@@@ -783,29 -782,9 +783,9 @@@ struct format_commit_context 
        size_t body_off;
  
        /* The following ones are relative to the result struct strbuf. */
-       struct chunk abbrev_commit_hash;
-       struct chunk abbrev_tree_hash;
-       struct chunk abbrev_parent_hashes;
        size_t wrap_start;
  };
  
- static int add_again(struct strbuf *sb, struct chunk *chunk)
- {
-       if (chunk->len) {
-               strbuf_adddup(sb, chunk->off, chunk->len);
-               return 1;
-       }
-       /*
-        * We haven't seen this chunk before.  Our caller is surely
-        * going to add it the hard way now.  Remember the most likely
-        * start of the to-be-added chunk: the current end of the
-        * struct strbuf.
-        */
-       chunk->off = sb->len;
-       return 0;
- }
  static void parse_commit_header(struct format_commit_context *context)
  {
        const char *msg = context->message;
@@@ -890,16 -869,6 +870,16 @@@ const char *format_subject(struct strbu
        return msg;
  }
  
 +static void format_trailers(struct strbuf *sb, const char *msg)
 +{
 +      struct trailer_info info;
 +
 +      trailer_info_get(&info, msg);
 +      strbuf_add(sb, info.trailer_start,
 +                 info.trailer_end - info.trailer_start);
 +      trailer_info_release(&info);
 +}
 +
  static void parse_commit_message(struct format_commit_context *c)
  {
        const char *msg = c->message + c->message_off;
@@@ -1137,7 -1106,7 +1117,7 @@@ static size_t format_commit_one(struct 
  
        /* these depend on the commit */
        if (!commit->object.parsed)
 -              parse_object(commit->object.oid.hash);
 +              parse_object(&commit->object.oid);
  
        switch (placeholder[0]) {
        case 'H':               /* commit hash */
                return 1;
        case 'h':               /* abbreviated commit hash */
                strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
-               if (add_again(sb, &c->abbrev_commit_hash)) {
-                       strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
-                       return 1;
-               }
                strbuf_add_unique_abbrev(sb, commit->object.oid.hash,
                                         c->pretty_ctx->abbrev);
                strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
-               c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
                return 1;
        case 'T':               /* tree hash */
                strbuf_addstr(sb, oid_to_hex(&commit->tree->object.oid));
                return 1;
        case 't':               /* abbreviated tree hash */
-               if (add_again(sb, &c->abbrev_tree_hash))
-                       return 1;
                strbuf_add_unique_abbrev(sb, commit->tree->object.oid.hash,
                                         c->pretty_ctx->abbrev);
-               c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
                return 1;
        case 'P':               /* parent hashes */
                for (p = commit->parents; p; p = p->next) {
                }
                return 1;
        case 'p':               /* abbreviated parent hashes */
-               if (add_again(sb, &c->abbrev_parent_hashes))
-                       return 1;
                for (p = commit->parents; p; p = p->next) {
                        if (p != commit->parents)
                                strbuf_addch(sb, ' ');
                        strbuf_add_unique_abbrev(sb, p->item->object.oid.hash,
                                                 c->pretty_ctx->abbrev);
                }
-               c->abbrev_parent_hashes.len = sb->len -
-                                             c->abbrev_parent_hashes.off;
                return 1;
        case 'm':               /* left/right/bottom */
                strbuf_addstr(sb, get_revision_mark(NULL, commit));
                        switch (c->signature_check.result) {
                        case 'G':
                        case 'B':
 +                      case 'E':
                        case 'U':
                        case 'N':
 +                      case 'X':
 +                      case 'Y':
 +                      case 'R':
                                strbuf_addch(sb, c->signature_check.result);
                        }
                        break;
                strbuf_addstr(sb, msg + c->body_off);
                return 1;
        }
 +
 +      if (starts_with(placeholder, "(trailers)")) {
 +              format_trailers(sb, msg + c->subject_off);
 +              return strlen("(trailers)");
 +      }
 +
        return 0;       /* unknown placeholder */
  }
  
@@@ -1607,9 -1554,8 +1575,9 @@@ void pp_title_line(struct pretty_print_
                                pp->preserve_subject ? "\n" : " ");
  
        strbuf_grow(sb, title.len + 1024);
 -      if (pp->subject) {
 -              strbuf_addstr(sb, pp->subject);
 +      if (pp->print_email_subject) {
 +              if (pp->rev)
 +                      fmt_output_email_subject(sb, pp->rev);
                if (needs_rfc2047_encoding(title.buf, title.len, RFC2047_SUBJECT))
                        add_rfc2047(sb, title.buf, title.len,
                                                encoding, RFC2047_SUBJECT);
@@@ -1819,7 -1765,7 +1787,7 @@@ void pretty_print_commit(struct pretty_
        }
  
        pp_header(pp, encoding, commit, &msg, sb);
 -      if (pp->fmt != CMIT_FMT_ONELINE && !pp->subject) {
 +      if (pp->fmt != CMIT_FMT_ONELINE && !pp->print_email_subject) {
                strbuf_addch(sb, '\n');
        }
  
diff --combined strbuf.c
index be3b9e37b1d969e86e913cc69ccab935f516a063,df2c113f2143be86d3557eeb71be3859510a9e06..c4e91a66567304ee7732e1121229e7098f45384a
+++ b/strbuf.c
@@@ -204,13 -204,6 +204,6 @@@ void strbuf_addbuf(struct strbuf *sb, c
        strbuf_setlen(sb, sb->len + sb2->len);
  }
  
- void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
- {
-       strbuf_grow(sb, len);
-       memcpy(sb->buf + sb->len, sb->buf + pos, len);
-       strbuf_setlen(sb, sb->len + len);
- }
  void strbuf_addchars(struct strbuf *sb, int c, size_t n)
  {
        strbuf_grow(sb, n);
@@@ -449,17 -442,6 +442,17 @@@ int strbuf_getcwd(struct strbuf *sb
                        strbuf_setlen(sb, strlen(sb->buf));
                        return 0;
                }
 +
 +              /*
 +               * If getcwd(3) is implemented as a syscall that falls
 +               * back to a regular lookup using readdir(3) etc. then
 +               * we may be able to avoid EACCES by providing enough
 +               * space to the syscall as it's not necessarily bound
 +               * to the same restrictions as the fallback.
 +               */
 +              if (errno == EACCES && guessed_len < PATH_MAX)
 +                      continue;
 +
                if (errno != ERANGE)
                        break;
        }
@@@ -718,17 -700,6 +711,17 @@@ void strbuf_add_absolute_path(struct st
        strbuf_addstr(sb, path);
  }
  
 +void strbuf_add_real_path(struct strbuf *sb, const char *path)
 +{
 +      if (sb->len) {
 +              struct strbuf resolved = STRBUF_INIT;
 +              strbuf_realpath(&resolved, path, 1);
 +              strbuf_addbuf(sb, &resolved);
 +              strbuf_release(&resolved);
 +      } else
 +              strbuf_realpath(sb, path, 1);
 +}
 +
  int printf_ln(const char *fmt, ...)
  {
        int ret;
@@@ -785,48 -756,14 +778,48 @@@ char *xstrfmt(const char *fmt, ...
        return ret;
  }
  
 -void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm)
 +void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
 +                   int tz_offset, const char *tz_name)
  {
 +      struct strbuf munged_fmt = STRBUF_INIT;
        size_t hint = 128;
        size_t len;
  
        if (!*fmt)
                return;
  
 +      /*
 +       * There is no portable way to pass timezone information to
 +       * strftime, so we handle %z and %Z here.
 +       */
 +      for (;;) {
 +              const char *percent = strchrnul(fmt, '%');
 +              strbuf_add(&munged_fmt, fmt, percent - fmt);
 +              if (!*percent)
 +                      break;
 +              fmt = percent + 1;
 +              switch (*fmt) {
 +              case '%':
 +                      strbuf_addstr(&munged_fmt, "%%");
 +                      fmt++;
 +                      break;
 +              case 'z':
 +                      strbuf_addf(&munged_fmt, "%+05d", tz_offset);
 +                      fmt++;
 +                      break;
 +              case 'Z':
 +                      if (tz_name) {
 +                              strbuf_addstr(&munged_fmt, tz_name);
 +                              fmt++;
 +                              break;
 +                      }
 +                      /* FALLTHROUGH */
 +              default:
 +                      strbuf_addch(&munged_fmt, '%');
 +              }
 +      }
 +      fmt = munged_fmt.buf;
 +
        strbuf_grow(sb, hint);
        len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
  
                 * 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);
 +              strbuf_addch(&munged_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_release(&munged_fmt);
        strbuf_setlen(sb, sb->len + len);
  }
  
@@@ -925,23 -863,3 +918,23 @@@ void strbuf_stripspace(struct strbuf *s
  
        strbuf_setlen(sb, j);
  }
 +
 +int strbuf_normalize_path(struct strbuf *src)
 +{
 +      struct strbuf dst = STRBUF_INIT;
 +
 +      strbuf_grow(&dst, src->len);
 +      if (normalize_path_copy(dst.buf, src->buf) < 0) {
 +              strbuf_release(&dst);
 +              return -1;
 +      }
 +
 +      /*
 +       * normalize_path does not tell us the new length, so we have to
 +       * compute it by looking for the new NUL it placed
 +       */
 +      strbuf_setlen(&dst, strlen(dst.buf));
 +      strbuf_swap(src, &dst);
 +      strbuf_release(&dst);
 +      return 0;
 +}
diff --combined strbuf.h
index 4559035c47268c0603119b90c7278c08c6b99a09,ca4eff8bff6cef22b876520f4a5befd26dc60ce9..3646a6291b5026fc6d9e211a0313d76e4d2e100d
+++ b/strbuf.h
@@@ -109,7 -109,9 +109,7 @@@ extern void strbuf_attach(struct strbu
   */
  static inline void strbuf_swap(struct strbuf *a, struct strbuf *b)
  {
 -      struct strbuf tmp = *a;
 -      *a = *b;
 -      *b = tmp;
 +      SWAP(*a, *b);
  }
  
  
@@@ -263,12 -265,6 +263,6 @@@ static inline void strbuf_addstr(struc
   */
  extern void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
  
- /**
-  * Copy part of the buffer from a given position till a given length to the
-  * end of the buffer.
-  */
- extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
  /**
   * This function can be used to expand a format string containing
   * placeholders. To that end, it parses the string and calls the specified
@@@ -340,14 -336,8 +334,14 @@@ extern void strbuf_vaddf(struct strbuf 
  
  /**
   * Add the time specified by `tm`, as formatted by `strftime`.
 + * `tz_name` is used to expand %Z internally unless it's NULL.
 + * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
 + * of Greenwich, and it's used to expand %z internally.  However, tokens
 + * with modifiers (e.g. %Ez) are passed to `strftime`.
   */
 -extern void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm);
 +extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
 +                          const struct tm *tm, int tz_offset,
 +                          const char *tz_name);
  
  /**
   * Read a given size of data from a FILE* pointer to the buffer.
@@@ -447,28 -437,6 +441,28 @@@ extern int strbuf_getcwd(struct strbuf 
   */
  extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
  
 +/**
 + * Canonize `path` (make it absolute, resolve symlinks, remove extra
 + * slashes) and append it to `sb`.  Die with an informative error
 + * message if there is a problem.
 + *
 + * The directory part of `path` (i.e., everything up to the last
 + * dir_sep) must denote a valid, existing directory, but the last
 + * component need not exist.
 + *
 + * Callers that don't mind links should use the more lightweight
 + * strbuf_add_absolute_path() instead.
 + */
 +extern void strbuf_add_real_path(struct strbuf *sb, const char *path);
 +
 +
 +/**
 + * Normalize in-place the path contained in the strbuf. See
 + * normalize_path_copy() for details. If an error occurs, the contents of "sb"
 + * are left untouched, and -1 is returned.
 + */
 +extern int strbuf_normalize_path(struct strbuf *sb);
 +
  /**
   * Strip whitespace from a buffer. The second parameter controls if
   * comments are considered contents to be removed or not.
@@@ -580,26 -548,7 +574,26 @@@ static inline void strbuf_complete_line
        strbuf_complete(sb, '\n');
  }
  
 -extern int strbuf_branchname(struct strbuf *sb, const char *name);
 +/*
 + * Copy "name" to "sb", expanding any special @-marks as handled by
 + * interpret_branch_name(). The result is a non-qualified branch name
 + * (so "foo" or "origin/master" instead of "refs/heads/foo" or
 + * "refs/remotes/origin/master").
 + *
 + * Note that the resulting name may not be a syntactically valid refname.
 + *
 + * If "allowed" is non-zero, restrict the set of allowed expansions. See
 + * interpret_branch_name() for details.
 + */
 +extern void strbuf_branchname(struct strbuf *sb, const char *name,
 +                            unsigned allowed);
 +
 +/*
 + * Like strbuf_branchname() above, but confirm that the result is
 + * syntactically valid to be used as a local branch name in refs/heads/.
 + *
 + * The return value is "0" if the result is valid, and "-1" otherwise.
 + */
  extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
  
  extern void strbuf_addstr_urlencode(struct strbuf *, const char *,