Commit b4a4cf24a539ce07d86fed6835c98154fb40e723

Russell Belfer 2013-07-22T16:07:56

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.

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"