Add basic functionality for commit lookup/parsing The external API function "git_commit_parse" has been renamed to "git_commit_lookup" and has been partially implemented with support for loading commits straight from the ODB. It still lacks the functionality to lookup cached commits in the revpool and to resolve tags to commits. The following internal functions have been partially implemented: int git_commit__parse_buffer(...); int git_commit__parse_time(...); int git_commit__parse_oid(...); Commits are now fully parsed but the generated parent and tree references are not handled yet. Signed-off-by: Vicent Marti <tanoku@gmail.com> Signed-off-by: Andreas Ericsson <ae@op5.se>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
diff --git a/src/commit.c b/src/commit.c
index 710a14e..e589dde 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -23,10 +23,128 @@
* Boston, MA 02110-1301, USA.
*/
+#include <time.h>
+
#include "common.h"
#include "commit.h"
+#include "revwalk.h"
+#include "git/odb.h"
const git_oid *git_commit_id(git_commit *c)
{
return &c->id;
}
+
+git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id)
+{
+ git_obj commit_obj;
+ git_commit *commit = NULL;
+
+ /*
+ * TODO: check if the commit is already cached in the
+ * revpool instead of loading it from the odb
+ */
+
+ if (git_odb_read(&commit_obj, pool->db, id) < 0)
+ return NULL;
+
+ if (commit_obj.type != GIT_OBJ_COMMIT)
+ goto error_cleanup;
+
+ commit = git__malloc(sizeof(git_commit));
+ memset(commit, 0x0, sizeof(git_commit));
+
+ git_oid_cpy(&commit->id, id);
+ commit->pool = pool;
+
+ if (git_commit__parse_buffer(commit, commit_obj.data, commit_obj.len) < 0)
+ goto error_cleanup;
+
+ return commit;
+
+error_cleanup:
+ git_obj_close(&commit_obj);
+ free(commit);
+
+ return NULL;
+}
+
+int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end)
+{
+ if (memcmp(buffer, "author ", 7) != 0)
+ return -1;
+
+ buffer = memchr(buffer, '\n', buffer_end - buffer);
+ if (buffer == 0 || buffer >= buffer_end)
+ return -1;
+
+ if (memcmp(buffer, "committer ", 10) != 0)
+ return -1;
+
+ buffer = memchr(buffer, '\n', buffer_end - buffer);
+ if (buffer == 0 || buffer >= buffer_end)
+ return -1;
+
+ *commit_time = strtol(buffer, &buffer, 10);
+
+ return (buffer < buffer_end) ? 0 : -1;
+}
+
+int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header)
+{
+ size_t sha_len = GIT_OID_HEXSZ;
+ size_t header_len = strlen(header);
+
+ char *buffer = *buffer_out;
+
+ if (buffer + (header_len + sha_len + 1) > buffer_end)
+ return -1;
+
+ if (memcmp(buffer, header, header_len) != 0)
+ return -1;
+
+ if (buffer[header_len + sha_len] != '\n')
+ return -1;
+
+ if (git_oid_mkstr(oid, buffer + header_len) < 0)
+ return -1;
+
+ *buffer_out = buffer + (header_len + sha_len + 1);
+
+ return 0;
+}
+
+int git_commit__parse_buffer(git_commit *commit, void *data, size_t len)
+{
+ char *buffer = (char *)data;
+ const char *buffer_end = (char *)data + len;
+
+ git_oid oid;
+
+ if (commit->parsed)
+ return 0;
+
+ if (git_commit__parse_oid(&oid, &buffer, buffer_end, "tree ") < 0)
+ return -1;
+
+ /*
+ * TODO: load tree into commit object
+ * TODO: commit grafts!
+ */
+
+ while (git_commit__parse_oid(&oid, &buffer, buffer_end, "parent ") == 0) {
+ git_commit *parent;
+
+ if ((parent = git_commit_lookup(commit->pool, &oid)) == NULL)
+ return -1;
+
+ // TODO: push the new commit into the revpool
+ }
+
+ if (git_commit__parse_time(&commit->commit_time, buffer, buffer_end) < 0)
+ return -1;
+
+ commit->parsed = 1;
+
+ return 0;
+}
diff --git a/src/commit.h b/src/commit.h
index 05504cd..1cdb9a4 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -5,11 +5,20 @@
#include <time.h>
+#define GIT_COMMIT_SEEN (1 << 0)
+#define GIT_COMMIT_HIDE (1 << 1)
+#define GIT_COMMIT_DELAY (1 << 2)
+
struct git_commit {
git_oid id;
time_t commit_time;
+ git_revpool *pool;
unsigned parsed:1,
flags:26;
};
+int git_commit__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
+int git_commit__parse_buffer(git_commit *commit, void *data, size_t len);
+int git_commit__parse_time(time_t *commit_time, char *buffer, const char *buffer_end);
+
#endif
diff --git a/src/git/commit.h b/src/git/commit.h
index 010f258..ea59a21 100644
--- a/src/git/commit.h
+++ b/src/git/commit.h
@@ -17,7 +17,7 @@ GIT_BEGIN_DECL
typedef struct git_commit git_commit;
/**
- * Parse (or lookup) a commit from a revision pool.
+ * Lookup a commit from a revision pool, and parse it if needed.
* @param pool the pool to use when parsing/caching the commit.
* @param id identity of the commit to locate. If the object is
* an annotated tag it will be peeled back to the commit.
@@ -25,7 +25,7 @@ typedef struct git_commit git_commit;
* pool's git_odb, or if the commit is present but is
* too malformed to be parsed successfully.
*/
-GIT_EXTERN(git_commit *) git_commit_parse(git_revpool *pool, const git_oid *id);
+GIT_EXTERN(git_commit *) git_commit_lookup(git_revpool *pool, const git_oid *id);
/**
* Get the id of a commit.