From b3b36a68d16f1fdc383a06fbe85c3cc042d86314 Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Thu, 10 Apr 2014 12:43:16 +0200 Subject: [PATCH 1/9] Introduce git_buf_putcn Allows for inserting the same character n amount of times --- src/buffer.c | 9 +++++++++ src/buffer.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/buffer.c b/src/buffer.c index 83960e91265..f6e34a4458c 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -148,6 +148,15 @@ int git_buf_putc(git_buf *buf, char c) return 0; } +int git_buf_putcn(git_buf *buf, char c, size_t len) +{ + ENSURE_SIZE(buf, buf->size + len + 1); + memset(buf->ptr + buf->size, c, len); + buf->size += len; + buf->ptr[buf->size] = '\0'; + return 0; +} + int git_buf_put(git_buf *buf, const char *data, size_t len) { ENSURE_SIZE(buf, buf->size + len + 1); diff --git a/src/buffer.h b/src/buffer.h index dba594d973d..398aec9b73a 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -88,6 +88,7 @@ GIT_INLINE(bool) git_buf_oom(const git_buf *buf) */ int git_buf_sets(git_buf *buf, const char *string); int git_buf_putc(git_buf *buf, char c); +int git_buf_putcn(git_buf *buf, char c, size_t len); int git_buf_put(git_buf *buf, const char *data, size_t len); int git_buf_puts(git_buf *buf, const char *string); int git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3); From 8e14b47fd788ce5ae0d1a003a8fba17753eb7db5 Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Thu, 10 Apr 2014 12:42:29 +0200 Subject: [PATCH 2/9] Introduce git__date_rfc2822_fmt. Allows for RFC2822 date headers --- src/date.c | 28 ++++++++++++++++++++++++++++ src/util.h | 12 ++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/date.c b/src/date.c index 7849c2f025f..0e1b31aeed3 100644 --- a/src/date.c +++ b/src/date.c @@ -874,3 +874,31 @@ int git__date_parse(git_time_t *out, const char *date) *out = approxidate_str(date, time_sec, &error_ret); return error_ret; } + +int git__date_rfc2822_fmt(char *out, size_t len, const git_time *date) +{ + int written; + struct tm gmt; + time_t t; + + assert(out && date); + + t = (time_t) (date->time + date->offset * 60); + + if (p_gmtime_r (&t, &gmt) == NULL) + return -1; + + written = p_snprintf(out, len, "%.3s, %u %.3s %.4u %02u:%02u:%02u %+03d%02d", + weekday_names[gmt.tm_wday], + gmt.tm_mday, + month_names[gmt.tm_mon], + gmt.tm_year + 1900, + gmt.tm_hour, gmt.tm_min, gmt.tm_sec, + date->offset / 60, date->offset % 60); + + if (written < 0 || (written > (int) len - 1)) + return -1; + + return 0; +} + diff --git a/src/util.h b/src/util.h index e378786d9d4..5c2c563d662 100644 --- a/src/util.h +++ b/src/util.h @@ -20,6 +20,8 @@ # define max(a,b) ((a) > (b) ? (a) : (b)) #endif +#define GIT_DATE_RFC2822_SZ 32 + /* * Custom memory allocation wrappers * that set error code and error message @@ -328,6 +330,16 @@ extern int git__parse_bool(int *out, const char *value); */ extern int git__date_parse(git_time_t *out, const char *date); +/* + * Format a git_time as a RFC2822 string + * + * @param out buffer to store formatted date; a '\\0' terminator will automatically be added. + * @param len size of the buffer; should be atleast `GIT_DATE_RFC2822_SZ` in size; + * @param date the date to be formatted + * @return 0 if successful; -1 on error + */ +extern int git__date_rfc2822_fmt(char *out, size_t len, const git_time *date); + /* * Unescapes a string in-place. * From 51297cadb32df3f7e1b1820034ff5a4ed6703668 Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Thu, 10 Apr 2014 12:44:12 +0200 Subject: [PATCH 3/9] Added RFC2822 date format test cases --- tests/date/rfc2822.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/date/rfc2822.c diff --git a/tests/date/rfc2822.c b/tests/date/rfc2822.c new file mode 100644 index 00000000000..eda475ac980 --- /dev/null +++ b/tests/date/rfc2822.c @@ -0,0 +1,40 @@ +#include "clar_libgit2.h" + +#include "util.h" + +void test_date_rfc2822__format_rfc2822_no_offset(void) +{ + git_time t = {1397031663, 0}; + char buf[GIT_DATE_RFC2822_SZ]; + + cl_git_pass(git__date_rfc2822_fmt(buf, sizeof(buf), &t)); + cl_assert(strcmp(buf, "Wed, 9 Apr 2014 08:21:03 +0000") == 0); +} + +void test_date_rfc2822__format_rfc2822_positive_offset(void) +{ + git_time t = {1397031663, 120}; + char buf[GIT_DATE_RFC2822_SZ]; + + cl_git_pass(git__date_rfc2822_fmt(buf, sizeof(buf), &t)); + cl_assert(strcmp(buf, "Wed, 9 Apr 2014 10:21:03 +0200") == 0); +} + +void test_date_rfc2822__format_rfc2822_negative_offset(void) +{ + git_time t = {1397031663, -120}; + char buf[GIT_DATE_RFC2822_SZ]; + + cl_git_pass(git__date_rfc2822_fmt(buf, sizeof(buf), &t)); + cl_assert(strcmp(buf, "Wed, 9 Apr 2014 06:21:03 -0200") == 0); +} + +void test_date_rfc2822__format_rfc2822_buffer_too_small(void) +{ + // "Wed, 10 Apr 2014 08:21:03 +0000" + git_time t = {1397031663 + 86400, 0}; + char buf[GIT_DATE_RFC2822_SZ-1]; + + cl_git_fail(git__date_rfc2822_fmt(buf, sizeof(buf), &t)); +} + From 7a28f268adc1d2569ce504147af05834ae94c01a Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Thu, 10 Apr 2014 12:44:51 +0200 Subject: [PATCH 4/9] Fix const-correctness of git_patch_get_delta, git_patch_num_hunks, git_patch_num_lines_in_hunk --- include/git2/patch.h | 6 +++--- src/diff_patch.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/git2/patch.h b/include/git2/patch.h index f5ec682c628..47c3956690a 100644 --- a/include/git2/patch.h +++ b/include/git2/patch.h @@ -141,12 +141,12 @@ GIT_EXTERN(void) git_patch_free(git_patch *patch); /** * Get the delta associated with a patch */ -GIT_EXTERN(const git_diff_delta *) git_patch_get_delta(git_patch *patch); +GIT_EXTERN(const git_diff_delta *) git_patch_get_delta(const git_patch *patch); /** * Get the number of hunks in a patch */ -GIT_EXTERN(size_t) git_patch_num_hunks(git_patch *patch); +GIT_EXTERN(size_t) git_patch_num_hunks(const git_patch *patch); /** * Get line counts of each type in a patch. @@ -197,7 +197,7 @@ GIT_EXTERN(int) git_patch_get_hunk( * @return Number of lines in hunk or -1 if invalid hunk index */ GIT_EXTERN(int) git_patch_num_lines_in_hunk( - git_patch *patch, + const git_patch *patch, size_t hunk_idx); /** diff --git a/src/diff_patch.c b/src/diff_patch.c index dd8b73938f4..38d5f425766 100644 --- a/src/diff_patch.c +++ b/src/diff_patch.c @@ -631,13 +631,13 @@ void git_patch_free(git_patch *patch) GIT_REFCOUNT_DEC(patch, diff_patch_free); } -const git_diff_delta *git_patch_get_delta(git_patch *patch) +const git_diff_delta *git_patch_get_delta(const git_patch *patch) { assert(patch); return patch->delta; } -size_t git_patch_num_hunks(git_patch *patch) +size_t git_patch_num_hunks(const git_patch *patch) { assert(patch); return git_array_size(patch->hunks); @@ -708,7 +708,7 @@ int git_patch_get_hunk( return 0; } -int git_patch_num_lines_in_hunk(git_patch *patch, size_t hunk_idx) +int git_patch_num_lines_in_hunk(const git_patch *patch, size_t hunk_idx) { diff_patch_hunk *hunk; assert(patch); From cab39378dc4dba7cc501255f066808c713dd11ef Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Fri, 11 Apr 2014 19:14:18 +0200 Subject: [PATCH 5/9] Added git_diff_stats test files --- tests/resources/diff_format_email/.gitted/HEAD | 1 + .../resources/diff_format_email/.gitted/config | 7 +++++++ .../resources/diff_format_email/.gitted/index | Bin 0 -> 256 bytes .../diff_format_email/.gitted/info/exclude | 6 ++++++ .../0a/37045ca6d8503e9bcf06a12abbbc8e92664cce | Bin 0 -> 29 bytes .../10/808fe9c9be5a190c0ba68d1a002233fb363508 | Bin 0 -> 176 bytes .../13/ecf3d572dbc5e5b32c8ba067d1d1e0939572e8 | Bin 0 -> 34 bytes .../17/cfad36e93db7706b16bef5ef842ba1e5ca06ab | Bin 0 -> 155 bytes .../1a/9932083f96b0db42552103d40076f62fa8235e | Bin 0 -> 54 bytes .../1a/e3be57f869687d983066a0f5d2aaea1b82ddc5 | Bin 0 -> 162 bytes .../1b/525b0a6c5218b069b601ce91fce8eaf0a54e20 | Bin 0 -> 31 bytes .../1e/82c3b234e37da82e5b23e0e2a70bca68ee12c6 | Bin 0 -> 28 bytes .../1e/875da9b1e67f853b2eec3e202c21c867097234 | Bin 0 -> 121 bytes .../20/609dbbc32bbfc827528eec3fcea2d024e6dd8a | Bin 0 -> 121 bytes .../23/f92946d3f38bd090f700d3e8e7b728ffc58264 | Bin 0 -> 155 bytes .../24/97c5249408494e66e25070a8c74e49eaeeb6c3 | Bin 0 -> 162 bytes .../24/9a4263be23b4d1c02484cb840b6eca4c6cf74d | Bin 0 -> 171 bytes .../25/2a3e19fd2c6fb7b20c111142c5bd5fb9ea6b8e | Bin 0 -> 121 bytes .../27/93544db9060bab4f9169e5b89c82f9fa7c7fa6 | Bin 0 -> 120 bytes .../29/1f1ff3cbb9a6f153678d9657679e3d4bf257df | Bin 0 -> 29 bytes .../2f/f7b811eee62a73959350b1f7349f6f4d0c882d | Bin 0 -> 54 bytes .../39/91dce9e71a0641ca49a6a4eea6c9e7ff402ed4 | Bin 0 -> 166 bytes .../45/eef2a9317e179984649de247269e38cd5d99cf | 2 ++ .../4a/076277b884c519a932be67e346db2ac80a98fa | Bin 0 -> 40 bytes .../4c/3bd7182ad66ea7aa20ba47ae82812b710d169c | Bin 0 -> 179 bytes .../4c/a10087e696d2ba78d07b146a118e9a7096ed4f | Bin 0 -> 173 bytes .../4d/de2b17d1c982cd988f21d24350a214401e4a1e | Bin 0 -> 121 bytes .../4f/31e0248ac800a1edc78b74f74e86f5eba90e87 | Bin 0 -> 54 bytes .../50/17c9456d013b2c7712d29aab73b681c880f509 | Bin 0 -> 54 bytes .../50/438cfa585c1d15cf3650ed1bf641da937cc261 | Bin 0 -> 123 bytes .../52/c3cd1ff6234b95fecbaf9ef13624da17697b8d | Bin 0 -> 41 bytes .../55/0d730ba1b8c4937ea170b37c7ba91d792c0aaa | Bin 0 -> 123 bytes .../66/81f1844dc677e5ff07ffd993461f5c441e6af5 | Bin 0 -> 35 bytes .../69/ddefb5c245e2f9ee62bd4cabd8ebe60a01e448 | Bin 0 -> 54 bytes .../6b/6c2067c6d968f9bddb9b900ee1ab7e5b067430 | 2 ++ .../6b/ef49b206b29d9c46456e075722cd1a48b41e4c | Bin 0 -> 121 bytes .../6c/15659c036377aebf3b4569959ca1f5bedb551f | Bin 0 -> 167 bytes .../6e/05acc5a5dab507d91a0a0cc0fb05a3dd98892d | 2 ++ .../74/6d514eae0c330261d37940cab33aa97fefbd93 | 1 + .../74/a4d5394ebcfa7e9f445680897dfbc96586bc86 | Bin 0 -> 38 bytes .../77/d0a3ed37236a7941d564f08d68d3b36462d231 | 2 ++ .../7a/de76dd34bba4733cf9878079f9fd4a456a9189 | 3 +++ .../7a/ff11da95ca2be0bfb74b06e7cc1c480559dbe7 | Bin 0 -> 26 bytes .../7f/854619451620f7fbcec7ea171675e615ce92b6 | Bin 0 -> 179 bytes .../87/3806f6f27e631eb0b23e4b56bea2bfac14a373 | Bin 0 -> 181 bytes .../89/47a46e2097638ca6040ad4877246f4186ec3bd | 2 ++ .../89/7d3af16ca9e420cd071b1c4541bd2b91d04c8c | 1 + .../8d/7523f6fcb2404257889abe0d96f093d9f524f9 | 1 + .../8d/fa038554d5b682a51bda8ee3038cee6c63be76 | Bin 0 -> 120 bytes .../92/64b96c6d104d0e07ae33d3007b6a48246c6f92 | Bin 0 -> 181 bytes .../94/350226b3aa14efac831c803a51f7a09f3fc31a | Bin 0 -> 24 bytes .../94/75e21dcbc515af8f641576400e4b450e5f4c03 | Bin 0 -> 62 bytes .../94/aaae8954e8bb613de636071da663a621695911 | Bin 0 -> 29 bytes .../9a/2d780ac2ea0aeabdb9d2a876e6bbfff17b2c44 | Bin 0 -> 28 bytes .../9a/c0329b8b7a4046210d8b8b02ac02055667de63 | Bin 0 -> 29 bytes .../9a/c35ff15cd8864aeafd889e4826a3150f0b06c4 | Bin 0 -> 20 bytes .../9b/997daca2a0beb5cc44b32c64f100a9a26d4d4b | Bin 0 -> 22 bytes .../a3/ac918e3a6604294b239cb956363e83d71abb3b | 1 + .../a5/ac978d4f2a1784f847f41223a34c3e78934238 | Bin 0 -> 54 bytes .../a7/29eab45c84563135e8631d4010230bc0479f1f | Bin 0 -> 40 bytes .../a9/7157a0d0571698728b6f2f7675b456c98c5961 | Bin 0 -> 62 bytes .../af/8f41d0cb7a3079a8f8e231ea2ab8b97837ce13 | Bin 0 -> 50 bytes .../b0/5cecf1949d192b6df852b3f71853ef820ee235 | Bin 0 -> 37 bytes .../b4/f457c219dbb3517be908d4e70f0ada2fd8b8f9 | Bin 0 -> 54 bytes .../bd/474b2519cc15eab801ff851cc7d50f0dee49a1 | Bin 0 -> 18 bytes .../bd/f7ba6bc5c4e57ca6595928dcbe6753c8a663ff | Bin 0 -> 35 bytes .../cb/a89408dc016f4caddb6dc886fcb58f587a78df | 3 +++ .../cd/471f0d8770371e1bc78bcbb38db4c7e4106bd2 | Bin 0 -> 180 bytes .../cd/ed722d05305c6b181f188c118d2d9810f39bb8 | Bin 0 -> 163 bytes .../ce/2792fcae8d704a56901754a0583a7418a21d8a | Bin 0 -> 121 bytes .../d1/4aa252e52a709d03a3d3d0d965e177eb0a674e | 1 + .../d7/bb447df12c6a8aba8727005482fb211f11297a | Bin 0 -> 156 bytes .../db/e8727e4806ae88ccc3f0755cae8f8cb7efa2cc | Bin 0 -> 175 bytes .../e1/2af77c510e8ce4c261a3758736109c2c2dd1f0 | Bin 0 -> 51 bytes .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin 0 -> 15 bytes .../e9/091231467304a5ef112de02361d795ef051ee1 | Bin 0 -> 24 bytes .../ee/251372f131d82e575f16fe51c778406d88f8c2 | 2 ++ .../f3/d35bd592fefd8280fc0c302fa9f27dbdd721a3 | 1 + .../f4/07be01334e07bfb8f57cd2078f0ee3eb61e085 | 1 + .../f9/e215d309644e24fa50d6bd6e6eedba166e56bc | 2 ++ .../fc/a0c10eb9f1af6494a448d5733d283f5232a514 | Bin 0 -> 176 bytes .../ff/8d35b41494f7f0dc92f95d67f54fff274d3fcb | Bin 0 -> 29 bytes .../.gitted/refs/heads/binary | 1 + .../.gitted/refs/heads/master | 1 + .../.gitted/refs/heads/multihunk | 1 + .../.gitted/refs/heads/rename | 1 + .../diff_format_email/file1.txt.renamed | 17 +++++++++++++++++ tests/resources/diff_format_email/file2.txt | 5 +++++ tests/resources/diff_format_email/file3.txt | 5 +++++ 89 files changed, 72 insertions(+) create mode 100644 tests/resources/diff_format_email/.gitted/HEAD create mode 100644 tests/resources/diff_format_email/.gitted/config create mode 100644 tests/resources/diff_format_email/.gitted/index create mode 100644 tests/resources/diff_format_email/.gitted/info/exclude create mode 100644 tests/resources/diff_format_email/.gitted/objects/0a/37045ca6d8503e9bcf06a12abbbc8e92664cce create mode 100644 tests/resources/diff_format_email/.gitted/objects/10/808fe9c9be5a190c0ba68d1a002233fb363508 create mode 100644 tests/resources/diff_format_email/.gitted/objects/13/ecf3d572dbc5e5b32c8ba067d1d1e0939572e8 create mode 100644 tests/resources/diff_format_email/.gitted/objects/17/cfad36e93db7706b16bef5ef842ba1e5ca06ab create mode 100644 tests/resources/diff_format_email/.gitted/objects/1a/9932083f96b0db42552103d40076f62fa8235e create mode 100644 tests/resources/diff_format_email/.gitted/objects/1a/e3be57f869687d983066a0f5d2aaea1b82ddc5 create mode 100644 tests/resources/diff_format_email/.gitted/objects/1b/525b0a6c5218b069b601ce91fce8eaf0a54e20 create mode 100644 tests/resources/diff_format_email/.gitted/objects/1e/82c3b234e37da82e5b23e0e2a70bca68ee12c6 create mode 100644 tests/resources/diff_format_email/.gitted/objects/1e/875da9b1e67f853b2eec3e202c21c867097234 create mode 100644 tests/resources/diff_format_email/.gitted/objects/20/609dbbc32bbfc827528eec3fcea2d024e6dd8a create mode 100644 tests/resources/diff_format_email/.gitted/objects/23/f92946d3f38bd090f700d3e8e7b728ffc58264 create mode 100644 tests/resources/diff_format_email/.gitted/objects/24/97c5249408494e66e25070a8c74e49eaeeb6c3 create mode 100644 tests/resources/diff_format_email/.gitted/objects/24/9a4263be23b4d1c02484cb840b6eca4c6cf74d create mode 100644 tests/resources/diff_format_email/.gitted/objects/25/2a3e19fd2c6fb7b20c111142c5bd5fb9ea6b8e create mode 100644 tests/resources/diff_format_email/.gitted/objects/27/93544db9060bab4f9169e5b89c82f9fa7c7fa6 create mode 100644 tests/resources/diff_format_email/.gitted/objects/29/1f1ff3cbb9a6f153678d9657679e3d4bf257df create mode 100644 tests/resources/diff_format_email/.gitted/objects/2f/f7b811eee62a73959350b1f7349f6f4d0c882d create mode 100644 tests/resources/diff_format_email/.gitted/objects/39/91dce9e71a0641ca49a6a4eea6c9e7ff402ed4 create mode 100644 tests/resources/diff_format_email/.gitted/objects/45/eef2a9317e179984649de247269e38cd5d99cf create mode 100644 tests/resources/diff_format_email/.gitted/objects/4a/076277b884c519a932be67e346db2ac80a98fa create mode 100644 tests/resources/diff_format_email/.gitted/objects/4c/3bd7182ad66ea7aa20ba47ae82812b710d169c create mode 100644 tests/resources/diff_format_email/.gitted/objects/4c/a10087e696d2ba78d07b146a118e9a7096ed4f create mode 100644 tests/resources/diff_format_email/.gitted/objects/4d/de2b17d1c982cd988f21d24350a214401e4a1e create mode 100644 tests/resources/diff_format_email/.gitted/objects/4f/31e0248ac800a1edc78b74f74e86f5eba90e87 create mode 100644 tests/resources/diff_format_email/.gitted/objects/50/17c9456d013b2c7712d29aab73b681c880f509 create mode 100644 tests/resources/diff_format_email/.gitted/objects/50/438cfa585c1d15cf3650ed1bf641da937cc261 create mode 100644 tests/resources/diff_format_email/.gitted/objects/52/c3cd1ff6234b95fecbaf9ef13624da17697b8d create mode 100644 tests/resources/diff_format_email/.gitted/objects/55/0d730ba1b8c4937ea170b37c7ba91d792c0aaa create mode 100644 tests/resources/diff_format_email/.gitted/objects/66/81f1844dc677e5ff07ffd993461f5c441e6af5 create mode 100644 tests/resources/diff_format_email/.gitted/objects/69/ddefb5c245e2f9ee62bd4cabd8ebe60a01e448 create mode 100644 tests/resources/diff_format_email/.gitted/objects/6b/6c2067c6d968f9bddb9b900ee1ab7e5b067430 create mode 100644 tests/resources/diff_format_email/.gitted/objects/6b/ef49b206b29d9c46456e075722cd1a48b41e4c create mode 100644 tests/resources/diff_format_email/.gitted/objects/6c/15659c036377aebf3b4569959ca1f5bedb551f create mode 100644 tests/resources/diff_format_email/.gitted/objects/6e/05acc5a5dab507d91a0a0cc0fb05a3dd98892d create mode 100644 tests/resources/diff_format_email/.gitted/objects/74/6d514eae0c330261d37940cab33aa97fefbd93 create mode 100644 tests/resources/diff_format_email/.gitted/objects/74/a4d5394ebcfa7e9f445680897dfbc96586bc86 create mode 100644 tests/resources/diff_format_email/.gitted/objects/77/d0a3ed37236a7941d564f08d68d3b36462d231 create mode 100644 tests/resources/diff_format_email/.gitted/objects/7a/de76dd34bba4733cf9878079f9fd4a456a9189 create mode 100644 tests/resources/diff_format_email/.gitted/objects/7a/ff11da95ca2be0bfb74b06e7cc1c480559dbe7 create mode 100644 tests/resources/diff_format_email/.gitted/objects/7f/854619451620f7fbcec7ea171675e615ce92b6 create mode 100644 tests/resources/diff_format_email/.gitted/objects/87/3806f6f27e631eb0b23e4b56bea2bfac14a373 create mode 100644 tests/resources/diff_format_email/.gitted/objects/89/47a46e2097638ca6040ad4877246f4186ec3bd create mode 100644 tests/resources/diff_format_email/.gitted/objects/89/7d3af16ca9e420cd071b1c4541bd2b91d04c8c create mode 100644 tests/resources/diff_format_email/.gitted/objects/8d/7523f6fcb2404257889abe0d96f093d9f524f9 create mode 100644 tests/resources/diff_format_email/.gitted/objects/8d/fa038554d5b682a51bda8ee3038cee6c63be76 create mode 100644 tests/resources/diff_format_email/.gitted/objects/92/64b96c6d104d0e07ae33d3007b6a48246c6f92 create mode 100644 tests/resources/diff_format_email/.gitted/objects/94/350226b3aa14efac831c803a51f7a09f3fc31a create mode 100644 tests/resources/diff_format_email/.gitted/objects/94/75e21dcbc515af8f641576400e4b450e5f4c03 create mode 100644 tests/resources/diff_format_email/.gitted/objects/94/aaae8954e8bb613de636071da663a621695911 create mode 100644 tests/resources/diff_format_email/.gitted/objects/9a/2d780ac2ea0aeabdb9d2a876e6bbfff17b2c44 create mode 100644 tests/resources/diff_format_email/.gitted/objects/9a/c0329b8b7a4046210d8b8b02ac02055667de63 create mode 100644 tests/resources/diff_format_email/.gitted/objects/9a/c35ff15cd8864aeafd889e4826a3150f0b06c4 create mode 100644 tests/resources/diff_format_email/.gitted/objects/9b/997daca2a0beb5cc44b32c64f100a9a26d4d4b create mode 100644 tests/resources/diff_format_email/.gitted/objects/a3/ac918e3a6604294b239cb956363e83d71abb3b create mode 100644 tests/resources/diff_format_email/.gitted/objects/a5/ac978d4f2a1784f847f41223a34c3e78934238 create mode 100644 tests/resources/diff_format_email/.gitted/objects/a7/29eab45c84563135e8631d4010230bc0479f1f create mode 100644 tests/resources/diff_format_email/.gitted/objects/a9/7157a0d0571698728b6f2f7675b456c98c5961 create mode 100644 tests/resources/diff_format_email/.gitted/objects/af/8f41d0cb7a3079a8f8e231ea2ab8b97837ce13 create mode 100644 tests/resources/diff_format_email/.gitted/objects/b0/5cecf1949d192b6df852b3f71853ef820ee235 create mode 100644 tests/resources/diff_format_email/.gitted/objects/b4/f457c219dbb3517be908d4e70f0ada2fd8b8f9 create mode 100644 tests/resources/diff_format_email/.gitted/objects/bd/474b2519cc15eab801ff851cc7d50f0dee49a1 create mode 100644 tests/resources/diff_format_email/.gitted/objects/bd/f7ba6bc5c4e57ca6595928dcbe6753c8a663ff create mode 100644 tests/resources/diff_format_email/.gitted/objects/cb/a89408dc016f4caddb6dc886fcb58f587a78df create mode 100644 tests/resources/diff_format_email/.gitted/objects/cd/471f0d8770371e1bc78bcbb38db4c7e4106bd2 create mode 100644 tests/resources/diff_format_email/.gitted/objects/cd/ed722d05305c6b181f188c118d2d9810f39bb8 create mode 100644 tests/resources/diff_format_email/.gitted/objects/ce/2792fcae8d704a56901754a0583a7418a21d8a create mode 100644 tests/resources/diff_format_email/.gitted/objects/d1/4aa252e52a709d03a3d3d0d965e177eb0a674e create mode 100644 tests/resources/diff_format_email/.gitted/objects/d7/bb447df12c6a8aba8727005482fb211f11297a create mode 100644 tests/resources/diff_format_email/.gitted/objects/db/e8727e4806ae88ccc3f0755cae8f8cb7efa2cc create mode 100644 tests/resources/diff_format_email/.gitted/objects/e1/2af77c510e8ce4c261a3758736109c2c2dd1f0 create mode 100644 tests/resources/diff_format_email/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 create mode 100644 tests/resources/diff_format_email/.gitted/objects/e9/091231467304a5ef112de02361d795ef051ee1 create mode 100644 tests/resources/diff_format_email/.gitted/objects/ee/251372f131d82e575f16fe51c778406d88f8c2 create mode 100644 tests/resources/diff_format_email/.gitted/objects/f3/d35bd592fefd8280fc0c302fa9f27dbdd721a3 create mode 100644 tests/resources/diff_format_email/.gitted/objects/f4/07be01334e07bfb8f57cd2078f0ee3eb61e085 create mode 100644 tests/resources/diff_format_email/.gitted/objects/f9/e215d309644e24fa50d6bd6e6eedba166e56bc create mode 100644 tests/resources/diff_format_email/.gitted/objects/fc/a0c10eb9f1af6494a448d5733d283f5232a514 create mode 100644 tests/resources/diff_format_email/.gitted/objects/ff/8d35b41494f7f0dc92f95d67f54fff274d3fcb create mode 100644 tests/resources/diff_format_email/.gitted/refs/heads/binary create mode 100644 tests/resources/diff_format_email/.gitted/refs/heads/master create mode 100644 tests/resources/diff_format_email/.gitted/refs/heads/multihunk create mode 100644 tests/resources/diff_format_email/.gitted/refs/heads/rename create mode 100755 tests/resources/diff_format_email/file1.txt.renamed create mode 100644 tests/resources/diff_format_email/file2.txt create mode 100644 tests/resources/diff_format_email/file3.txt diff --git a/tests/resources/diff_format_email/.gitted/HEAD b/tests/resources/diff_format_email/.gitted/HEAD new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/diff_format_email/.gitted/config b/tests/resources/diff_format_email/.gitted/config new file mode 100644 index 00000000000..6c9406b7d93 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/config @@ -0,0 +1,7 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true diff --git a/tests/resources/diff_format_email/.gitted/index b/tests/resources/diff_format_email/.gitted/index new file mode 100644 index 0000000000000000000000000000000000000000..f73027e565387ebbe041eab863c6cce17c04085c GIT binary patch literal 256 zcmZ?q402{*U|<4b=3tM=7$D66qZxtXoK6pCFfcT}Wnf_Z3X~E7;&m$v!xvl#7n@Pk zov&Y3x+UynPh=v4U|MEQs-a#%#*MB zFL-O}DeVXQw|lcaKO^J88hQIU11HElBanHx%uz%)XO?aS*P&NjulDY|w4&_U?*AXF hbzC6k7=z83$!y8oCb#9_q@2!NN8hQ^4>#Av0svY-Oy2+i literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/info/exclude b/tests/resources/diff_format_email/.gitted/info/exclude new file mode 100644 index 00000000000..a5196d1be8f --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/resources/diff_format_email/.gitted/objects/0a/37045ca6d8503e9bcf06a12abbbc8e92664cce b/tests/resources/diff_format_email/.gitted/objects/0a/37045ca6d8503e9bcf06a12abbbc8e92664cce new file mode 100644 index 0000000000000000000000000000000000000000..1ece99cde7f29ee21d52ee35a7447a4538acdf83 GIT binary patch literal 29 lcmbQGc& zmt|J)X?)Nw0#!T~-zrIFw2{(Stiu$^rW^>P%j6wrGN07tLjj2eN9GWxi6VwjTgjL$ zmR1@^ifN?caxt{)W$o}r^|s3fuhN%!yX@Z^JiY(B^J&vQlhRPv7HD@q1FfcPQQAoTkz954FXj z{M>9ufU3+*O%>8Ib5afUN-9e9ic<3ub5m0oRu+aYxDYNjqo_MyzpQji*vX#AM5vJ< z#YP~-3|0RHZ%sX={b2ugZ?@-WWIR|SZ$C#;WDHg`OSgjS&?~N2dv{)1QTA;2|Bux= JE&w2$LZ@WfMQi{7 literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/1a/9932083f96b0db42552103d40076f62fa8235e b/tests/resources/diff_format_email/.gitted/objects/1a/9932083f96b0db42552103d40076f62fa8235e new file mode 100644 index 0000000000000000000000000000000000000000..b6f04538e8fe30bb8096094af233382a3f795c0f GIT binary patch literal 54 zcmb(jYs0@?RQAuF=IWMp=jL>|nxx22 K^$b~agaZH_^cCL# literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/1a/e3be57f869687d983066a0f5d2aaea1b82ddc5 b/tests/resources/diff_format_email/.gitted/objects/1a/e3be57f869687d983066a0f5d2aaea1b82ddc5 new file mode 100644 index 0000000000000000000000000000000000000000..be85c78ba0c98841fe66262efc3dca34d1614e7d GIT binary patch literal 162 zcmV;T0A2rh0i}*X3c@fD06pgwxeJnJ)9w~TJSq5#?RH};#MU$g{k;XB;Bn?Kj7%ww z#d>IVC97JlSz4q%M9&pch!ik}%6ni40*cf^@IYqftj}WmP6<6~AlI-Gi3mi8buAl3 zk`6Vp7csn+VaoQ#@>+GVSIuc$hV`@9_4qbrC?wxneY<62M Q`d7qU#`ij#FU9~&&28gNLI3~& literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/1b/525b0a6c5218b069b601ce91fce8eaf0a54e20 b/tests/resources/diff_format_email/.gitted/objects/1b/525b0a6c5218b069b601ce91fce8eaf0a54e20 new file mode 100644 index 0000000000000000000000000000000000000000..e8145edfd2b60a471a44202c02e7081ab3a96f02 GIT binary patch literal 31 ncmba1HPt#{ile+}EyahdbxEa1Y;@$xO$4v~9 literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/1e/82c3b234e37da82e5b23e0e2a70bca68ee12c6 b/tests/resources/diff_format_email/.gitted/objects/1e/82c3b234e37da82e5b23e0e2a70bca68ee12c6 new file mode 100644 index 0000000000000000000000000000000000000000..3ae87cfa97e2003303d5bb6a6e375af19e7dfdbc GIT binary patch literal 28 kcmb7Hf1n0FfcbYRY=RsNj20fsVLDaO3h2mO-*4~Ss1?HLb%wB zqV9bCveGSKCwn3jfr`ycOu&kbP!#{~HQgdI<@<*_lYYjgfA#;b?rVP7v}77HD@q1FfcPQQAo8Ib5afUN-9e9ic<3ub5m0oRu+aYxDYNjqo_MyzpQji*vX#AM5vJ< z#YP~-3|0RHZ%sX={b2ugZ?@-WWIR|SZ$C#;WDHg`OSgjS&?~N2dv{)1QTA;2|Bux= JE&#_MLLg!sMF9W+ literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/24/97c5249408494e66e25070a8c74e49eaeeb6c3 b/tests/resources/diff_format_email/.gitted/objects/24/97c5249408494e66e25070a8c74e49eaeeb6c3 new file mode 100644 index 0000000000000000000000000000000000000000..e1ede9ae9b0e3f139846a25a10c776e12991a386 GIT binary patch literal 162 zcmV;T0A2rh0i}*R3IZ_{0IhS1^n$$n6A-ad@D@q-#f=bm%?I@ME_ejHVTxhmQcCWW z3%%<)$lGkMQ6`!3Z2__&gAtY{;f=$ZAiG#5T z5CsO!5Ue78^m(cD=HqK%qgSjYw|RUTJwAT!er~;H-~Ayj6tq9UlQ{s0;5%h-0t%{Fu#NHQc7hPR$Bl7 literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/25/2a3e19fd2c6fb7b20c111142c5bd5fb9ea6b8e b/tests/resources/diff_format_email/.gitted/objects/25/2a3e19fd2c6fb7b20c111142c5bd5fb9ea6b8e new file mode 100644 index 0000000000000000000000000000000000000000..10c34009d1598d0728686138bddf8f5c247d2769 GIT binary patch literal 121 zcmV-<0EYi~0V^p=O;s>7Hf1n0FfcbYRY=RsNj20fsVLDaO3h2mO-*4~Ss1?HLb%wB zqV9bCveGSKCwn3jfr`ycOu&kbP!w1F7rZs~l=g%D+r8PIpONukjlBIFNwG1CV&ONR buNK`t`gF5S_k#3`7avTXTJ!<{@Q^zku0uJS literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/27/93544db9060bab4f9169e5b89c82f9fa7c7fa6 b/tests/resources/diff_format_email/.gitted/objects/27/93544db9060bab4f9169e5b89c82f9fa7c7fa6 new file mode 100644 index 0000000000000000000000000000000000000000..689f5b9a1197cf2fb281cca0c2f654db6225adb5 GIT binary patch literal 120 zcmV-;0Ehp00V^p=O;s>7v}7cYf literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/29/1f1ff3cbb9a6f153678d9657679e3d4bf257df b/tests/resources/diff_format_email/.gitted/objects/29/1f1ff3cbb9a6f153678d9657679e3d4bf257df new file mode 100644 index 0000000000000000000000000000000000000000..6af5dda9d1dc701d5b4c6e444bec868d5a67151f GIT binary patch literal 29 lcmb9XD~D{Ff%bxNXyJgHPkDqC}9XXd{+LOviH<~r`ON>Xr^*Y MJhQqN09W)8rXjr-3;+NC literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/39/91dce9e71a0641ca49a6a4eea6c9e7ff402ed4 b/tests/resources/diff_format_email/.gitted/objects/39/91dce9e71a0641ca49a6a4eea6c9e7ff402ed4 new file mode 100644 index 0000000000000000000000000000000000000000..69d213dcb0c7235a5a5755d309486fbc493496bf GIT binary patch literal 166 zcmV;X09pTd0i}*f3IZ_@06pgweHSE4X9E#$f+xSwc6xM#IGV{E{JjG{!D~Sk#Z#?g z2a9&on+SM~F7ZGTU)MaS`>pE3YU*q0Q+74n#+5i9m literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/45/eef2a9317e179984649de247269e38cd5d99cf b/tests/resources/diff_format_email/.gitted/objects/45/eef2a9317e179984649de247269e38cd5d99cf new file mode 100644 index 00000000000..e5014565bdd --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/45/eef2a9317e179984649de247269e38cd5d99cf @@ -0,0 +1,2 @@ +xJ0ay_IIqwo0Lo+$&[zU&FY,:YCT8B UsH,BL)(r.ca }+^Y>mp՚_ sG)&k}GhzRļi* +Rrs X \ No newline at end of file diff --git a/tests/resources/diff_format_email/.gitted/objects/4a/076277b884c519a932be67e346db2ac80a98fa b/tests/resources/diff_format_email/.gitted/objects/4a/076277b884c519a932be67e346db2ac80a98fa new file mode 100644 index 0000000000000000000000000000000000000000..b855408e8f40413af0f82c04e253d0a0db1d90e4 GIT binary patch literal 40 wcmb)Rn7uKSep}~+`T@H&QB<%1S>pfz literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/4c/a10087e696d2ba78d07b146a118e9a7096ed4f b/tests/resources/diff_format_email/.gitted/objects/4c/a10087e696d2ba78d07b146a118e9a7096ed4f new file mode 100644 index 0000000000000000000000000000000000000000..b05e7d634f2498bcd3cf136b809b23a0d24efa1f GIT binary patch literal 173 zcmV;e08;;W0j17CYQr!PM&Yb=irE*+$dauHLdh=BWp40$G>#pRol5eex33{b==NJY zo@_ZUjk=yst*BDpa|(_}*zqhrx}dOuM;9cFh&F}T2?H=M6kQv+c%W$1V8Mg80v|EJ zt74Etr^$1t$s6o#-U@v~es-;N(~_4u@4uBU&$m6UwUq@8pR(mIvMvU9?maVoaK~&8 bJyx6kD`M`tB5NY7iDbt5&}#kwSj18SapzOF literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/4d/de2b17d1c982cd988f21d24350a214401e4a1e b/tests/resources/diff_format_email/.gitted/objects/4d/de2b17d1c982cd988f21d24350a214401e4a1e new file mode 100644 index 0000000000000000000000000000000000000000..57a8dfed1977454596f062590d33ed043ef6c844 GIT binary patch literal 121 zcmV-<0EYi~0V^p=O;s>7v}79XD~D{Ff%bxNXyJgHPkDqC}EhgYF%f@i`|K~&&=3mmnAP# M%#0KS08eHQ)*P`Fl>h($ literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/50/17c9456d013b2c7712d29aab73b681c880f509 b/tests/resources/diff_format_email/.gitted/objects/50/17c9456d013b2c7712d29aab73b681c880f509 new file mode 100644 index 0000000000000000000000000000000000000000..5b96aa5ea61edcc9ecb2a62f6ab9e2f65cdef1b0 GIT binary patch literal 54 zcmb0EGW|0V^p=O;s>7HfJz2FfcbYRY=RsNj20fsVLDaO3h2mO-*4~Ss1?HLb%wB zqV9bCveGSKCwn3jfr`ycOu&kbkQEy-{O>j0A~NOshdYyg#-@Mu|F76HDO50%t0EGW|0V^p=O;s>7He)a}FfcbYRY=RsNj20fsVLDaO3h2mO-*4~Ss1?HLb%wB zqV9bCveGSKCwn3jfr`ycOu&kbkQEy-%sOB+ySvK4O_8^|n`sRbYgqcdWF*zb$f_BH d-+aDWbo=Pj%{tu+(l1_oFnMax3jk}{I4rE}I5z+Q literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/66/81f1844dc677e5ff07ffd993461f5c441e6af5 b/tests/resources/diff_format_email/.gitted/objects/66/81f1844dc677e5ff07ffd993461f5c441e6af5 new file mode 100644 index 0000000000000000000000000000000000000000..86a38289b8162a6f0204922380652a2423b2358b GIT binary patch literal 35 rcmbkUwo~F;3CU?brOt6wWw6vpTCJRI1MfrUI9Lx{c literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/69/ddefb5c245e2f9ee62bd4cabd8ebe60a01e448 b/tests/resources/diff_format_email/.gitted/objects/69/ddefb5c245e2f9ee62bd4cabd8ebe60a01e448 new file mode 100644 index 0000000000000000000000000000000000000000..81b606f4e4b5e3e0c03d9bf92a679d36a5708f3e GIT binary patch literal 54 zcmV-60LlM&0V^p=O;s>9XD~D{Ff%bxNXyJgHPkDqC}Gf)m;Zcv=dzE%>Alm!)92ZG Me+s`3080lEM@qOCumAu6 literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/6b/6c2067c6d968f9bddb9b900ee1ab7e5b067430 b/tests/resources/diff_format_email/.gitted/objects/6b/6c2067c6d968f9bddb9b900ee1ab7e5b067430 new file mode 100644 index 00000000000..aa9d7b0cdfe --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/6b/6c2067c6d968f9bddb9b900ee1ab7e5b067430 @@ -0,0 +1,2 @@ +x; +1a X)$sD3{.+sšsj޵ 'fg=Cm⤄A 7v}7tC!a8=C#M2}q>Z#* zlu;5#*DwV#ywuxN?3v?h(b=A~ LqGh~u$+g+H[^`ȏQW \ No newline at end of file diff --git a/tests/resources/diff_format_email/.gitted/objects/7a/de76dd34bba4733cf9878079f9fd4a456a9189 b/tests/resources/diff_format_email/.gitted/objects/7a/de76dd34bba4733cf9878079f9fd4a456a9189 new file mode 100644 index 00000000000..cf9bdaa5fd9 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/7a/de76dd34bba4733cf9878079f9fd4a456a9189 @@ -0,0 +1,3 @@ +xA +0E]d4M"`m5IޢGp>X4aWn3 y ,[FHoD-e +:ёcz0FbCÊ:_HNcwRHqN'6xF {4j[j$0U_y*&R \ No newline at end of file diff --git a/tests/resources/diff_format_email/.gitted/objects/7a/ff11da95ca2be0bfb74b06e7cc1c480559dbe7 b/tests/resources/diff_format_email/.gitted/objects/7a/ff11da95ca2be0bfb74b06e7cc1c480559dbe7 new file mode 100644 index 0000000000000000000000000000000000000000..d8c9934f7ad2c0d2dbf4f0bc4eb8e4afc457d6c9 GIT binary patch literal 26 icmbd+B#e$|86?qti7(|y4?r7eLvXOY0SRLl-JzqJ2*<_|#RP`ER{TF3wZ literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/87/3806f6f27e631eb0b23e4b56bea2bfac14a373 b/tests/resources/diff_format_email/.gitted/objects/87/3806f6f27e631eb0b23e4b56bea2bfac14a373 new file mode 100644 index 0000000000000000000000000000000000000000..890abcd4a91aa4f33b8566a8b5242d032e1499f5 GIT binary patch literal 181 zcmV;m080OO0i}*XN(3R>tqCC;DP)?C^NikNY!od$HOd%j?5K{LcU9Sd&5o6Vq)1-q?!ix!0%FdJ~gFUgk$2pN=$87)H29 jMs&N~ubTcV;?7HHwP}Ic-jxsbWe>mTZ|HsiqzO~x^$J?j literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/89/47a46e2097638ca6040ad4877246f4186ec3bd b/tests/resources/diff_format_email/.gitted/objects/89/47a46e2097638ca6040ad4877246f4186ec3bd new file mode 100644 index 00000000000..d4018bf8e9c --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/89/47a46e2097638ca6040ad4877246f4186ec3bd @@ -0,0 +1,2 @@ +xAj0E)/ь,Jw.{8 ;Eo_C{nWZnYҩ7:8\u!Ni@0qaWR4Foڰt$ +S8"C'-ΫD1쇖}Gv߿7{y۬]eb"sc|bъL \ No newline at end of file diff --git a/tests/resources/diff_format_email/.gitted/objects/89/7d3af16ca9e420cd071b1c4541bd2b91d04c8c b/tests/resources/diff_format_email/.gitted/objects/89/7d3af16ca9e420cd071b1c4541bd2b91d04c8c new file mode 100644 index 00000000000..1dce143b761 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/89/7d3af16ca9e420cd071b1c4541bd2b91d04c8c @@ -0,0 +1 @@ +xAN0 @Q9Hȵ$Y!q 't1g$-~ֵ FWb[hqXY)9Q[ '͘9d&e‘us׶__yGo2lLD3HաsZ!;X"Pq \ No newline at end of file diff --git a/tests/resources/diff_format_email/.gitted/objects/8d/7523f6fcb2404257889abe0d96f093d9f524f9 b/tests/resources/diff_format_email/.gitted/objects/8d/7523f6fcb2404257889abe0d96f093d9f524f9 new file mode 100644 index 00000000000..903ec751c9a --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/8d/7523f6fcb2404257889abe0d96f093d9f524f9 @@ -0,0 +1 @@ +xAJ0a9IӤw!f&_Utno#nF7JZLT$%BQVfe,,9+ElL$a$KAu|ެm>zO/@SNOfG!c+6+ ]ER \ No newline at end of file diff --git a/tests/resources/diff_format_email/.gitted/objects/8d/fa038554d5b682a51bda8ee3038cee6c63be76 b/tests/resources/diff_format_email/.gitted/objects/8d/fa038554d5b682a51bda8ee3038cee6c63be76 new file mode 100644 index 0000000000000000000000000000000000000000..b5e08f901f1feccd5744ae5682797aed72ddbb4f GIT binary patch literal 120 zcmV-;0Ehp00V^p=O;s>7Hf1n0FfcbYRY=RsNj20fsVLDaO3h2mO-*4~Ss1?HLb%wB zqV9bCveGSKCwn3jfr`ycOu&kbP!w1F7rZs~l=g%D+r8PIpONukjlBIFNwG1CV(Fl0 auACr=4Vl{*&rSUE;?;+xehL7)hBuLWmO4@Z literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/92/64b96c6d104d0e07ae33d3007b6a48246c6f92 b/tests/resources/diff_format_email/.gitted/objects/92/64b96c6d104d0e07ae33d3007b6a48246c6f92 new file mode 100644 index 0000000000000000000000000000000000000000..75b047a64a1c7783d040ce8edc91742292e3e5f0 GIT binary patch literal 181 zcmV;m080OO0hN!tY6CG408{HLwhx%ym2{H8gmi&`KVnZ0`vS5ONmuyqbKv|y+9`&a z*lOJ-u*H|za|Vm#VlZ||NP6Yy9C6|xvO2vko}%|yEC%&0J>MskC>ROz8VX5SOfX`M zPu6Lj*z00hvsf}p_IYa^J|+I_dB8{RbsM++G2s05WY_mG`zBLPvDG&q9ULyfGr=n| jqB`i2I`h9J4lTPsiMq73l?RMgGsJeE$AtO?Aq!BajS*H< literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/94/350226b3aa14efac831c803a51f7a09f3fc31a b/tests/resources/diff_format_email/.gitted/objects/94/350226b3aa14efac831c803a51f7a09f3fc31a new file mode 100644 index 0000000000000000000000000000000000000000..a5286bc68f29157e2424d43ea5e6b1f70a9ef42b GIT binary patch literal 24 gcmb-QQ0DUkD8vp4WiT`_Ff%bxNXyJgHPkDqDA6lQ%}dNpO<{Pb^}QyLujk33 U#KooUW&(3`bT57Y0Mktq{ph0_jsO4v literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/94/aaae8954e8bb613de636071da663a621695911 b/tests/resources/diff_format_email/.gitted/objects/94/aaae8954e8bb613de636071da663a621695911 new file mode 100644 index 0000000000000000000000000000000000000000..5fc167e7965f4d5758f37b8057a39bf1343433e4 GIT binary patch literal 29 lcmb9XD~D{Ff%bxNXyJgHPkDqC}HqoPb%Nha#V7q(Z2M@Znw2g MaLxDy06`%Tzb4xj!vFvP literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/a7/29eab45c84563135e8631d4010230bc0479f1f b/tests/resources/diff_format_email/.gitted/objects/a7/29eab45c84563135e8631d4010230bc0479f1f new file mode 100644 index 0000000000000000000000000000000000000000..5c1faf009b1260acdd5808c335a153a27f5158f6 GIT binary patch literal 40 wcmbliab|5l}Z08U&G8UO$Q literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/a9/7157a0d0571698728b6f2f7675b456c98c5961 b/tests/resources/diff_format_email/.gitted/objects/a9/7157a0d0571698728b6f2f7675b456c98c5961 new file mode 100644 index 0000000000000000000000000000000000000000..3baf494bef2dbfebb4181b38b445dbfbc7fed222 GIT binary patch literal 62 zcmV-E0Kxxw0ZYosPf{>6H(^N2%tF*h{@A;QIl U#3oJ$LKU*T$ZUiP05fJjM>NzJwEzGB literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/af/8f41d0cb7a3079a8f8e231ea2ab8b97837ce13 b/tests/resources/diff_format_email/.gitted/objects/af/8f41d0cb7a3079a8f8e231ea2ab8b97837ce13 new file mode 100644 index 0000000000000000000000000000000000000000..f0dcaa9acbd4b5712f9b374c1606cd2681a2d19c GIT binary patch literal 50 zcmV-20L}k+0ZYosPf{>6wO~lg%tkUwo~Dnw*n>aD2*}L{ad|f3fSV~7L$Rg&dH^z24@Cd~ literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/b4/f457c219dbb3517be908d4e70f0ada2fd8b8f9 b/tests/resources/diff_format_email/.gitted/objects/b4/f457c219dbb3517be908d4e70f0ada2fd8b8f9 new file mode 100644 index 0000000000000000000000000000000000000000..0c74e76964a3b9ca3153741a4c5f86acbb2e2a61 GIT binary patch literal 54 zcmbGG?-$?rim$hjcN1OH6MzW_my2G;-p literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/bd/f7ba6bc5c4e57ca6595928dcbe6753c8a663ff b/tests/resources/diff_format_email/.gitted/objects/bd/f7ba6bc5c4e57ca6595928dcbe6753c8a663ff new file mode 100644 index 0000000000000000000000000000000000000000..af0232aa14f672c99f9c66213792d546bb7f1295 GIT binary patch literal 35 rcmbx|+#*0aG2=dURpo~7+uU*~s+hqvE$dFrEWJorAJ`y&_^$r|#(z^%4g it82Zk4*3Uygnx*7ogZVnTj%i(dFA6GUHt$rYEYpJ)>^v& literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/cd/ed722d05305c6b181f188c118d2d9810f39bb8 b/tests/resources/diff_format_email/.gitted/objects/cd/ed722d05305c6b181f188c118d2d9810f39bb8 new file mode 100644 index 0000000000000000000000000000000000000000..fd93636125d3e2745134b5ca8355b68d845151dc GIT binary patch literal 163 zcmV;U09^lg0i}*h3c@fH0A1%4*$a}qHa`$?rQj`IUS4d3+M1@Ix3}OCoaHQrp=lgT zlhD~+tIQG%V8=S-1Y~n`5ftf-9>~OGatw?%dKNQQel|%Fedv`>q_oXFVM@^^^4?~O z#%JRlI-jz@wGC61H>B6fi@b6j%QCE=MIIkNcRw$!7HoK+X*@~Y1qUiXaB{CeDY4mY RweepOaVhV07GIz&P40AdNlO3# literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/ce/2792fcae8d704a56901754a0583a7418a21d8a b/tests/resources/diff_format_email/.gitted/objects/ce/2792fcae8d704a56901754a0583a7418a21d8a new file mode 100644 index 0000000000000000000000000000000000000000..5863cec1ba2cedfe621ab8ac730842dba6c3c8f3 GIT binary patch literal 121 zcmV-<0EYi~0V^p=O;s>7v}7|DB*`v|AAvQg literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/d1/4aa252e52a709d03a3d3d0d965e177eb0a674e b/tests/resources/diff_format_email/.gitted/objects/d1/4aa252e52a709d03a3d3d0d965e177eb0a674e new file mode 100644 index 00000000000..a5d4d78e987 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/objects/d1/4aa252e52a709d03a3d3d0d965e177eb0a674e @@ -0,0 +1 @@ +x+)JMU01e040075UHI5+(+JKMMaXYB،|-a'{"z \ No newline at end of file diff --git a/tests/resources/diff_format_email/.gitted/objects/d7/bb447df12c6a8aba8727005482fb211f11297a b/tests/resources/diff_format_email/.gitted/objects/d7/bb447df12c6a8aba8727005482fb211f11297a new file mode 100644 index 0000000000000000000000000000000000000000..85eb8141ce2c1fb9167c143e8dc811452c55c169 GIT binary patch literal 156 zcmV;N0Av4n0V^p=O;s>7HD@q1FfcPQQAoZdj~tl)x2qfdYU d>Y&HfDKAOXSIb*@=+Ua^)b8_$Q2!UuP|>)hS~dUx literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/objects/e1/2af77c510e8ce4c261a3758736109c2c2dd1f0 b/tests/resources/diff_format_email/.gitted/objects/e1/2af77c510e8ce4c261a3758736109c2c2dd1f0 new file mode 100644 index 0000000000000000000000000000000000000000..92a89a2cf6cb86271d9845660e3f6ce3210cdd9c GIT binary patch literal 51 zcmV-30L=e*0ZYosPf{>6Fk(o{%t$N_#W{1@yp(y$Lu>#ekiRz!4fjzB~wmtj~>yT e^h}-lZwXJpG-aKFbp6#%;Y3(^1p literal 0 HcmV?d00001 diff --git a/tests/resources/diff_format_email/.gitted/refs/heads/binary b/tests/resources/diff_format_email/.gitted/refs/heads/binary new file mode 100644 index 00000000000..7e563c95791 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/refs/heads/binary @@ -0,0 +1 @@ +a3ac918e3a6604294b239cb956363e83d71abb3b diff --git a/tests/resources/diff_format_email/.gitted/refs/heads/master b/tests/resources/diff_format_email/.gitted/refs/heads/master new file mode 100644 index 00000000000..f0f3f932a86 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/refs/heads/master @@ -0,0 +1 @@ +873806f6f27e631eb0b23e4b56bea2bfac14a373 diff --git a/tests/resources/diff_format_email/.gitted/refs/heads/multihunk b/tests/resources/diff_format_email/.gitted/refs/heads/multihunk new file mode 100644 index 00000000000..41bd37f39b2 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/refs/heads/multihunk @@ -0,0 +1 @@ +cd471f0d8770371e1bc78bcbb38db4c7e4106bd2 diff --git a/tests/resources/diff_format_email/.gitted/refs/heads/rename b/tests/resources/diff_format_email/.gitted/refs/heads/rename new file mode 100644 index 00000000000..3025fbc6435 --- /dev/null +++ b/tests/resources/diff_format_email/.gitted/refs/heads/rename @@ -0,0 +1 @@ +4ca10087e696d2ba78d07b146a118e9a7096ed4f diff --git a/tests/resources/diff_format_email/file1.txt.renamed b/tests/resources/diff_format_email/file1.txt.renamed new file mode 100755 index 00000000000..a97157a0d05 --- /dev/null +++ b/tests/resources/diff_format_email/file1.txt.renamed @@ -0,0 +1,17 @@ +file1.txt +file1.txt +_file1.txt_ +file1.txt +file1.txt +file1.txt_renamed +file1.txt + + +file1.txt +file1.txt +file1.txt_renamed +file1.txt +file1.txt +_file1.txt_ +_file1.txt_ +file1.txt diff --git a/tests/resources/diff_format_email/file2.txt b/tests/resources/diff_format_email/file2.txt new file mode 100644 index 00000000000..7aff11da95c --- /dev/null +++ b/tests/resources/diff_format_email/file2.txt @@ -0,0 +1,5 @@ +file2 +file2 +file2 +file2! +file2 diff --git a/tests/resources/diff_format_email/file3.txt b/tests/resources/diff_format_email/file3.txt new file mode 100644 index 00000000000..9a2d780ac2e --- /dev/null +++ b/tests/resources/diff_format_email/file3.txt @@ -0,0 +1,5 @@ +file3 +file3! +file3 +file3 +file3 From 360314c9dbb383b3737876a9c229e22050ec9c49 Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Fri, 11 Apr 2014 19:03:29 +0200 Subject: [PATCH 6/9] Introduce git_diff_get_stats, git_diff_stats_files_changed, git_diff_stats_insertions, git_diff_stats_deletions and git_diff_stats_to_buf --- include/git2/diff.h | 85 +++++++++ src/diff_stats.c | 343 +++++++++++++++++++++++++++++++++++ tests/diff/stats.c | 428 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 856 insertions(+) create mode 100644 src/diff_stats.c create mode 100644 tests/diff/stats.c diff --git a/include/git2/diff.h b/include/git2/diff.h index f855f52ba60..571f0c887ad 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -1072,6 +1072,91 @@ GIT_EXTERN(int) git_diff_buffers( git_diff_line_cb line_cb, void *payload); +/** + * This is an opaque structure which is allocated by `git_diff_get_stats`. + * You are responsible for releasing the object memory when done, using the + * `git_diff_stats_free()` function. + */ +typedef struct git_diff_stats git_diff_stats; + +/** + * Formatting options for diff stats + */ +typedef enum { + /** No stats*/ + GIT_DIFF_STATS_NONE = 0, + + /** Full statistics, equivalent of `--stat` */ + GIT_DIFF_STATS_FULL = (1u << 0), + + /** Short statistics, equivalent of `--shortstat` */ + GIT_DIFF_STATS_SHORT = (1u << 1), + + /** Number statistics, equivalent of `--numstat` */ + GIT_DIFF_STATS_NUMBER = (1u << 2), + + /** Extended header information such as creations, renames and mode changes, equivalent of `--summary` */ + GIT_DIFF_STATS_INCLUDE_SUMMARY = (1u << 3), +} git_diff_stats_format_t; + +/** + * Accumlate diff statistics for all patches. + * + * @param out Structure containg the diff statistics. + * @param diff A git_diff generated by one of the above functions. + * @return 0 on success; non-zero on error + */ +GIT_EXTERN(int) git_diff_get_stats( + git_diff_stats **out, + git_diff *diff); + +/** + * Get the total number of files changed in a diff + * + * @param stats A `git_diff_stats` generated by one of the above functions. + * @return total number of files changed in the diff + */ +GIT_EXTERN(size_t) git_diff_stats_files_changed( + const git_diff_stats *stats); + +/** + * Get the total number of insertions in a diff + * + * @param stats A `git_diff_stats` generated by one of the above functions. + * @return total number of insertions in the diff + */ +GIT_EXTERN(size_t) git_diff_stats_insertions( + const git_diff_stats *stats); + +/** + * Get the total number of deletions in a diff + * + * @param stats A `git_diff_stats` generated by one of the above functions. + * @return total number of deletions in the diff + */ +GIT_EXTERN(size_t) git_diff_stats_deletions( + const git_diff_stats *stats); + +/** + * Print diff statistics to a `git_buf`. + * + * @param out buffer to store the formatted diff statistics in. + * @param stats A `git_diff_stats` generated by one of the above functions. + * @param format Formatting option. + * @return 0 on success; non-zero on error + */ +GIT_EXTERN(int) git_diff_stats_to_buf( + git_buf *out, + const git_diff_stats *stats, + git_diff_stats_format_t format); + +/** + * Deallocate a `git_diff_stats`. + * + * @param stats The previously created statistics object; + * cannot be used after free. + */ +GIT_EXTERN(void) git_diff_stats_free(git_diff_stats *stats); GIT_END_DECL diff --git a/src/diff_stats.c b/src/diff_stats.c new file mode 100644 index 00000000000..bb436bf7b77 --- /dev/null +++ b/src/diff_stats.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include "common.h" +#include "vector.h" +#include "diff.h" +#include "diff_patch.h" + +#define DIFF_RENAME_FILE_SEPARATOR " => " + +struct git_diff_stats { + git_vector patches; + + size_t files_changed; + size_t insertions; + size_t deletions; +}; + +static size_t diff_get_filename_padding( + int has_renames, + const git_diff_stats *stats) +{ + const git_patch *patch = NULL; + size_t i, max_padding = 0; + + if (has_renames) { + git_vector_foreach(&stats->patches, i, patch) { + const git_diff_delta *delta = NULL; + size_t len; + + delta = git_patch_get_delta(patch); + if (strcmp(delta->old_file.path, delta->new_file.path) == 0) + continue; + + if ((len = strlen(delta->old_file.path) + strlen(delta->new_file.path)) > max_padding) + max_padding = len; + } + } + + git_vector_foreach(&stats->patches, i, patch) { + const git_diff_delta *delta = NULL; + size_t len; + + delta = git_patch_get_delta(patch); + len = strlen(delta->new_file.path); + + if (strcmp(delta->old_file.path, delta->new_file.path) != 0) + continue; + + if (len > max_padding) + max_padding = len; + } + + return max_padding; +} + +int git_diff_file_stats__full_to_buf( + git_buf *out, + size_t max_padding, + int has_renames, + const git_patch *patch) +{ + const char *old_path = NULL, *new_path = NULL; + const git_diff_delta *delta = NULL; + size_t padding, old_size, new_size; + int error; + + delta = git_patch_get_delta(patch); + + old_path = delta->old_file.path; + new_path = delta->new_file.path; + old_size = delta->old_file.size; + new_size = delta->new_file.size; + + if ((error = git_buf_printf(out, " %s", old_path)) < 0) + goto on_error; + + if (strcmp(old_path, new_path) != 0) { + padding = max_padding - strlen(old_path) - strlen(new_path); + + if ((error = git_buf_printf(out, DIFF_RENAME_FILE_SEPARATOR "%s", new_path)) < 0) + goto on_error; + } + else { + padding = max_padding - strlen(old_path); + + if (has_renames) + padding += strlen(DIFF_RENAME_FILE_SEPARATOR); + } + + if ((error = git_buf_putcn(out, ' ', padding)) < 0 || + (error = git_buf_puts(out, " | ")) < 0) + goto on_error; + + if (delta->flags & GIT_DIFF_FLAG_BINARY) { + if ((error = git_buf_printf(out, "Bin %" PRIuZ " -> %" PRIuZ " bytes", old_size, new_size)) < 0) + goto on_error; + } + else { + size_t insertions, deletions; + + if ((error = git_patch_line_stats(NULL, &insertions, &deletions, patch)) < 0) + goto on_error; + + if ((error = git_buf_printf(out, "%" PRIuZ, insertions + deletions)) < 0) + goto on_error; + + if (insertions || deletions) { + if ((error = git_buf_putc(out, ' ')) < 0 || + (error = git_buf_putcn(out, '+', insertions)) < 0 || + (error = git_buf_putcn(out, '-', deletions)) < 0) + goto on_error; + } + } + + error = git_buf_putc(out, '\n'); + +on_error: + return error; +} + +int git_diff_file_stats__number_to_buf( + git_buf *out, + const git_patch *patch) +{ + const git_diff_delta *delta = NULL; + const char *path = NULL; + size_t insertions, deletions; + int error; + + delta = git_patch_get_delta(patch); + path = delta->new_file.path; + + if ((error = git_patch_line_stats(NULL, &insertions, &deletions, patch)) < 0) + return error; + + if (delta->flags & GIT_DIFF_FLAG_BINARY) + error = git_buf_printf(out, "%-8c" "%-8c" "%s\n", '-', '-', path); + else + error = git_buf_printf(out, "%-8" PRIuZ "%-8" PRIuZ "%s\n", insertions, deletions, path); + + return error; +} + +int git_diff_file_stats__summary_to_buf( + git_buf *out, + const git_patch *patch) +{ + const git_diff_delta *delta = NULL; + + delta = git_patch_get_delta(patch); + + if (delta->old_file.mode != delta->new_file.mode) { + if (delta->old_file.mode == 0) { + git_buf_printf(out, " create mode %06o %s\n", + delta->new_file.mode, delta->new_file.path); + } + else if (delta->new_file.mode == 0) { + git_buf_printf(out, " delete mode %06o %s\n", + delta->old_file.mode, delta->old_file.path); + } + else { + git_buf_printf(out, " mode change %06o => %06o %s\n", + delta->old_file.mode, delta->new_file.mode, delta->new_file.path); + } + } + + return 0; +} + +int git_diff_stats__has_renames( + const git_diff_stats *stats) +{ + git_patch *patch = NULL; + size_t i; + + git_vector_foreach(&stats->patches, i, patch) { + const git_diff_delta *delta = git_patch_get_delta(patch); + + if (strcmp(delta->old_file.path, delta->new_file.path) != 0) { + return 1; + } + } + + return 0; +} + +int git_diff_stats__add_file_stats( + git_diff_stats *stats, + git_patch *patch) +{ + const git_diff_delta *delta = NULL; + int error = 0; + + if ((delta = git_patch_get_delta(patch)) == NULL) + return -1; + + if ((error = git_vector_insert(&stats->patches, patch)) < 0) + return error; + + return error; +} + +int git_diff_get_stats( + git_diff_stats **out, + git_diff *diff) +{ + size_t i, deltas; + size_t total_insertions = 0, total_deletions = 0; + git_diff_stats *stats = NULL; + int error = 0; + + assert(out && diff); + + stats = git__calloc(1, sizeof(git_diff_stats)); + GITERR_CHECK_ALLOC(stats); + + deltas = git_diff_num_deltas(diff); + + for (i = 0; i < deltas; ++i) { + git_patch *patch = NULL; + size_t add, remove; + + if ((error = git_patch_from_diff(&patch, diff, i)) < 0) + goto on_error; + + if ((error = git_patch_line_stats(NULL, &add, &remove, patch)) < 0 || + (error = git_diff_stats__add_file_stats(stats, patch)) < 0) { + git_patch_free(patch); + goto on_error; + } + + total_insertions += add; + total_deletions += remove; + } + + stats->files_changed = deltas; + stats->insertions = total_insertions; + stats->deletions = total_deletions; + + *out = stats; + + goto done; + +on_error: + git_diff_stats_free(stats); + +done: + return error; +} + +size_t git_diff_stats_files_changed( + const git_diff_stats *stats) +{ + assert(stats); + + return stats->files_changed; +} + +size_t git_diff_stats_insertions( + const git_diff_stats *stats) +{ + assert(stats); + + return stats->insertions; +} + +size_t git_diff_stats_deletions( + const git_diff_stats *stats) +{ + assert(stats); + + return stats->deletions; +} + +int git_diff_stats_to_buf( + git_buf *out, + const git_diff_stats *stats, + git_diff_stats_format_t format) +{ + git_patch *patch = NULL; + size_t i; + int has_renames = 0, error = 0; + + assert(out && stats); + + /* check if we have renames, it affects the padding */ + has_renames = git_diff_stats__has_renames(stats); + + git_vector_foreach(&stats->patches, i, patch) { + if (format & GIT_DIFF_STATS_FULL) { + size_t max_padding = diff_get_filename_padding(has_renames, stats); + + error = git_diff_file_stats__full_to_buf(out, max_padding, has_renames, patch); + } + else if (format & GIT_DIFF_STATS_NUMBER) { + error = git_diff_file_stats__number_to_buf(out, patch); + } + + if (error < 0) + return error; + } + + if (format & GIT_DIFF_STATS_FULL || format & GIT_DIFF_STATS_SHORT) { + error = git_buf_printf(out, " %" PRIuZ " file%s changed, %" PRIuZ " insertions(+), %" PRIuZ " deletions(-)\n", + stats->files_changed, stats->files_changed > 1 ? "s" : "", + stats->insertions, stats->deletions); + + if (error < 0) + return error; + } + + if (format & GIT_DIFF_STATS_INCLUDE_SUMMARY) { + git_vector_foreach(&stats->patches, i, patch) { + if ((error = git_diff_file_stats__summary_to_buf(out, patch)) < 0) + return error; + } + + if (git_vector_length(&stats->patches) > 0) + git_buf_putc(out, '\n'); + } + + return error; +} + +void git_diff_stats_free(git_diff_stats *stats) +{ + size_t i; + git_patch *patch; + + if (stats == NULL) + return; + + git_vector_foreach(&stats->patches, i, patch) + git_patch_free(patch); + + git_vector_free(&stats->patches); + git__free(stats); +} + diff --git a/tests/diff/stats.c b/tests/diff/stats.c new file mode 100644 index 00000000000..131b7681d21 --- /dev/null +++ b/tests/diff/stats.c @@ -0,0 +1,428 @@ +#include "clar.h" +#include "clar_libgit2.h" + +#include "buffer.h" +#include "commit.h" +#include "diff.h" + +static git_repository *repo; + +void test_diff_stats__initialize(void) +{ + repo = cl_git_sandbox_init("diff_format_email"); +} + +void test_diff_stats__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_diff_stats__stat(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n"; + + git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 1); + cl_assert(git_diff_stats_insertions(stats) == 5); + cl_assert(git_diff_stats_deletions(stats) == 3); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__multiple_hunks(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file2.txt | 5 +++--\n" \ + " file3.txt | 6 ++++--\n" \ + " 2 files changed, 7 insertions(+), 4 deletions(-)\n"; + + git_oid_fromstr(&oid, "cd471f0d8770371e1bc78bcbb38db4c7e4106bd2"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 2); + cl_assert(git_diff_stats_insertions(stats) == 7); + cl_assert(git_diff_stats_deletions(stats) == 4); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__numstat(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + "3 2 file2.txt\n" + "4 2 file3.txt\n"; + + git_oid_fromstr(&oid, "cd471f0d8770371e1bc78bcbb38db4c7e4106bd2"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_NUMBER)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__shortstat(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " 1 file changed, 5 insertions(+), 3 deletions(-)\n"; + + git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 1); + cl_assert(git_diff_stats_insertions(stats) == 5); + cl_assert(git_diff_stats_deletions(stats) == 3); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_SHORT)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__rename(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file2.txt => file2.txt.renamed | 1 +\n" + " file3.txt => file3.txt.renamed | 4 +++-\n" + " 2 files changed, 4 insertions(+), 1 deletions(-)\n"; + + git_oid_fromstr(&oid, "8947a46e2097638ca6040ad4877246f4186ec3bd"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_find_similar(diff, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 2); + cl_assert(git_diff_stats_insertions(stats) == 4); + cl_assert(git_diff_stats_deletions(stats) == 1); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__rename_nochanges(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file2.txt.renamed => file2.txt.renamed2 | 0\n" + " file3.txt.renamed => file3.txt.renamed2 | 0\n" + " 2 files changed, 0 insertions(+), 0 deletions(-)\n"; + + git_oid_fromstr(&oid, "3991dce9e71a0641ca49a6a4eea6c9e7ff402ed4"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_find_similar(diff, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 2); + cl_assert(git_diff_stats_insertions(stats) == 0); + cl_assert(git_diff_stats_deletions(stats) == 0); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__rename_and_modifiy(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file2.txt.renamed2 | 2 +-\n" + " file3.txt.renamed2 => file3.txt.renamed | 0\n" + " 2 files changed, 1 insertions(+), 1 deletions(-)\n"; + + git_oid_fromstr(&oid, "4ca10087e696d2ba78d07b146a118e9a7096ed4f"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_find_similar(diff, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 2); + cl_assert(git_diff_stats_insertions(stats) == 1); + cl_assert(git_diff_stats_deletions(stats) == 1); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__rename_no_find(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file2.txt | 5 -----\n" + " file2.txt.renamed | 6 ++++++\n" + " file3.txt | 5 -----\n" + " file3.txt.renamed | 7 +++++++\n" + " 4 files changed, 13 insertions(+), 10 deletions(-)\n"; + + git_oid_fromstr(&oid, "8947a46e2097638ca6040ad4877246f4186ec3bd"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 4); + cl_assert(git_diff_stats_insertions(stats) == 13); + cl_assert(git_diff_stats_deletions(stats) == 10); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__rename_nochanges_no_find(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file2.txt.renamed | 6 ------\n" + " file2.txt.renamed2 | 6 ++++++\n" + " file3.txt.renamed | 7 -------\n" + " file3.txt.renamed2 | 7 +++++++\n" + " 4 files changed, 13 insertions(+), 13 deletions(-)\n"; + + git_oid_fromstr(&oid, "3991dce9e71a0641ca49a6a4eea6c9e7ff402ed4"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 4); + cl_assert(git_diff_stats_insertions(stats) == 13); + cl_assert(git_diff_stats_deletions(stats) == 13); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__rename_and_modifiy_no_find(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file2.txt.renamed2 | 2 +-\n" + " file3.txt.renamed | 7 +++++++\n" + " file3.txt.renamed2 | 7 -------\n" + " 3 files changed, 8 insertions(+), 8 deletions(-)\n"; + + git_oid_fromstr(&oid, "4ca10087e696d2ba78d07b146a118e9a7096ed4f"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 3); + cl_assert(git_diff_stats_insertions(stats) == 8); + cl_assert(git_diff_stats_deletions(stats) == 8); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__binary(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + /* TODO: Actually 0 bytes here should be 5!. Seems like we don't load the new content for binary files? */ + const char *stat = + " binary.bin | Bin 3 -> 0 bytes\n" + " 1 file changed, 0 insertions(+), 0 deletions(-)\n"; + + git_oid_fromstr(&oid, "8d7523f6fcb2404257889abe0d96f093d9f524f9"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + cl_assert(git_diff_stats_files_changed(stats) == 1); + cl_assert(git_diff_stats_insertions(stats) == 0); + cl_assert(git_diff_stats_deletions(stats) == 0); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__binary_numstat(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + "- - binary.bin\n"; + + git_oid_fromstr(&oid, "8d7523f6fcb2404257889abe0d96f093d9f524f9"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_NUMBER)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_stats__mode_change(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_stats *stats = NULL; + git_buf buf = GIT_BUF_INIT; + + const char *stat = + " file1.txt.renamed | 0\n" \ + " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \ + " mode change 100644 => 100755 file1.txt.renamed\n" \ + "\n"; + + git_oid_fromstr(&oid, "7ade76dd34bba4733cf9878079f9fd4a456a9189"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + + cl_git_pass(git_diff_get_stats(&stats, diff)); + + cl_git_pass(git_diff_stats_to_buf(&buf, stats, GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY)); + cl_assert(strcmp(git_buf_cstr(&buf), stat) == 0); + + git_diff_stats_free(stats); + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} From d8cc1fb653387d9acc28b075147084cf452c43dc Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Fri, 11 Apr 2014 19:15:15 +0200 Subject: [PATCH 7/9] Introduce git_diff_format_email and git_diff_commit_as_email --- include/git2/diff.h | 88 ++++++++ src/diff.c | 204 +++++++++++++++++ src/diff.h | 3 + tests/diff/format_email.c | 445 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 740 insertions(+) create mode 100644 tests/diff/format_email.c diff --git a/include/git2/diff.h b/include/git2/diff.h index 571f0c887ad..a0cfbc91896 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -1158,6 +1158,94 @@ GIT_EXTERN(int) git_diff_stats_to_buf( */ GIT_EXTERN(void) git_diff_stats_free(git_diff_stats *stats); +/** + * Formatting options for diff e-mail generation + */ +typedef enum { + /** Normal patch, the default */ + GIT_DIFF_FORMAT_EMAIL_NONE = 0, + + /** Don't insert "[PATCH]" in the subject header*/ + GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = (1 << 0), + +} git_diff_format_email_flags_t; + +/** + * Options for controlling the formatting of the generated e-mail. + */ +typedef struct { + unsigned int version; + + git_diff_format_email_flags_t flags; + + /** This patch number */ + size_t patch_no; + + /** Total number of patches in this series */ + size_t total_patches; + + /** id to use for the commit */ + const git_oid *id; + + /** Summary of the change */ + const char *summary; + + /** Author of the change */ + const git_signature *author; +} git_diff_format_email_options; + +#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION 1 +#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT {GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, 0, 1, 1, NULL, NULL, NULL} + +/** + * Create an e-mail ready patch from a diff. + * + * @param out buffer to store the e-mail patch in + * @param diff containing the commit + * @param opts structure with options to influence content and formatting. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_diff_format_email( + git_buf *out, + git_diff *diff, + const git_diff_format_email_options *opts); + +/** + * Create an e-mail ready patch for a commit. + * + * Does not support creating patches for merge commits (yet). + * + * @param out buffer to store the e-mail patch in + * @param repo containing the commit + * @param commit pointer to up commit + * @param patch_no patch number of the commit + * @param total_patches total number of patches in the patch set + * @param flags determines the formatting of the e-mail + * @param diff_opts structure with options to influence diff or NULL for defaults. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_diff_commit_as_email( + git_buf *out, + git_repository *repo, + git_commit *commit, + size_t patch_no, + size_t total_patches, + git_diff_format_email_flags_t flags, + const git_diff_options *diff_opts); + +/** +* Initializes a `git_diff_format_email_options` with default values. Equivalent to +* creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT. +* +* @param opts the `git_diff_format_email_options` instance to initialize. +* @param version the version of the struct; you should pass +* `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION` here. +* @return Zero on success; -1 on failure. +*/ +GIT_EXTERN(int) git_diff_format_email_init_options( + git_diff_format_email_options *opts, + int version); + GIT_END_DECL /** @} */ diff --git a/src/diff.c b/src/diff.c index e62f45c225d..ba3cd26b50f 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1427,6 +1427,198 @@ int git_diff__paired_foreach( return error; } +int git_diff__commit( + git_diff **diff, + git_repository *repo, + const git_commit *commit, + const git_diff_options *opts) +{ + git_commit *parent = NULL; + git_diff *commit_diff = NULL; + git_tree *old_tree = NULL, *new_tree = NULL; + size_t parents; + int error = 0; + + if ((parents = git_commit_parentcount(commit)) > 1) { + char commit_oidstr[GIT_OID_HEXSZ + 1]; + + error = -1; + giterr_set(GITERR_INVALID, "Commit %s is a merge commit", + git_oid_tostr(commit_oidstr, GIT_OID_HEXSZ + 1, git_commit_id(commit))); + goto on_error; + } + + if (parents > 0) + if ((error = git_commit_parent(&parent, commit, 0)) < 0 || + (error = git_commit_tree(&old_tree, parent)) < 0) + goto on_error; + + if ((error = git_commit_tree(&new_tree, commit)) < 0 || + (error = git_diff_tree_to_tree(&commit_diff, repo, old_tree, new_tree, opts)) < 0) + goto on_error; + + *diff = commit_diff; + +on_error: + git_tree_free(new_tree); + git_tree_free(old_tree); + git_commit_free(parent); + + return error; +} + +int git_diff_format_email__append_header_tobuf( + git_buf *out, + const git_oid *id, + const git_signature *author, + const char *summary, + size_t patch_no, + size_t total_patches, + bool exclude_patchno_marker) +{ + char idstr[GIT_OID_HEXSZ + 1]; + char date_str[GIT_DATE_RFC2822_SZ]; + int error = 0; + + git_oid_fmt(idstr, id); + idstr[GIT_OID_HEXSZ] = '\0'; + + if ((error = git__date_rfc2822_fmt(date_str, sizeof(date_str), &author->when)) < 0) + return error; + + error = git_buf_printf(out, + "From %s Mon Sep 17 00:00:00 2001\n" \ + "From: %s <%s>\n" \ + "Date: %s\n" \ + "Subject: ", + idstr, + author->name, author->email, + date_str); + + if (error < 0) + return error; + + if (!exclude_patchno_marker) { + if (total_patches == 1) { + error = git_buf_puts(out, "[PATCH] "); + } else { + error = git_buf_printf(out, "[PATCH %"PRIuZ"/%"PRIuZ"] ", patch_no, total_patches); + } + + if (error < 0) + return error; + } + + error = git_buf_printf(out, "%s\n\n", summary); + + return error; +} + +int git_diff_format_email__append_patches_tobuf( + git_buf *out, + git_diff *diff) +{ + size_t i, deltas; + int error = 0; + + deltas = git_diff_num_deltas(diff); + + for (i = 0; i < deltas; ++i) { + git_patch *patch = NULL; + + if ((error = git_patch_from_diff(&patch, diff, i)) >= 0) + error = git_patch_to_buf(out, patch); + + git_patch_free(patch); + + if (error < 0) + break; + } + + return error; +} + +int git_diff_format_email( + git_buf *out, + git_diff *diff, + const git_diff_format_email_options *opts) +{ + git_diff_stats *stats = NULL; + bool ignore_marker; + unsigned int format_flags = 0; + int error; + + assert(out && diff && opts); + assert(opts->summary && opts->id && opts->author); + + GITERR_CHECK_VERSION(opts, GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, "git_format_email_options"); + + if ((ignore_marker = opts->flags & GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER) == false) { + if (opts->patch_no > opts->total_patches) { + giterr_set(GITERR_INVALID, "patch %"PRIuZ" out of range. max %"PRIuZ, opts->patch_no, opts->total_patches); + return -1; + } + + if (opts->patch_no == 0) { + giterr_set(GITERR_INVALID, "invalid patch no %"PRIuZ". should be >0", opts->patch_no); + return -1; + } + } + + error = git_diff_format_email__append_header_tobuf(out, + opts->id, opts->author, opts->summary, + opts->patch_no, opts->total_patches, ignore_marker); + + if (error < 0) + goto on_error; + + format_flags = GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY; + + if ((error = git_buf_puts(out, "---\n")) < 0 || + (error = git_diff_get_stats(&stats, diff)) < 0 || + (error = git_diff_stats_to_buf(out, stats, format_flags)) < 0 || + (error = git_diff_format_email__append_patches_tobuf(out, diff)) < 0) + goto on_error; + + error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n"); + +on_error: + git_diff_stats_free(stats); + + return error; +} + +int git_diff_commit_as_email( + git_buf *out, + git_repository *repo, + git_commit *commit, + size_t patch_no, + size_t total_patches, + git_diff_format_email_flags_t flags, + const git_diff_options *diff_opts) +{ + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + int error; + + assert (out && repo && commit); + + opts.flags = flags; + opts.patch_no = patch_no; + opts.total_patches = total_patches; + opts.id = git_commit_id(commit); + opts.summary = git_commit_summary(commit); + opts.author = git_commit_author(commit); + + if ((error = git_diff__commit(&diff, repo, commit, diff_opts)) < 0) + return error; + + error = git_diff_format_email(out, diff, &opts); + + git_diff_free(diff); + return error; +} + int git_diff_init_options(git_diff_options* opts, int version) { if (version != GIT_DIFF_OPTIONS_VERSION) { @@ -1450,3 +1642,15 @@ int git_diff_find_init_options(git_diff_find_options* opts, int version) return 0; } } + +int git_diff_format_email_init_options(git_diff_format_email_options* opts, int version) +{ + if (version != GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION) { + giterr_set(GITERR_INVALID, "Invalid version %d for git_diff_format_email_options", version); + return -1; + } else { + git_diff_format_email_options o = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + memcpy(opts, &o, sizeof(o)); + return 0; + } +} diff --git a/src/diff.h b/src/diff.h index c588f630112..aae8fbff163 100644 --- a/src/diff.h +++ b/src/diff.h @@ -116,6 +116,9 @@ extern void git_diff_find_similar__hashsig_free(void *sig, void *payload); extern int git_diff_find_similar__calc_similarity( int *score, void *siga, void *sigb, void *payload); +extern int git_diff__commit( + git_diff **diff, git_repository *repo, const git_commit *commit, const git_diff_options *opts); + /* * Sometimes a git_diff_file will have a zero size; this attempts to * fill in the size without loading the blob if possible. If that is diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c new file mode 100644 index 00000000000..ff0209e6fc2 --- /dev/null +++ b/tests/diff/format_email.c @@ -0,0 +1,445 @@ +#include "clar.h" +#include "clar_libgit2.h" + +#include "buffer.h" +#include "commit.h" +#include "diff.h" + +static git_repository *repo; + +void test_diff_format_email__initialize(void) +{ + repo = cl_git_sandbox_init("diff_format_email"); +} + +void test_diff_format_email__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_diff_format_email__simple(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + const char *email = + "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ + "Subject: [PATCH] Modify some content\n" \ + "\n" \ + "---\n" \ + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "index 94aaae8..af8f41d 100644\n" \ + "--- a/file1.txt\n" \ + "+++ b/file1.txt\n" \ + "@@ -1,15 +1,17 @@\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+\n" \ + "+\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_buf_clear(&buf); + cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__multiple(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + const char *email = + "From 10808fe9c9be5a190c0ba68d1a002233fb363508 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Thu, 10 Apr 2014 19:37:05 +0200\n" \ + "Subject: [PATCH 1/2] Added file2.txt file3.txt\n" \ + "\n" \ + "---\n" \ + " file2.txt | 5 +++++\n" \ + " file3.txt | 5 +++++\n" \ + " 2 files changed, 10 insertions(+), 0 deletions(-)\n" \ + " create mode 100644 file2.txt\n" \ + " create mode 100644 file3.txt\n" \ + "\n" \ + "diff --git a/file2.txt b/file2.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..e909123\n" \ + "--- /dev/null\n" \ + "+++ b/file2.txt\n" \ + "@@ -0,0 +1,5 @@\n" \ + "+file2\n" \ + "+file2\n" \ + "+file2\n" \ + "+file2\n" \ + "+file2\n" \ + "diff --git a/file3.txt b/file3.txt\n" \ + "new file mode 100644\n" \ + "index 0000000..9435022\n" \ + "--- /dev/null\n" \ + "+++ b/file3.txt\n" \ + "@@ -0,0 +1,5 @@\n" \ + "+file3\n" \ + "+file3\n" \ + "+file3\n" \ + "+file3\n" \ + "+file3\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n" \ + "From 873806f6f27e631eb0b23e4b56bea2bfac14a373 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Thu, 10 Apr 2014 19:37:36 +0200\n" \ + "Subject: [PATCH 2/2] Modified file2.txt, file3.txt\n" \ + "\n" \ + "---\n" \ + " file2.txt | 2 +-\n" \ + " file3.txt | 2 +-\n" \ + " 2 files changed, 2 insertions(+), 2 deletions(-)\n" \ + "\n" \ + "diff --git a/file2.txt b/file2.txt\n" \ + "index e909123..7aff11d 100644\n" \ + "--- a/file2.txt\n" \ + "+++ b/file2.txt\n" \ + "@@ -1,5 +1,5 @@\n" \ + " file2\n" \ + " file2\n" \ + " file2\n" \ + "-file2\n" \ + "+file2!\n" \ + " file2\n" \ + "diff --git a/file3.txt b/file3.txt\n" \ + "index 9435022..9a2d780 100644\n" \ + "--- a/file3.txt\n" \ + "+++ b/file3.txt\n" \ + "@@ -1,5 +1,5 @@\n" \ + " file3\n" \ + "-file3\n" \ + "+file3!\n" \ + " file3\n" \ + " file3\n" \ + " file3\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + git_oid_fromstr(&oid, "10808fe9c9be5a190c0ba68d1a002233fb363508"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + opts.patch_no = 1; + opts.total_patches = 2; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + + git_diff_free(diff); + git_commit_free(commit); + diff = NULL; + commit = NULL; + + git_oid_fromstr(&oid, "873806f6f27e631eb0b23e4b56bea2bfac14a373"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + opts.patch_no = 2; + opts.total_patches = 2; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__exclude_marker(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + const char *email = + "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ + "Subject: Modify some content\n" \ + "\n" \ + "---\n" \ + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "index 94aaae8..af8f41d 100644\n" \ + "--- a/file1.txt\n" \ + "+++ b/file1.txt\n" \ + "@@ -1,15 +1,17 @@\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+\n" \ + "+\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + + opts.flags |= GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_buf_clear(&buf); + cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, + GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER, NULL)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__invalid_no(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + opts.patch_no = 2; + opts.total_patches = 1; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_fail(git_diff_format_email(&buf, diff, &opts)); + cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 2, 1, 0, NULL)); + cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 0, 0, 0, NULL)); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__mode_change(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + const char *email = + "From 7ade76dd34bba4733cf9878079f9fd4a456a9189 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Thu, 10 Apr 2014 10:05:03 +0200\n" \ + "Subject: [PATCH] Update permissions\n" \ + "\n" \ + "---\n" \ + " file1.txt.renamed | 0\n" \ + " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \ + " mode change 100644 => 100755 file1.txt.renamed\n" \ + "\n" \ + "diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \ + "old mode 100644\n" \ + "new mode 100755\n" \ + "index a97157a..a97157a\n" \ + "--- a/file1.txt.renamed\n" \ + "+++ b/file1.txt.renamed\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + git_oid_fromstr(&oid, "7ade76dd34bba4733cf9878079f9fd4a456a9189"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_buf_clear(&buf); + cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + +void test_diff_format_email__rename_add_remove(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + const char *email = + "From 6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Wed, 9 Apr 2014 21:15:56 +0200\n" \ + "Subject: [PATCH] Renamed file1.txt -> file1.txt.renamed\n" \ + "\n" \ + "---\n" \ + " file1.txt | 17 -----------------\n" \ + " file1.txt.renamed | 17 +++++++++++++++++\n" \ + " 2 files changed, 17 insertions(+), 17 deletions(-)\n" \ + " delete mode 100644 file1.txt\n" \ + " create mode 100644 file1.txt.renamed\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "deleted file mode 100644\n" \ + "index af8f41d..0000000\n" \ + "--- a/file1.txt\n" \ + "+++ /dev/null\n" \ + "@@ -1,17 +0,0 @@\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-_file1.txt_\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-\n" \ + "-\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-_file1.txt_\n" \ + "-_file1.txt_\n" \ + "-file1.txt\n" \ + "diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \ + "new file mode 100644\n" \ + "index 0000000..a97157a\n" \ + "--- /dev/null\n" \ + "+++ b/file1.txt.renamed\n" \ + "@@ -0,0 +1,17 @@\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+_file1.txt_\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+file1.txt_renamed\n" \ + "+file1.txt\n" \ + "+\n" \ + "+\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+file1.txt_renamed\n" \ + "+file1.txt\n" \ + "+file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + "+file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + git_oid_fromstr(&oid, "6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = git_commit_summary(commit); + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_buf_clear(&buf); + cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + From a56b418d8541e04f02be1227772b13762bfebaed Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Fri, 11 Apr 2014 22:57:15 +0200 Subject: [PATCH 8/9] Sanitize git_diff_format_email_options' summary parameter It will form part of the subject line and should thus be one line. --- src/diff.c | 20 +++++++++++- tests/diff/format_email.c | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/diff.c b/src/diff.c index ba3cd26b50f..cb05a5fafb2 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1544,6 +1544,7 @@ int git_diff_format_email( const git_diff_format_email_options *opts) { git_diff_stats *stats = NULL; + char *summary = NULL, *loc = NULL; bool ignore_marker; unsigned int format_flags = 0; int error; @@ -1565,8 +1566,24 @@ int git_diff_format_email( } } + /* the summary we receive may not be clean. + * it could potentially contain new line characters + * or not be set, sanitize, */ + if ((loc = strpbrk(opts->summary, "\r\n")) != NULL) { + size_t offset = 0; + + if ((offset = (loc - opts->summary)) == 0) { + giterr_set(GITERR_INVALID, "summary is empty"); + error = -1; + } + + summary = git__calloc(offset + 1, sizeof(char)); + GITERR_CHECK_ALLOC(summary); + strncpy(summary, opts->summary, offset); + } + error = git_diff_format_email__append_header_tobuf(out, - opts->id, opts->author, opts->summary, + opts->id, opts->author, summary == NULL ? opts->summary : summary, opts->patch_no, opts->total_patches, ignore_marker); if (error < 0) @@ -1583,6 +1600,7 @@ int git_diff_format_email( error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n"); on_error: + git__free(summary); git_diff_stats_free(stats); return error; diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c index ff0209e6fc2..dbd41552f53 100644 --- a/tests/diff/format_email.c +++ b/tests/diff/format_email.c @@ -443,3 +443,71 @@ void test_diff_format_email__rename_add_remove(void) git_buf_free(&buf); } +void test_diff_format_email__multiline_summary(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + const char *email = + "From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ + "Subject: [PATCH] Modify some content\n" \ + "\n" \ + "---\n" \ + " file1.txt | 8 +++++---\n" \ + " 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ + "\n" \ + "diff --git a/file1.txt b/file1.txt\n" \ + "index 94aaae8..af8f41d 100644\n" \ + "--- a/file1.txt\n" \ + "+++ b/file1.txt\n" \ + "@@ -1,15 +1,17 @@\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "+\n" \ + "+\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + " file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "-file1.txt\n" \ + "+_file1.txt_\n" \ + "+_file1.txt_\n" \ + " file1.txt\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = "Modify some content\nSome extra stuff here"; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_buf_clear(&buf); + cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} + From 39206ca256409edb7102edf0d30a6ced2e5f16e3 Mon Sep 17 00:00:00 2001 From: Jacques Germishuys Date: Mon, 14 Apr 2014 17:12:56 +0200 Subject: [PATCH 9/9] Added a test case for formatting a binary patch e-mail --- tests/diff/format_email.c | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c index dbd41552f53..3260fdea89d 100644 --- a/tests/diff/format_email.c +++ b/tests/diff/format_email.c @@ -511,3 +511,46 @@ void test_diff_format_email__multiline_summary(void) git_buf_free(&buf); } +void test_diff_format_email__binary(void) +{ + git_oid oid; + git_commit *commit = NULL; + git_diff *diff = NULL; + git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + + /* TODO: Actually 0 bytes here should be 5!. Seems like we don't load the new content for binary files? */ + const char *email = + "From 8d7523f6fcb2404257889abe0d96f093d9f524f9 Mon Sep 17 00:00:00 2001\n" \ + "From: Jacques Germishuys \n" \ + "Date: Sun, 13 Apr 2014 18:10:18 +0200\n" \ + "Subject: [PATCH] Modified binary file\n" \ + "\n" \ + "---\n" \ + " binary.bin | Bin 3 -> 0 bytes\n" \ + " 1 file changed, 0 insertions(+), 0 deletions(-)\n" \ + "\n" \ + "diff --git a/binary.bin b/binary.bin\n" \ + "index bd474b2..9ac35ff 100644\n" \ + "Binary files a/binary.bin and b/binary.bin differ\n" \ + "--\n" \ + "libgit2 " LIBGIT2_VERSION "\n" \ + "\n"; + + git_oid_fromstr(&oid, "8d7523f6fcb2404257889abe0d96f093d9f524f9"); + + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + + opts.id = git_commit_id(commit); + opts.author = git_commit_author(commit); + opts.summary = "Modified binary file"; + + cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); + cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + + git_diff_free(diff); + git_commit_free(commit); + git_buf_free(&buf); +} +