Merge branch 'jk/pretty-G-format-fixes' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 16 Jul 2014 18:17:21 +0000 (11:17 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 16 Jul 2014 18:17:21 +0000 (11:17 -0700)
"%G" (nothing after G) is an invalid pretty format specifier, but
the parser did not notice it as garbage.

* jk/pretty-G-format-fixes:
move "%G" format test from t7510 to t6006
pretty: avoid reading past end-of-string with "%G"
t7510: check %G* pretty-format output
t7510: test a commit signed by an unknown key
t7510: use consistent &&-chains in loop
t7510: stop referring to master in later tests

1  2 
pretty.c
t/t6006-rev-list-format.sh
diff --combined pretty.c
index 32099632f61e944cfa8022fd58d175c653ed47fe,fe249f8820f3787c737cad2da49c16b50c092601..f3e8b6c5bcffced1401b8550400c5b17817c24e2
+++ b/pretty.c
@@@ -274,7 -274,7 +274,7 @@@ static void add_rfc822_quoted(struct st
  
  enum rfc2047_type {
        RFC2047_SUBJECT,
 -      RFC2047_ADDRESS,
 +      RFC2047_ADDRESS
  };
  
  static int is_rfc2047_special(char ch, enum rfc2047_type type)
@@@ -606,16 -606,29 +606,16 @@@ static char *replace_encoding_header(ch
        return strbuf_detach(&tmp, NULL);
  }
  
 -char *logmsg_reencode(const struct commit *commit,
 -                    char **commit_encoding,
 -                    const char *output_encoding)
 +const char *logmsg_reencode(const struct commit *commit,
 +                          char **commit_encoding,
 +                          const char *output_encoding)
  {
        static const char *utf8 = "UTF-8";
        const char *use_encoding;
        char *encoding;
 -      char *msg = commit->buffer;
 +      const char *msg = get_commit_buffer(commit, NULL);
        char *out;
  
 -      if (!msg) {
 -              enum object_type type;
 -              unsigned long size;
 -
 -              msg = read_sha1_file(commit->object.sha1, &type, &size);
 -              if (!msg)
 -                      die("Cannot read commit object %s",
 -                          sha1_to_hex(commit->object.sha1));
 -              if (type != OBJ_COMMIT)
 -                      die("Expected commit for '%s', got %s",
 -                          sha1_to_hex(commit->object.sha1), typename(type));
 -      }
 -
        if (!output_encoding || !*output_encoding) {
                if (commit_encoding)
                        *commit_encoding =
                 * Otherwise, we still want to munge the encoding header in the
                 * result, which will be done by modifying the buffer. If we
                 * are using a fresh copy, we can reuse it. But if we are using
 -               * the cached copy from commit->buffer, we need to duplicate it
 -               * to avoid munging commit->buffer.
 +               * the cached copy from get_commit_buffer, we need to duplicate it
 +               * to avoid munging the cached copy.
                 */
 -              out = msg;
 -              if (out == commit->buffer)
 -                      out = xstrdup(out);
 +              if (msg == get_cached_commit_buffer(commit, NULL))
 +                      out = xstrdup(msg);
 +              else
 +                      out = (char *)msg;
        }
        else {
                /*
                 * copy, we can free it.
                 */
                out = reencode_string(msg, output_encoding, use_encoding);
 -              if (out && msg != commit->buffer)
 -                      free(msg);
 +              if (out)
 +                      unuse_commit_buffer(commit, msg);
        }
  
        /*
        return out ? out : msg;
  }
  
 -void logmsg_free(char *msg, const struct commit *commit)
 -{
 -      if (msg != commit->buffer)
 -              free(msg);
 -}
 -
  static int mailmap_name(const char **email, size_t *email_len,
                        const char **name, size_t *name_len)
  {
@@@ -778,7 -796,7 +778,7 @@@ struct format_commit_context 
        struct signature_check signature_check;
        enum flush_type flush_type;
        enum trunc_type truncate;
 -      char *message;
 +      const char *message;
        char *commit_encoding;
        size_t width, indent1, indent2;
        int auto_color;
@@@ -1249,6 -1267,8 +1249,8 @@@ static size_t format_commit_one(struct 
                        if (c->signature_check.key)
                                strbuf_addstr(sb, c->signature_check.key);
                        break;
+               default:
+                       return 0;
                }
                return 2;
        }
@@@ -1488,18 -1508,13 +1490,18 @@@ void format_commit_message(const struc
        context.commit = commit;
        context.pretty_ctx = pretty_ctx;
        context.wrap_start = sb->len;
 +      /*
 +       * convert a commit message to UTF-8 first
 +       * as far as 'format_commit_item' assumes it in UTF-8
 +       */
        context.message = logmsg_reencode(commit,
                                          &context.commit_encoding,
 -                                        output_enc);
 +                                        utf8);
  
        strbuf_expand(sb, format, format_commit_item, &context);
        rewrap_message_tail(sb, &context, 0, 0, 0);
  
 +      /* then convert a commit message to an actual output encoding */
        if (output_enc) {
                if (same_encoding(utf8, output_enc))
                        output_enc = NULL;
        }
  
        free(context.commit_encoding);
 -      logmsg_free(context.message, commit);
 +      unuse_commit_buffer(commit, context.message);
        free(context.signature_check.gpg_output);
        free(context.signature_check.signer);
  }
@@@ -1687,7 -1702,7 +1689,7 @@@ void pretty_print_commit(struct pretty_
        unsigned long beginning_of_body;
        int indent = 4;
        const char *msg;
 -      char *reencoded;
 +      const char *reencoded;
        const char *encoding;
        int need_8bit_cte = pp->need_8bit_cte;
  
        if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
                strbuf_addch(sb, '\n');
  
 -      logmsg_free(reencoded, commit);
 +      unuse_commit_buffer(commit, reencoded);
  }
  
  void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
index c277db64f75ac9f9c0cd617262824d76959fbfbd,9ab20ee09d60f2c6c8deae9f34ab21c557e6d9b6..88ed3191e871cd9a164c3c903f69b07e7d9cf937
@@@ -9,32 -9,19 +9,32 @@@ test_description='git rev-list --pretty
  . "$TEST_DIRECTORY"/lib-terminal.sh
  
  test_tick
 +# Tested non-UTF-8 encoding
 +test_encoding="ISO8859-1"
 +
  # String "added" in German
  # (translated with Google Translate),
  # encoded in UTF-8, used as a commit log message below.
 -added=$(printf "added (hinzugef\303\274gt) foo")
 -added_iso88591=$(echo "$added" | iconv -f utf-8 -t iso8859-1)
 +added_utf8_part=$(printf "\303\274")
 +added_utf8_part_iso88591=$(echo "$added_utf8_part" | iconv -f utf-8 -t $test_encoding)
 +added=$(printf "added (hinzugef${added_utf8_part}gt) foo")
 +added_iso88591=$(echo "$added" | iconv -f utf-8 -t $test_encoding)
  # same but "changed"
 -changed=$(printf "changed (ge\303\244ndert) foo")
 -changed_iso88591=$(echo "$changed" | iconv -f utf-8 -t iso8859-1)
 +changed_utf8_part=$(printf "\303\244")
 +changed_utf8_part_iso88591=$(echo "$changed_utf8_part" | iconv -f utf-8 -t $test_encoding)
 +changed=$(printf "changed (ge${changed_utf8_part}ndert) foo")
 +changed_iso88591=$(echo "$changed" | iconv -f utf-8 -t $test_encoding)
 +
 +# Count of char to truncate
 +# Number is chosen so, that non-ACSII characters
 +# (see $added_utf8_part and $changed_utf8_part)
 +# fall into truncated parts of appropriate words both from left and right
 +truncate_count=20
  
  test_expect_success 'setup' '
        : >foo &&
        git add foo &&
 -      git config i18n.commitEncoding iso8859-1 &&
 +      git config i18n.commitEncoding $test_encoding &&
        git commit -m "$added_iso88591" &&
        head1=$(git rev-parse --verify HEAD) &&
        head1_short=$(git rev-parse --verify --short $head1) &&
@@@ -137,9 -124,9 +137,9 @@@ EO
  
  test_format encoding %e <<EOF
  commit $head2
 -iso8859-1
 +$test_encoding
  commit $head1
 -iso8859-1
 +$test_encoding
  EOF
  
  test_format subject %s <<EOF
@@@ -149,13 -136,6 +149,13 @@@ commit $head
  $added
  EOF
  
 +test_format subject-truncated "%<($truncate_count,trunc)%s" <<EOF
 +commit $head2
 +changed (ge${changed_utf8_part}ndert)..
 +commit $head1
 +added (hinzugef${added_utf8_part}gt..
 +EOF
 +
  test_format body %b <<EOF
  commit $head2
  commit $head1
@@@ -223,16 -203,16 +223,16 @@@ test_expect_success '%C(auto) respects 
        )
  '
  
 -iconv -f utf-8 -t iso8859-1 > commit-msg <<EOF
 +iconv -f utf-8 -t $test_encoding > commit-msg <<EOF
  Test printing of complex bodies
  
  This commit message is much longer than the others,
 -and it will be encoded in iso8859-1. We should therefore
 -include an iso8859 character: ¡bueno!
 +and it will be encoded in $test_encoding. We should therefore
 +include an ISO8859 character: ¡bueno!
  EOF
  
  test_expect_success 'setup complex body' '
 -      git config i18n.commitencoding iso8859-1 &&
 +      git config i18n.commitencoding $test_encoding &&
        echo change2 >foo && git commit -a -F commit-msg &&
        head3=$(git rev-parse --verify HEAD) &&
        head3_short=$(git rev-parse --short $head3)
  
  test_format complex-encoding %e <<EOF
  commit $head3
 -iso8859-1
 +$test_encoding
  commit $head2
 -iso8859-1
 +$test_encoding
  commit $head1
 -iso8859-1
 +$test_encoding
  EOF
  
  test_format complex-subject %s <<EOF
@@@ -256,47 -236,20 +256,47 @@@ commit $head
  $added_iso88591
  EOF
  
 +test_format complex-subject-trunc "%<($truncate_count,trunc)%s" <<EOF
 +commit $head3
 +Test printing of c..
 +commit $head2
 +changed (ge${changed_utf8_part_iso88591}ndert)..
 +commit $head1
 +added (hinzugef${added_utf8_part_iso88591}gt..
 +EOF
 +
 +test_format complex-subject-mtrunc "%<($truncate_count,mtrunc)%s" <<EOF
 +commit $head3
 +Test prin..ex bodies
 +commit $head2
 +changed (..dert) foo
 +commit $head1
 +added (hi..f${added_utf8_part_iso88591}gt) foo
 +EOF
 +
 +test_format complex-subject-ltrunc "%<($truncate_count,ltrunc)%s" <<EOF
 +commit $head3
 +.. of complex bodies
 +commit $head2
 +..ged (ge${changed_utf8_part_iso88591}ndert) foo
 +commit $head1
 +.. (hinzugef${added_utf8_part_iso88591}gt) foo
 +EOF
 +
  test_expect_success 'prepare expected messages (for test %b)' '
        cat <<-EOF >expected.utf-8 &&
        commit $head3
        This commit message is much longer than the others,
 -      and it will be encoded in iso8859-1. We should therefore
 -      include an iso8859 character: ¡bueno!
 +      and it will be encoded in $test_encoding. We should therefore
 +      include an ISO8859 character: ¡bueno!
  
        commit $head2
        commit $head1
        EOF
 -      iconv -f utf-8 -t iso8859-1 expected.utf-8 >expected.iso8859-1
 +      iconv -f utf-8 -t $test_encoding expected.utf-8 >expected.ISO8859-1
  '
  
 -test_format complex-body %b <expected.iso8859-1
 +test_format complex-body %b <expected.ISO8859-1
  
  # Git uses i18n.commitEncoding if no i18n.logOutputEncoding set
  # so unset i18n.commitEncoding to test encoding conversion
@@@ -311,33 -264,6 +311,33 @@@ commit $head
  $added
  EOF
  
 +test_format complex-subject-commitencoding-unset-trunc "%<($truncate_count,trunc)%s" <<EOF
 +commit $head3
 +Test printing of c..
 +commit $head2
 +changed (ge${changed_utf8_part}ndert)..
 +commit $head1
 +added (hinzugef${added_utf8_part}gt..
 +EOF
 +
 +test_format complex-subject-commitencoding-unset-mtrunc "%<($truncate_count,mtrunc)%s" <<EOF
 +commit $head3
 +Test prin..ex bodies
 +commit $head2
 +changed (..dert) foo
 +commit $head1
 +added (hi..f${added_utf8_part}gt) foo
 +EOF
 +
 +test_format complex-subject-commitencoding-unset-ltrunc "%<($truncate_count,ltrunc)%s" <<EOF
 +commit $head3
 +.. of complex bodies
 +commit $head2
 +..ged (ge${changed_utf8_part}ndert) foo
 +commit $head1
 +.. (hinzugef${added_utf8_part}gt) foo
 +EOF
 +
  test_format complex-body-commitencoding-unset %b <expected.utf-8
  
  test_expect_success '%x00 shows NUL' '
@@@ -468,4 -394,10 +468,10 @@@ test_expect_success 'single-character n
        test_cmp expect actual
  '
  
+ test_expect_success 'unused %G placeholders are passed through' '
+       echo "%GX %G" >expect &&
+       git log -1 --format="%GX %G" >actual &&
+       test_cmp expect actual
+ '
  test_done