Add git_diff_patch_size() API This adds a new API to get the size in bytes of the diffs in a git_diff_patch object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 71a8b72..7119675 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -943,6 +943,24 @@ GIT_EXTERN(int) git_diff_patch_get_line_in_hunk(
size_t line_of_hunk);
/**
+ * Look up size of patch diff data in bytes
+ *
+ * This returns the raw size of the patch data. This only includes the
+ * actual data from the lines of the diff, not the file or hunk headers.
+ *
+ * If you pass `include_context` as true (non-zero), this will be the size
+ * of all of the diff output; if you pass it as false (zero), this will
+ * only include the actual changed lines (as if `context_lines` was 0).
+ *
+ * @param patch A git_diff_patch representing changes to one file
+ * @param include_context Include context lines in size if non-zero
+ * @return The number of bytes of data
+ */
+GIT_EXTERN(size_t) git_diff_patch_size(
+ git_diff_patch *patch,
+ int include_context);
+
+/**
* Serialize the patch to text via callback.
*
* Returning a non-zero value from the callback will terminate the iteration
diff --git a/src/diff_patch.c b/src/diff_patch.c
index 1b4adac..5febc88 100644
--- a/src/diff_patch.c
+++ b/src/diff_patch.c
@@ -42,7 +42,7 @@ struct git_diff_patch {
git_array_t(diff_patch_hunk) hunks;
git_array_t(diff_patch_line) lines;
size_t oldno, newno;
- size_t content_size;
+ size_t content_size, context_size;
git_pool flattened;
};
@@ -806,6 +806,20 @@ notfound:
return diff_error_outofrange(thing);
}
+size_t git_diff_patch_size(git_diff_patch *patch, int include_context)
+{
+ size_t out;
+
+ assert(patch);
+
+ out = patch->content_size;
+
+ if (!include_context)
+ out -= patch->context_size;
+
+ return out;
+}
+
git_diff_list *git_diff_patch__diff(git_diff_patch *patch)
{
return patch->diff;
@@ -934,7 +948,11 @@ static int diff_patch_line_cb(
line->len = content_len;
line->origin = line_origin;
- patch->content_size += content_len;
+ patch->content_size += content_len + 1; /* +1 for line_origin */
+
+ if (line_origin == GIT_DIFF_LINE_CONTEXT ||
+ line_origin == GIT_DIFF_LINE_CONTEXT_EOFNL)
+ patch->context_size += content_len + 1;
/* do some bookkeeping so we can provide old/new line numbers */
diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c
index 3f14a0d..51baadf 100644
--- a/tests-clar/diff/patch.c
+++ b/tests-clar/diff/patch.c
@@ -128,6 +128,9 @@ void test_diff_patch__to_string(void)
cl_assert_equal_s(expected, text);
+ cl_assert_equal_sz(31, git_diff_patch_size(patch, 0));
+ cl_assert_equal_sz(31, git_diff_patch_size(patch, 1));
+
git__free(text);
git_diff_patch_free(patch);
git_diff_list_free(diff);
@@ -409,6 +412,7 @@ void test_diff_patch__hunks_have_correct_line_numbers(void)
static void check_single_patch_stats(
git_repository *repo, size_t hunks,
size_t adds, size_t dels, size_t ctxt,
+ size_t size_with_context, size_t size_without_context,
const char *expected)
{
git_diff_list *diff;
@@ -439,6 +443,13 @@ static void check_single_patch_stats(
git__free(text);
}
+ if (size_with_context)
+ cl_assert_equal_sz(
+ size_with_context, git_diff_patch_size(patch, 1));
+ if (size_without_context)
+ cl_assert_equal_sz(
+ size_without_context, git_diff_patch_size(patch, 0));
+
/* walk lines in hunk with basic sanity checks */
for (; hunks > 0; --hunks) {
size_t i, max_i;
@@ -495,14 +506,14 @@ void test_diff_patch__line_counts_with_eofnl(void)
git_buf_consume(&content, end);
cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
- check_single_patch_stats(g_repo, 1, 0, 1, 3, NULL);
+ check_single_patch_stats(g_repo, 1, 0, 1, 3, 0, 0, NULL);
/* remove trailing whitespace */
git_buf_rtrim(&content);
cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
- check_single_patch_stats(g_repo, 2, 1, 2, 6, NULL);
+ check_single_patch_stats(g_repo, 2, 1, 2, 6, 0, 0, NULL);
/* add trailing whitespace */
@@ -514,7 +525,7 @@ void test_diff_patch__line_counts_with_eofnl(void)
cl_git_pass(git_buf_putc(&content, '\n'));
cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
- check_single_patch_stats(g_repo, 1, 1, 1, 3, NULL);
+ check_single_patch_stats(g_repo, 1, 1, 1, 3, 0, 0, NULL);
/* no trailing whitespace as context line */
@@ -537,7 +548,7 @@ void test_diff_patch__line_counts_with_eofnl(void)
cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
check_single_patch_stats(
- g_repo, 1, 1, 1, 6,
+ g_repo, 1, 1, 1, 6, 349, 115,
/* below is pasted output of 'git diff' with fn context removed */
"diff --git a/songof7cities.txt b/songof7cities.txt\n"
"index 378a7d9..3d0154e 100644\n"