From 9cea29d15401ee091da2c9212ac584e42510d462 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 22 Jun 2024 21:20:34 +0100 Subject: [PATCH] blame: update API Use `size_t` for sizes, standardize naming with the rest of the library. --- examples/blame.c | 2 +- include/git2/blame.h | 108 ++++++++++++++++++++-------- src/libgit2/blame.c | 55 ++++++++++---- tests/libgit2/blame/blame_helpers.c | 2 +- tests/libgit2/blame/buffer.c | 14 ++-- tests/libgit2/blame/getters.c | 8 +-- tests/libgit2/blame/harder.c | 4 +- tests/libgit2/blame/simple.c | 18 ++--- tests/libgit2/mailmap/blame.c | 4 +- 9 files changed, 147 insertions(+), 68 deletions(-) diff --git a/examples/blame.c b/examples/blame.c index 0996e7a1f..1e2869a63 100644 --- a/examples/blame.c +++ b/examples/blame.c @@ -97,7 +97,7 @@ int lg2_blame(git_repository *repo, int argc, char *argv[]) while (i < rawsize) { const char *eol = memchr(rawdata + i, '\n', (size_t)(rawsize - i)); char oid[10] = {0}; - const git_blame_hunk *hunk = git_blame_get_hunk_byline(blame, line); + const git_blame_hunk *hunk = git_blame_hunk_byline(blame, line); if (break_on_null_hunk && !hunk) break; diff --git a/include/git2/blame.h b/include/git2/blame.h index cb961a562..dec2a8a3f 100644 --- a/include/git2/blame.h +++ b/include/git2/blame.h @@ -87,7 +87,7 @@ typedef struct git_blame_options { unsigned int version; /** A combination of `git_blame_flag_t` */ - uint32_t flags; + unsigned int flags; /** * The lower bound on the number of alphanumeric characters that @@ -207,6 +207,39 @@ typedef struct git_blame git_blame; * @param blame The blame structure to query. * @return The number of hunks. */ +GIT_EXTERN(size_t) git_blame_hunkcount(git_blame *blame); + +/** + * Gets the blame hunk at the given index. + * + * @param blame the blame structure to query + * @param index index of the hunk to retrieve + * @return the hunk at the given index, or NULL on error + */ +GIT_EXTERN(const git_blame_hunk *) git_blame_hunk_byindex( + git_blame *blame, + size_t index); + +/** + * Gets the hunk that relates to the given line number in the newest + * commit. + * + * @param blame the blame structure to query + * @param lineno the (1-based) line number to find a hunk for + * @return the hunk that contains the given line, or NULL on error + */ +GIT_EXTERN(const git_blame_hunk *) git_blame_hunk_byline( + git_blame *blame, + size_t lineno); + +#ifndef GIT_DEPRECATE_HARD +/** + * Gets the number of hunks that exist in the blame structure. + * + * @param blame The blame structure to query. + * @return The number of hunks. + */ + GIT_EXTERN(uint32_t) git_blame_get_hunk_count(git_blame *blame); /** @@ -216,9 +249,9 @@ GIT_EXTERN(uint32_t) git_blame_get_hunk_count(git_blame *blame); * @param index index of the hunk to retrieve * @return the hunk at the given index, or NULL on error */ -GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byindex( - git_blame *blame, - uint32_t index); +GIT_EXTERN(const git_blame_hunk *) git_blame_get_hunk_byindex( + git_blame *blame, + uint32_t index); /** * Gets the hunk that relates to the given line number in the newest commit. @@ -227,39 +260,58 @@ GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byindex( * @param lineno the (1-based) line number to find a hunk for * @return the hunk that contains the given line, or NULL on error */ -GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byline( - git_blame *blame, - size_t lineno); +GIT_EXTERN(const git_blame_hunk *) git_blame_get_hunk_byline( + git_blame *blame, + size_t lineno); +#endif /** - * Get the blame for a single file. + * Get the blame for a single file in the repository. * * @param out pointer that will receive the blame object * @param repo repository whose history is to be walked * @param path path to file to consider - * @param options options for the blame operation. If NULL, this is treated as - * though GIT_BLAME_OPTIONS_INIT were passed. - * @return 0 on success, or an error code. (use git_error_last for information - * about the error.) + * @param options options for the blame operation or NULL + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_blame_file( - git_blame **out, - git_repository *repo, - const char *path, - git_blame_options *options); - + git_blame **out, + git_repository *repo, + const char *path, + git_blame_options *options); /** - * Get blame data for a file that has been modified in memory. The `reference` - * parameter is a pre-calculated blame for the in-odb history of the file. This - * means that once a file blame is completed (which can be expensive), updating - * the buffer blame is very fast. + * Get the blame for a single file in the repository, using the specified + * buffer contents as the uncommitted changes of the file (the working + * directory contents). * - * Lines that differ between the buffer and the committed version are marked as - * having a zero OID for their final_commit_id. + * @param out pointer that will receive the blame object + * @param repo repository whose history is to be walked + * @param path path to file to consider + * @param contents the uncommitted changes + * @param contents_len the length of the changes buffer + * @param options options for the blame operation or NULL + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_blame_file_from_buffer( + git_blame **out, + git_repository *repo, + const char *path, + const char *contents, + size_t contents_len, + git_blame_options *options); + +/** + * Get blame data for a file that has been modified in memory. The `blame` + * parameter is a pre-calculated blame for the in-odb history of the file. + * This means that once a file blame is completed (which can be expensive), + * updating the buffer blame is very fast. + * + * Lines that differ between the buffer and the committed version are + * marked as having a zero OID for their final_commit_id. * * @param out pointer that will receive the resulting blame data - * @param reference cached blame from the history of the file (usually the output + * @param base cached blame from the history of the file (usually the output * from git_blame_file) * @param buffer the (possibly) modified contents of the file * @param buffer_len number of valid bytes in the buffer @@ -267,10 +319,10 @@ GIT_EXTERN(int) git_blame_file( * about the error) */ GIT_EXTERN(int) git_blame_buffer( - git_blame **out, - git_blame *reference, - const char *buffer, - size_t buffer_len); + git_blame **out, + git_blame *base, + const char *buffer, + size_t buffer_len); /** * Free memory allocated by git_blame_file or git_blame_buffer. diff --git a/src/libgit2/blame.c b/src/libgit2/blame.c index 693e39b5e..7b872dc76 100644 --- a/src/libgit2/blame.c +++ b/src/libgit2/blame.c @@ -19,7 +19,6 @@ #include "repository.h" #include "blame_git.h" - static int hunk_byfinalline_search_cmp(const void *key, const void *entry) { git_blame_hunk *hunk = (git_blame_hunk*)entry; @@ -178,31 +177,59 @@ void git_blame_free(git_blame *blame) git__free(blame); } -uint32_t git_blame_get_hunk_count(git_blame *blame) +size_t git_blame_hunkcount(git_blame *blame) { GIT_ASSERT_ARG(blame); - return (uint32_t)blame->hunks.length; + + return blame->hunks.length; } -const git_blame_hunk *git_blame_get_hunk_byindex(git_blame *blame, uint32_t index) +const git_blame_hunk *git_blame_hunk_byindex( + git_blame *blame, + size_t index) { GIT_ASSERT_ARG_WITH_RETVAL(blame, NULL); - return (git_blame_hunk*)git_vector_get(&blame->hunks, index); + return git_vector_get(&blame->hunks, index); } -const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_t lineno) +const git_blame_hunk *git_blame_hunk_byline( + git_blame *blame, + size_t lineno) { size_t i, new_lineno = lineno; GIT_ASSERT_ARG_WITH_RETVAL(blame, NULL); - if (!git_vector_bsearch2(&i, &blame->hunks, hunk_byfinalline_search_cmp, &new_lineno)) { - return git_blame_get_hunk_byindex(blame, (uint32_t)i); - } + if (git_vector_bsearch2(&i, &blame->hunks, + hunk_byfinalline_search_cmp, &new_lineno) != 0) + return NULL; - return NULL; + return git_blame_hunk_byindex(blame, i); } +#ifndef GIT_DEPRECATE_HARD +uint32_t git_blame_get_hunk_count(git_blame *blame) +{ + size_t count = git_blame_hunkcount(blame); + GIT_ASSERT(count < UINT32_MAX); + return (uint32_t)count; +} + +const git_blame_hunk *git_blame_get_hunk_byindex( + git_blame *blame, + uint32_t index) +{ + return git_blame_hunk_byindex(blame, index); +} + +const git_blame_hunk *git_blame_get_hunk_byline( + git_blame *blame, + size_t lineno) +{ + return git_blame_hunk_byline(blame, lineno); +} +#endif + static int normalize_options( git_blame_options *out, const git_blame_options *in, @@ -444,9 +471,9 @@ static int buffer_hunk_cb( GIT_UNUSED(delta); - wedge_line = (hunk->new_start >= hunk->old_start || hunk->old_lines==0) ? hunk->new_start : hunk->old_start; + wedge_line = (hunk->new_start >= hunk->old_start || hunk->old_lines==0) ? hunk->new_start : hunk->old_start; blame->current_diff_line = wedge_line; - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byline(blame, wedge_line); + blame->current_hunk = (git_blame_hunk*)git_blame_hunk_byline(blame, wedge_line); if (!blame->current_hunk) { /* Line added at the end of the file */ blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, @@ -504,8 +531,8 @@ static int buffer_line_cb( if (!git_vector_search2(&i, &blame->hunks, ptrs_equal_cmp, blame->current_hunk)) { git_vector_remove(&blame->hunks, i); free_hunk(blame->current_hunk); - i_next = min( i , blame->hunks.length -1); - blame->current_hunk = (git_blame_hunk*)git_blame_get_hunk_byindex(blame, (uint32_t)i_next); + i_next = min( i , blame->hunks.length -1); + blame->current_hunk = (git_blame_hunk*)git_blame_hunk_byindex(blame, (uint32_t)i_next); } } shift_hunks_by(&blame->hunks, shift_base, -1); diff --git a/tests/libgit2/blame/blame_helpers.c b/tests/libgit2/blame/blame_helpers.c index 8aeaa5886..c8c3d4832 100644 --- a/tests/libgit2/blame/blame_helpers.c +++ b/tests/libgit2/blame/blame_helpers.c @@ -18,7 +18,7 @@ void check_blame_hunk_index(git_repository *repo, git_blame *blame, int idx, size_t start_line, size_t len, char boundary, const char *commit_id, const char *orig_path) { char expected[GIT_OID_SHA1_HEXSIZE+1] = {0}, actual[GIT_OID_SHA1_HEXSIZE+1] = {0}; - const git_blame_hunk *hunk = git_blame_get_hunk_byindex(blame, idx); + const git_blame_hunk *hunk = git_blame_hunk_byindex(blame, idx); cl_assert(hunk); if (!strncmp(commit_id, "0000", 4)) { diff --git a/tests/libgit2/blame/buffer.c b/tests/libgit2/blame/buffer.c index 456402c4e..cf70dbb31 100644 --- a/tests/libgit2/blame/buffer.c +++ b/tests/libgit2/blame/buffer.c @@ -220,14 +220,14 @@ void test_blame_buffer__index(void) cl_git_pass(git_blame_file(&g_fileblame, g_repo, "file.txt", NULL)); cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 1, 0, "836bc00b", "file.txt"); - hunk = git_blame_get_hunk_byline(g_bufferblame, 1); + hunk = git_blame_hunk_byline(g_bufferblame, 1); cl_assert(hunk); cl_assert_equal_s("lhchavez", hunk->final_signature->name); check_blame_hunk_index(g_repo, g_bufferblame, 1, 2, 1, 0, "00000000", "file.txt"); - hunk = git_blame_get_hunk_byline(g_bufferblame, 2); + hunk = git_blame_hunk_byline(g_bufferblame, 2); cl_assert(hunk); cl_assert(hunk->final_signature == NULL); } @@ -256,10 +256,10 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\n"; cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(5, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(5, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 1, 0, "000000", "b.txt"); - hunk = git_blame_get_hunk_byline(g_bufferblame, 16); + hunk = git_blame_hunk_byline(g_bufferblame, 16); cl_assert(hunk); cl_assert_equal_s("Ben Straub", hunk->final_signature->name); } @@ -294,7 +294,7 @@ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC \n"; cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(7, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(7, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 3, 0, "000000", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 4, 14, 3, 0, "000000", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 6, 22, 3, 0, "000000", "b.txt"); @@ -411,7 +411,7 @@ abc\n\ def\n"; cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer))); - cl_assert_equal_i(5, git_blame_get_hunk_count(g_bufferblame)); + cl_assert_equal_i(5, git_blame_hunkcount(g_bufferblame)); check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_bufferblame, 2, 6, 5, 0, "63d671eb", "b.txt"); diff --git a/tests/libgit2/blame/getters.c b/tests/libgit2/blame/getters.c index c160cd383..eb7936a9b 100644 --- a/tests/libgit2/blame/getters.c +++ b/tests/libgit2/blame/getters.c @@ -37,20 +37,20 @@ void test_blame_getters__cleanup(void) void test_blame_getters__byindex(void) { - const git_blame_hunk *h = git_blame_get_hunk_byindex(g_blame, 2); + const git_blame_hunk *h = git_blame_hunk_byindex(g_blame, 2); cl_assert(h); cl_assert_equal_s(h->orig_path, "c"); - h = git_blame_get_hunk_byindex(g_blame, 95); + h = git_blame_hunk_byindex(g_blame, 95); cl_assert_equal_p(h, NULL); } void test_blame_getters__byline(void) { - const git_blame_hunk *h = git_blame_get_hunk_byline(g_blame, 5); + const git_blame_hunk *h = git_blame_hunk_byline(g_blame, 5); cl_assert(h); cl_assert_equal_s(h->orig_path, "b"); - h = git_blame_get_hunk_byline(g_blame, 95); + h = git_blame_hunk_byline(g_blame, 95); cl_assert_equal_p(h, NULL); } diff --git a/tests/libgit2/blame/harder.c b/tests/libgit2/blame/harder.c index e77741720..412949a3b 100644 --- a/tests/libgit2/blame/harder.c +++ b/tests/libgit2/blame/harder.c @@ -10,7 +10,7 @@ * |\ * | * (B) aa06ecc * * | (C) 63d671e - * |/ + * |/ * * (D) da23739 * * (E) b99f7ac * @@ -71,7 +71,7 @@ void test_blame_harder__ccc(void) git_blame_options opts = GIT_BLAME_OPTIONS_INIT; GIT_UNUSED(opts); - + /* Attribute the third hunk in b.txt to (E). This hunk was deleted from * a.txt in (D), but reintroduced in (B). */ diff --git a/tests/libgit2/blame/simple.c b/tests/libgit2/blame/simple.c index 6b13cccd4..ee6d5f866 100644 --- a/tests/libgit2/blame/simple.c +++ b/tests/libgit2/blame/simple.c @@ -27,7 +27,7 @@ void test_blame_simple__trivial_testrepo(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo/.gitted"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "branch_file.txt", NULL)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 1, 0, "c47800c7", "branch_file.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 2, 1, 0, "a65fedf3", "branch_file.txt"); } @@ -57,7 +57,7 @@ void test_blame_simple__trivial_blamerepo(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", NULL)); - cl_assert_equal_i(4, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(4, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 5, 0, "63d671eb", "b.txt"); @@ -233,7 +233,7 @@ void test_blame_simple__can_restrict_lines_min(void) opts.min_line = 8; cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 8, 3, 0, "63d671eb", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 11, 5, 0, "aa06ecca", "b.txt"); } @@ -252,7 +252,7 @@ void test_blame_simple__can_ignore_whitespace_change(void) opts.flags |= GIT_BLAME_IGNORE_WHITESPACE; cl_git_pass(git_blame_file(&g_blame, g_repo, "c.txt", &opts)); - cl_assert_equal_i(1, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(1, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "702c7aa5", "c.txt"); } @@ -275,7 +275,7 @@ void test_blame_simple__can_restrict_lines_max(void) opts.max_line = 6; cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(3, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(3, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 1, 0, "63d671eb", "b.txt"); @@ -301,7 +301,7 @@ void test_blame_simple__can_restrict_lines_both(void) opts.min_line = 2; opts.max_line = 7; cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(3, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(3, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 2, 3, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 2, 0, "63d671eb", "b.txt"); @@ -314,7 +314,7 @@ void test_blame_simple__can_blame_huge_file(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "huge.txt", &opts)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 65536, 0, "4eecfea", "huge.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 65537, 1, 0, "6653ff4", "huge.txt"); } @@ -341,7 +341,7 @@ void test_blame_simple__can_restrict_to_newish_commits(void) cl_git_pass(git_blame_file(&g_blame, g_repo, "branch_file.txt", &opts)); - cl_assert_equal_i(2, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(2, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 1, 1, "be3563a", "branch_file.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 2, 1, 0, "a65fedf", "branch_file.txt"); } @@ -354,7 +354,7 @@ void test_blame_simple__can_restrict_to_first_parent_commits(void) cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git"))); cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts)); - cl_assert_equal_i(4, git_blame_get_hunk_count(g_blame)); + cl_assert_equal_i(4, git_blame_hunkcount(g_blame)); check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "da237394", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt"); check_blame_hunk_index(g_repo, g_blame, 2, 6, 5, 0, "63d671eb", "b.txt"); diff --git a/tests/libgit2/mailmap/blame.c b/tests/libgit2/mailmap/blame.c index e6bc1a41f..ce2c9d48a 100644 --- a/tests/libgit2/mailmap/blame.c +++ b/tests/libgit2/mailmap/blame.c @@ -33,7 +33,7 @@ void test_mailmap_blame__hunks(void) cl_assert(g_blame); for (idx = 0; idx < ARRAY_SIZE(resolved); ++idx) { - hunk = git_blame_get_hunk_byline(g_blame, idx + 1); + hunk = git_blame_hunk_byline(g_blame, idx + 1); cl_assert(hunk->final_signature != NULL); cl_assert(hunk->orig_signature != NULL); @@ -54,7 +54,7 @@ void test_mailmap_blame__hunks_no_mailmap(void) cl_assert(g_blame); for (idx = 0; idx < ARRAY_SIZE(resolved); ++idx) { - hunk = git_blame_get_hunk_byline(g_blame, idx + 1); + hunk = git_blame_hunk_byline(g_blame, idx + 1); cl_assert(hunk->final_signature != NULL); cl_assert(hunk->orig_signature != NULL);