diff options
Diffstat (limited to 'src/commit.c')
| -rw-r--r-- | src/commit.c | 391 |
1 files changed, 187 insertions, 204 deletions
diff --git a/src/commit.c b/src/commit.c index 974999a4a..03b111da5 100644 --- a/src/commit.c +++ b/src/commit.c @@ -29,10 +29,12 @@ #include "git2/signature.h" #include "common.h" +#include "odb.h" #include "commit.h" -#include "revwalk.h" #include "signature.h" +#include <stdarg.h> + #define COMMIT_BASIC_PARSE 0x0 #define COMMIT_FULL_PARSE 0x1 @@ -46,24 +48,22 @@ static void clear_parents(git_commit *commit) { unsigned int i; - for (i = 0; i < commit->parents.length; ++i) { - git_commit *parent = git_vector_get(&commit->parents, i); - GIT_OBJECT_DECREF(commit->object.repo, parent); + for (i = 0; i < commit->parent_oids.length; ++i) { + git_oid *parent = git_vector_get(&commit->parent_oids, i); + free(parent); } - git_vector_clear(&commit->parents); + git_vector_clear(&commit->parent_oids); } void git_commit__free(git_commit *commit) { clear_parents(commit); - git_vector_free(&commit->parents); + git_vector_free(&commit->parent_oids); git_signature_free(commit->author); git_signature_free(commit->committer); - GIT_OBJECT_DECREF(commit->object.repo, commit->tree); - free(commit->message); free(commit->message_short); free(commit); @@ -74,100 +74,199 @@ const git_oid *git_commit_id(git_commit *c) return git_object_id((git_object *)c); } -int git_commit__writeback(git_commit *commit, git_odb_source *src) + +int git_commit_create_v( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message, + const git_oid *tree_oid, + int parent_count, + ...) { - unsigned int i; + va_list ap; + int i, error; + const git_oid **oids; - if (commit->tree == NULL) - return GIT_EMISSINGOBJDATA; + oids = git__malloc(parent_count * sizeof(git_oid *)); - git__write_oid(src, "tree", git_tree_id(commit->tree)); + va_start(ap, parent_count); + for (i = 0; i < parent_count; ++i) + oids[i] = va_arg(ap, const git_oid *); + va_end(ap); - for (i = 0; i < commit->parents.length; ++i) { - git_commit *parent; + error = git_commit_create( + oid, repo, update_ref, author, committer, message, + tree_oid, parent_count, oids); - parent = git_vector_get(&commit->parents, i); - git__write_oid(src, "parent", git_commit_id(parent)); - } + free((void *)oids); + return error; +} - if (commit->author == NULL) - return GIT_EMISSINGOBJDATA; +int git_commit_create_ov( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message, + const git_tree *tree, + int parent_count, + ...) +{ + va_list ap; + int i, error; + const git_oid **oids; - git_signature__write(src, "author", commit->author); + oids = git__malloc(parent_count * sizeof(git_oid *)); - if (commit->committer == NULL) - return GIT_EMISSINGOBJDATA; + va_start(ap, parent_count); + for (i = 0; i < parent_count; ++i) + oids[i] = git_object_id(va_arg(ap, const git_object *)); + va_end(ap); - git_signature__write(src, "committer", commit->committer); + error = git_commit_create( + oid, repo, update_ref, author, committer, message, + git_object_id((git_object *)tree), + parent_count, oids); - if (commit->message != NULL) { - git__source_write(src, "\n", 1); - git__source_write(src, commit->message, strlen(commit->message)); - } + free((void *)oids); + return error; +} - /* Mark the commit as having all attributes */ - commit->full_parse = 1; +int git_commit_create_o( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]) +{ + int i, error; + const git_oid **oids; - return GIT_SUCCESS; + oids = git__malloc(parent_count * sizeof(git_oid *)); + + for (i = 0; i < parent_count; ++i) + oids[i] = git_object_id((git_object *)parents[i]); + + error = git_commit_create( + oid, repo, update_ref, author, committer, message, + git_object_id((git_object *)tree), + parent_count, oids); + + free((void *)oids); + return error; } -int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) +int git_commit_create( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message, + const git_oid *tree_oid, + int parent_count, + const git_oid *parents[]) { - char *buffer = (char *)data; - const char *buffer_end = (char *)data + len; + size_t final_size = 0; + int message_length, author_length, committer_length; - git_oid oid; - int error; + char *author_str, *committer_str; - /* first parse; the vector hasn't been initialized yet */ - if (commit->parents.contents == NULL) { - git_vector_init(&commit->parents, 4, NULL); - } + int error, i; + git_odb_stream *stream; - clear_parents(commit); + message_length = strlen(message); + author_length = git_signature__write(&author_str, "author", author); + committer_length = git_signature__write(&committer_str, "committer", committer); + if (author_length < 0 || committer_length < 0) + return GIT_ENOMEM; - if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) - return error; + final_size += GIT_OID_LINE_LENGTH("tree"); + final_size += GIT_OID_LINE_LENGTH("parent") * parent_count; + final_size += author_length; + final_size += committer_length; + final_size += 1 + message_length; - GIT_OBJECT_DECREF(commit->object.repo, commit->tree); - if ((error = git_object_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS) + if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_COMMIT)) < GIT_SUCCESS) return error; - /* - * TODO: commit grafts! - */ + git__write_oid(stream, "tree", tree_oid); + + for (i = 0; i < parent_count; ++i) + git__write_oid(stream, "parent", parents[i]); + + stream->write(stream, author_str, author_length); + free(author_str); + + stream->write(stream, committer_str, committer_length); + free(committer_str); - while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { - git_commit *parent; - if ((error = git_object_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS) + stream->write(stream, "\n", 1); + stream->write(stream, message, message_length); + + error = stream->finalize_write(oid, stream); + stream->free(stream); + + if (error == GIT_SUCCESS && update_ref != NULL) { + git_reference *head; + + error = git_reference_lookup(&head, repo, update_ref); + if (error < GIT_SUCCESS) return error; - if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS) - return GIT_ENOMEM; + if (git_reference_type(head) == GIT_REF_SYMBOLIC) { + if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS) + return error; + } + + error = git_reference_set_oid(head, oid); } + return error; +} - if (parse_flags & COMMIT_FULL_PARSE) { - if (commit->author) - git_signature_free(commit->author); +int commit_parse_buffer(git_commit *commit, void *data, size_t len) +{ + char *buffer = (char *)data; + const char *buffer_end = (char *)data + len; - commit->author = git__malloc(sizeof(git_signature)); - if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS) - return error; + git_oid parent_oid; + int error; - } else { - if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) - return GIT_EOBJCORRUPTED; + git_vector_init(&commit->parent_oids, 4, NULL); - buffer++; + if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) + return error; + + /* + * TODO: commit grafts! + */ + + while (git__parse_oid(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { + git_oid *new_oid; + + new_oid = git__malloc(sizeof(git_oid)); + git_oid_cpy(new_oid, &parent_oid); + + if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS) + return GIT_ENOMEM; } - /* Always parse the committer; we need the commit time */ - if (commit->committer) - git_signature_free(commit->committer); + commit->author = git__malloc(sizeof(git_signature)); + if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS) + return error; + /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS) return error; @@ -176,7 +275,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int while (buffer <= buffer_end && *buffer == '\n') buffer++; - if (parse_flags & COMMIT_FULL_PARSE && buffer < buffer_end) { + if (buffer < buffer_end) { const char *line_end; size_t message_len = buffer_end - buffer; @@ -199,160 +298,44 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int return GIT_SUCCESS; } -int git_commit__parse(git_commit *commit) +int git_commit__parse(git_commit *commit, git_odb_object *obj) { - assert(commit && commit->object.source.open); - return commit_parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_BASIC_PARSE); -} - -int git_commit__parse_full(git_commit *commit) -{ - int error; - - if (commit->full_parse) - return GIT_SUCCESS; - - if ((error = git_object__source_open((git_object *)commit)) < GIT_SUCCESS) - return error; - - error = commit_parse_buffer(commit, - commit->object.source.raw.data, commit->object.source.raw.len, COMMIT_FULL_PARSE); - - git_object__source_close((git_object *)commit); - - commit->full_parse = 1; - return error; + assert(commit); + return commit_parse_buffer(commit, obj->raw.data, obj->raw.len); } - - -#define GIT_COMMIT_GETTER(_rvalue, _name) \ - const _rvalue git_commit_##_name(git_commit *commit) \ +#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ + _rvalue git_commit_##_name(git_commit *commit) \ {\ assert(commit); \ - if (commit->_name) \ - return commit->_name; \ - if (!commit->object.in_memory) \ - git_commit__parse_full(commit); \ - return commit->_name; \ + return _return; \ } -#define CHECK_FULL_PARSE() \ - if (!commit->object.in_memory && !commit->full_parse)\ - git_commit__parse_full(commit); +GIT_COMMIT_GETTER(const git_signature *, author, commit->author) +GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer) +GIT_COMMIT_GETTER(const char *, message, commit->message) +GIT_COMMIT_GETTER(const char *, message_short, commit->message_short) +GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time) +GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) +GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length) -const git_tree *git_commit_tree(git_commit *commit) -{ - assert(commit); - if (!commit->object.in_memory && commit->tree == NULL) - git_commit__parse_full(commit); - - GIT_OBJECT_INCREF(commit->object.repo, commit->tree); - return commit->tree; -} - -GIT_COMMIT_GETTER(git_signature *, author) -GIT_COMMIT_GETTER(git_signature *, committer) -GIT_COMMIT_GETTER(char *, message) -GIT_COMMIT_GETTER(char *, message_short) - -time_t git_commit_time(git_commit *commit) -{ - assert(commit && commit->committer); - return commit->committer->when.time; -} - -int git_commit_time_offset(git_commit *commit) -{ - assert(commit && commit->committer); - return commit->committer->when.offset; -} - -unsigned int git_commit_parentcount(git_commit *commit) +int git_commit_tree(git_tree **tree_out, git_commit *commit) { assert(commit); - return commit->parents.length; + return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid); } -git_commit *git_commit_parent(git_commit *commit, unsigned int n) +int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) { - git_commit *parent; - + git_oid *parent_oid; assert(commit); - parent = git_vector_get(&commit->parents, n); - GIT_OBJECT_INCREF(commit->object.repo, parent); - return parent; -} - -void git_commit_set_tree(git_commit *commit, git_tree *tree) -{ - assert(commit && tree); - commit->object.modified = 1; - CHECK_FULL_PARSE(); - - GIT_OBJECT_DECREF(commit->object.repo, commit->tree); - GIT_OBJECT_INCREF(commit->object.repo, tree); - commit->tree = tree; -} - -void git_commit_set_author(git_commit *commit, const git_signature *author_sig) -{ - assert(commit && author_sig); - commit->object.modified = 1; - CHECK_FULL_PARSE(); - - git_signature_free(commit->author); - commit->author = git_signature_dup(author_sig); -} - -void git_commit_set_committer(git_commit *commit, const git_signature *committer_sig) -{ - assert(commit && committer_sig); - commit->object.modified = 1; - CHECK_FULL_PARSE(); - - git_signature_free(commit->committer); - commit->committer = git_signature_dup(committer_sig); -} - -void git_commit_set_message(git_commit *commit, const char *message) -{ - const char *line_end; - size_t message_len; - - commit->object.modified = 1; - CHECK_FULL_PARSE(); - - if (commit->message) - free(commit->message); - - if (commit->message_short) - free(commit->message_short); + parent_oid = git_vector_get(&commit->parent_oids, n); + if (parent_oid == NULL) + return GIT_ENOTFOUND; - commit->message = git__strdup(message); - - /* Short message */ - if((line_end = strchr(message, '\n')) == NULL) { - commit->message_short = git__strdup(message); - return; - } - - message_len = line_end - message; - - commit->message_short = git__malloc(message_len + 1); - memcpy(commit->message_short, message, message_len); - commit->message_short[message_len] = 0; + return git_commit_lookup(parent, commit->object.repo, parent_oid); } -int git_commit_add_parent(git_commit *commit, git_commit *new_parent) -{ - assert(commit && new_parent); - CHECK_FULL_PARSE(); - commit->object.modified = 1; - GIT_OBJECT_INCREF(commit->object.repo, new_parent); - return git_vector_insert(&commit->parents, new_parent); -} |
