diff options
| author | Russell Belfer <rb@github.com> | 2012-10-24 20:56:32 -0700 | 
|---|---|---|
| committer | Russell Belfer <rb@github.com> | 2012-10-24 20:56:32 -0700 | 
| commit | 93cf7bb8e26a04d9bd4197c1b938cee352023f63 (patch) | |
| tree | 34fc8c5fbf63e3962573d768c252197bcdf177e3 | |
| parent | 6f6b0c013c6eff2aca2a7ada1027044f2e20f578 (diff) | |
| download | libgit2-93cf7bb8e26a04d9bd4197c1b938cee352023f63.tar.gz | |
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.
| -rw-r--r-- | include/git2/diff.h | 11 | ||||
| -rw-r--r-- | src/diff_output.c | 54 | ||||
| -rw-r--r-- | tests-clar/diff/diffiter.c | 99 | ||||
| -rw-r--r-- | tests-clar/diff/patch.c | 30 | 
4 files changed, 194 insertions, 0 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h index 1932db029..1c2a2f83a 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -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); +  /**@}*/ diff --git a/src/diff_output.c b/src/diff_output.c index 5f0d13c64..511e9318b 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -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; +} + diff --git a/tests-clar/diff/diffiter.c b/tests-clar/diff/diffiter.c index f6d9bfc38..86e8d1f57 100644 --- a/tests-clar/diff/diffiter.c +++ b/tests-clar/diff/diffiter.c @@ -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); +} diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c index e8468386c..dce6d6da2 100644 --- a/tests-clar/diff/patch.c +++ b/tests-clar/diff/patch.c @@ -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); +}  | 
