-
Notifications
You must be signed in to change notification settings - Fork 2.6k
DRY commit parsing #4445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DRY commit parsing #4445
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| #include "revwalk.h" | ||
| #include "pool.h" | ||
| #include "odb.h" | ||
| #include "commit.h" | ||
|
|
||
| int git_commit_list_time_cmp(const void *a, const void *b) | ||
| { | ||
|
|
@@ -55,17 +56,6 @@ git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk) | |
| return (git_commit_list_node *)git_pool_mallocz(&walk->commit_pool, 1); | ||
| } | ||
|
|
||
| static int commit_error(git_commit_list_node *commit, const char *msg) | ||
| { | ||
| char commit_oid[GIT_OID_HEXSZ + 1]; | ||
| git_oid_fmt(commit_oid, &commit->oid); | ||
| commit_oid[GIT_OID_HEXSZ] = '\0'; | ||
|
|
||
| git_error_set(GIT_ERROR_ODB, "failed to parse commit %s - %s", commit_oid, msg); | ||
|
|
||
| return -1; | ||
| } | ||
|
|
||
| static git_commit_list_node **alloc_parents( | ||
| git_revwalk *walk, git_commit_list_node *commit, size_t n_parents) | ||
| { | ||
|
|
@@ -107,77 +97,42 @@ git_commit_list_node *git_commit_list_pop(git_commit_list **stack) | |
|
|
||
| static int commit_quick_parse( | ||
| git_revwalk *walk, | ||
| git_commit_list_node *commit, | ||
| const uint8_t *buffer, | ||
| size_t buffer_len) | ||
| git_commit_list_node *node, | ||
| git_odb_object *obj) | ||
| { | ||
| const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; | ||
| const uint8_t *buffer_end = buffer + buffer_len; | ||
| const uint8_t *parents_start, *committer_start; | ||
| int i, parents = 0; | ||
| int64_t commit_time; | ||
|
|
||
| buffer += strlen("tree ") + GIT_OID_HEXSZ + 1; | ||
|
|
||
| parents_start = buffer; | ||
| while (buffer + parent_len < buffer_end && memcmp(buffer, "parent ", strlen("parent ")) == 0) { | ||
| parents++; | ||
| buffer += parent_len; | ||
| } | ||
|
|
||
| commit->parents = alloc_parents(walk, commit, parents); | ||
| GIT_ERROR_CHECK_ALLOC(commit->parents); | ||
|
|
||
| buffer = parents_start; | ||
| for (i = 0; i < parents; ++i) { | ||
| git_oid oid; | ||
|
|
||
| if (git_oid_fromstr(&oid, (const char *)buffer + strlen("parent ")) < 0) | ||
| return -1; | ||
| git_oid *parent_oid; | ||
| git_commit *commit; | ||
| int error; | ||
| size_t i; | ||
|
|
||
| commit->parents[i] = git_revwalk__commit_lookup(walk, &oid); | ||
| if (commit->parents[i] == NULL) | ||
| return -1; | ||
| commit = git__calloc(1, sizeof(*commit)); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a few "I don't remember" commits related to that, as fixups in the actual shallow implementation, here and here. AFAIR, I was getting asserts/crashes in cache.c, until I made the initialization like this. But it's fuzzy now, and I think I wasn't able to extract a testcase for it anyways. Now that I'm thinking about it, maybe that's because the ODB memory semantics being weird 😆 ?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They are! That's why we've deprecated the |
||
| GIT_ERROR_CHECK_ALLOC(commit); | ||
| commit->object.repo = walk->repo; | ||
|
|
||
| buffer += parent_len; | ||
| if ((error = git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK)) < 0) { | ||
| git__free(commit); | ||
| return error; | ||
| } | ||
|
|
||
| commit->out_degree = (unsigned short)parents; | ||
|
|
||
| if ((committer_start = buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) | ||
| return commit_error(commit, "object is corrupted"); | ||
|
|
||
| buffer++; | ||
|
|
||
| if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) | ||
| return commit_error(commit, "object is corrupted"); | ||
|
|
||
| /* Skip trailing spaces */ | ||
| while (buffer > committer_start && git__isspace(*buffer)) | ||
| buffer--; | ||
|
|
||
| /* Seek for the beginning of the pack of digits */ | ||
| while (buffer > committer_start && git__isdigit(*buffer)) | ||
| buffer--; | ||
|
|
||
| /* Skip potential timezone offset */ | ||
| if ((buffer > committer_start) && (*buffer == '+' || *buffer == '-')) { | ||
| buffer--; | ||
| if (!git__is_uint16(git_array_size(commit->parent_ids))) { | ||
| git__free(commit); | ||
| git_error_set(GIT_ERROR_INVALID, "commit has more than 2^16 parents"); | ||
| return -1; | ||
| } | ||
|
|
||
| while (buffer > committer_start && git__isspace(*buffer)) | ||
| buffer--; | ||
| node->time = commit->committer->when.time; | ||
| node->out_degree = (uint16_t) git_array_size(commit->parent_ids); | ||
| node->parents = alloc_parents(walk, node, node->out_degree); | ||
| GIT_ERROR_CHECK_ALLOC(node->parents); | ||
|
|
||
| while (buffer > committer_start && git__isdigit(*buffer)) | ||
| buffer--; | ||
| git_array_foreach(commit->parent_ids, i, parent_oid) { | ||
| node->parents[i] = git_revwalk__commit_lookup(walk, parent_oid); | ||
| } | ||
|
|
||
| if ((buffer == committer_start) || | ||
| (git__strntol64(&commit_time, (char *)(buffer + 1), | ||
| buffer_end - buffer + 1, NULL, 10) < 0)) | ||
| return commit_error(commit, "cannot parse commit time"); | ||
| git_commit__free(commit); | ||
|
|
||
| node->parsed = 1; | ||
|
|
||
| commit->time = commit_time; | ||
| commit->parsed = 1; | ||
| return 0; | ||
| } | ||
|
|
||
|
|
@@ -196,10 +151,7 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) | |
| git_error_set(GIT_ERROR_INVALID, "object is no commit object"); | ||
| error = -1; | ||
| } else | ||
| error = commit_quick_parse( | ||
| walk, commit, | ||
| (const uint8_t *)git_odb_object_data(obj), | ||
| git_odb_object_size(obj)); | ||
| error = commit_quick_parse(walk, commit, obj); | ||
|
|
||
| git_odb_object_free(obj); | ||
| return error; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the commits are out of order. You first use the new generic mechanism and introduce it only in the next commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I caused some historic wreckage when doing some rebases, so when date-sorting, the commits are reverted. I already tried to fix it but failed, so I think I'll end up extracting patches and reapplying manually.