mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 07:10:07 +00:00
Merge pull request #1017 from arrbee/diff-patch-to-str
Add git_diff_patch_to_str API
This commit is contained in:
commit
efde422553
@ -603,6 +603,34 @@ GIT_EXTERN(int) git_diff_patch_get_line_in_hunk(
|
||||
size_t hunk_idx,
|
||||
size_t line_of_hunk);
|
||||
|
||||
/**
|
||||
* Serialize the patch to text via callback.
|
||||
*
|
||||
* Returning a non-zero value from the callback will terminate the iteration
|
||||
* and cause this return `GIT_EUSER`.
|
||||
*
|
||||
* @param patch A git_diff_patch representing changes to one file
|
||||
* @param cb_data Reference pointer that will be passed to your callbacks.
|
||||
* @param print_cb Callback function to output lines of the patch. Will be
|
||||
* called for file headers, hunk headers, and diff lines.
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_patch_print(
|
||||
git_diff_patch *patch,
|
||||
void *cb_data,
|
||||
git_diff_data_fn print_cb);
|
||||
|
||||
/**
|
||||
* Get the content of a patch as a single diff text.
|
||||
*
|
||||
* @param string Allocated string; caller must free.
|
||||
* @param patch A git_diff_patch representing changes to one file
|
||||
* @return 0 on success, <0 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_patch_to_str(
|
||||
char **string,
|
||||
git_diff_patch *patch);
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
||||
|
@ -1502,3 +1502,74 @@ 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);
|
||||
return git_buf_put(output, content, content_len);
|
||||
}
|
||||
|
||||
int git_diff_patch_print(
|
||||
git_diff_patch *patch,
|
||||
void *cb_data,
|
||||
git_diff_data_fn print_cb)
|
||||
{
|
||||
int error;
|
||||
git_buf temp = GIT_BUF_INIT;
|
||||
diff_print_info pi;
|
||||
size_t h, l;
|
||||
|
||||
assert(patch && print_cb);
|
||||
|
||||
pi.diff = patch->diff;
|
||||
pi.print_cb = print_cb;
|
||||
pi.cb_data = cb_data;
|
||||
pi.buf = &temp;
|
||||
|
||||
error = print_patch_file(&pi, patch->delta, 0);
|
||||
|
||||
for (h = 0; h < patch->hunks_size && !error; ++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 && !error; ++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);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_diff_patch_to_str(
|
||||
char **string,
|
||||
git_diff_patch *patch)
|
||||
{
|
||||
int error;
|
||||
git_buf output = GIT_BUF_INIT;
|
||||
|
||||
error = git_diff_patch_print(patch, &output, print_to_buffer_cb);
|
||||
|
||||
/* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1,
|
||||
* meaning a memory allocation failure, so just map to -1...
|
||||
*/
|
||||
if (error == GIT_EUSER)
|
||||
error = -1;
|
||||
|
||||
*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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user