Commit 93cf7bb8 by Russell Belfer

Add git_diff_patch_to_str API

This adds an API to generate a complete single-file patch text
from a git_diff_patch object.
parent 6f6b0c01
......@@ -603,6 +603,17 @@ GIT_EXTERN(int) git_diff_patch_get_line_in_hunk(
size_t hunk_idx,
size_t line_of_hunk);
/**
* Get the content of a patch as a single diff text.
*
* @param string Allocated string; caller must free.
* @param patch The patch to generate a string from.
* @return 0 on success, <0 on failure.
*/
GIT_EXTERN(int) git_diff_patch_to_str(
char **string,
git_diff_patch *patch);
/**@}*/
......
......@@ -1502,3 +1502,57 @@ notfound:
return GIT_ENOTFOUND;
}
static int print_to_buffer_cb(
void *cb_data,
const git_diff_delta *delta,
const git_diff_range *range,
char line_origin,
const char *content,
size_t content_len)
{
git_buf *output = cb_data;
GIT_UNUSED(delta);
GIT_UNUSED(range);
GIT_UNUSED(line_origin);
git_buf_put(output, content, content_len);
return 0;
}
int git_diff_patch_to_str(
char **string,
git_diff_patch *patch)
{
int error;
git_buf output = GIT_BUF_INIT, temp = GIT_BUF_INIT;
diff_print_info pi;
size_t h, l;
pi.diff = patch->diff;
pi.print_cb = print_to_buffer_cb;
pi.cb_data = &output;
pi.buf = &temp;
error = print_patch_file(&pi, patch->delta, 0);
for (h = 0; h < patch->hunks_size; ++h) {
diff_patch_hunk *hunk = &patch->hunks[h];
error = print_patch_hunk(&pi, patch->delta,
&hunk->range, hunk->header, hunk->header_len);
for (l = 0; l < hunk->line_count; ++l) {
diff_patch_line *line = &patch->lines[hunk->line_start + l];
error = print_patch_line(
&pi, patch->delta, &hunk->range,
line->origin, line->ptr, line->len);
}
}
git_buf_free(&temp);
*string = git_buf_detach(&output);
return error;
}
......@@ -342,3 +342,102 @@ void test_diff_diffiter__iterate_randomly_while_saving_state(void)
cl_assert_equal_i(8, exp.hunks);
cl_assert_equal_i(14, exp.lines);
}
/* This output is taken directly from `git diff` on the status test data */
static const char *expected_patch_text[8] = {
/* 0 */
"diff --git a/file_deleted b/file_deleted\n"
"deleted file mode 100644\n"
"index 5452d32..0000000\n"
"--- a/file_deleted\n"
"+++ /dev/null\n"
"@@ -1 +0,0 @@\n"
"-file_deleted\n",
/* 1 */
"diff --git a/modified_file b/modified_file\n"
"index 452e424..0a53963 100644\n"
"--- a/modified_file\n"
"+++ b/modified_file\n"
"@@ -1 +1,2 @@\n"
" modified_file\n"
"+modified_file\n",
/* 2 */
"diff --git a/staged_changes_file_deleted b/staged_changes_file_deleted\n"
"deleted file mode 100644\n"
"index a6be623..0000000\n"
"--- a/staged_changes_file_deleted\n"
"+++ /dev/null\n"
"@@ -1,2 +0,0 @@\n"
"-staged_changes_file_deleted\n"
"-staged_changes_file_deleted\n",
/* 3 */
"diff --git a/staged_changes_modified_file b/staged_changes_modified_file\n"
"index 906ee77..011c344 100644\n"
"--- a/staged_changes_modified_file\n"
"+++ b/staged_changes_modified_file\n"
"@@ -1,2 +1,3 @@\n"
" staged_changes_modified_file\n"
" staged_changes_modified_file\n"
"+staged_changes_modified_file\n",
/* 4 */
"diff --git a/staged_new_file_deleted_file b/staged_new_file_deleted_file\n"
"deleted file mode 100644\n"
"index 90b8c29..0000000\n"
"--- a/staged_new_file_deleted_file\n"
"+++ /dev/null\n"
"@@ -1 +0,0 @@\n"
"-staged_new_file_deleted_file\n",
/* 5 */
"diff --git a/staged_new_file_modified_file b/staged_new_file_modified_file\n"
"index ed06290..8b090c0 100644\n"
"--- a/staged_new_file_modified_file\n"
"+++ b/staged_new_file_modified_file\n"
"@@ -1 +1,2 @@\n"
" staged_new_file_modified_file\n"
"+staged_new_file_modified_file\n",
/* 6 */
"diff --git a/subdir/deleted_file b/subdir/deleted_file\n"
"deleted file mode 100644\n"
"index 1888c80..0000000\n"
"--- a/subdir/deleted_file\n"
"+++ /dev/null\n"
"@@ -1 +0,0 @@\n"
"-subdir/deleted_file\n",
/* 7 */
"diff --git a/subdir/modified_file b/subdir/modified_file\n"
"index a619198..57274b7 100644\n"
"--- a/subdir/modified_file\n"
"+++ b/subdir/modified_file\n"
"@@ -1 +1,2 @@\n"
" subdir/modified_file\n"
"+subdir/modified_file\n"
};
void test_diff_diffiter__iterate_and_generate_patch_text(void)
{
git_repository *repo = cl_git_sandbox_init("status");
git_diff_list *diff;
size_t d, num_d;
cl_git_pass(git_diff_workdir_to_index(repo, NULL, &diff));
num_d = git_diff_num_deltas(diff);
cl_assert_equal_i(8, (int)num_d);
for (d = 0; d < num_d; ++d) {
git_diff_patch *patch;
char *text;
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, d));
cl_assert(patch != NULL);
cl_git_pass(git_diff_patch_to_str(&text, patch));
cl_assert_equal_s(expected_patch_text[d], text);
git__free(text);
git_diff_patch_free(patch);
}
git_diff_list_free(diff);
}
......@@ -97,3 +97,33 @@ void test_diff_patch__can_properly_display_the_removal_of_a_file(void)
git_tree_free(another);
git_tree_free(one);
}
void test_diff_patch__to_string(void)
{
const char *one_sha = "26a125e";
const char *another_sha = "735b6a2";
git_tree *one, *another;
git_diff_list *diff;
git_diff_patch *patch;
char *text;
const char *expected = "diff --git a/subdir.txt b/subdir.txt\ndeleted file mode 100644\nindex e8ee89e..0000000\n--- a/subdir.txt\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-Is it a bird?\n-Is it a plane?\n";
one = resolve_commit_oid_to_tree(g_repo, one_sha);
another = resolve_commit_oid_to_tree(g_repo, another_sha);
cl_git_pass(git_diff_tree_to_tree(g_repo, NULL, one, another, &diff));
cl_assert_equal_i(1, git_diff_num_deltas(diff));
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
cl_git_pass(git_diff_patch_to_str(&text, patch));
cl_assert_equal_s(expected, text);
git__free(text);
git_diff_patch_free(patch);
git_diff_list_free(diff);
git_tree_free(another);
git_tree_free(one);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment