Merge pull request #216 from glesserd/development git_tag_create{,_o,_frombuffer} correction and improvement
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
diff --git a/include/git2/tag.h b/include/git2/tag.h
index 3f82ce4..49836a1 100644
--- a/include/git2/tag.h
+++ b/include/git2/tag.h
@@ -152,7 +152,9 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *t);
* Create a new tag in the repository from an OID
*
* @param oid Pointer where to store the OID of the
- * newly created tag
+ * newly created tag. If the tag already exists, this parameter
+ * will be the oid of the existed tag, and the function will
+ * return a GIT_EEXISTS error code.
*
* @param repo Repository where to store the tag
*
diff --git a/src/tag.c b/src/tag.c
index 905d129..10ed9c0 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -180,6 +180,46 @@ static int retreive_tag_reference(git_reference **tag_reference_out, char *ref_n
return GIT_SUCCESS;
}
+/* tag_reference_out will contain the reference of the tag if exists, otherwise NULL */
+static int tag_valid_in_odb(
+ git_reference **tag_reference_out,
+ char *ref_name_out,
+ const git_oid *target,
+ git_otype target_type,
+ git_repository *repo,
+ const char *tag_name) {
+
+ int error;
+
+ *tag_reference_out = NULL;
+
+
+ error = retreive_tag_reference(tag_reference_out, ref_name_out, repo, tag_name);
+
+ switch (error) {
+ case GIT_SUCCESS:
+ /* Fall trough */
+ case GIT_ENOTFOUND:
+ break;
+
+ default:
+ return git__rethrow(error, "Failed to create tag");
+ }
+
+ if (!git_odb_exists(repo->db, target))
+ return git__throw(GIT_ENOTFOUND, "Failed to create tag. Object to tag doesn't exist");
+
+ /* Try to find out what the type is */
+ if (target_type == GIT_OBJ_ANY) {
+ size_t _unused;
+ error = git_odb_read_header(&_unused, &target_type, repo->db, target);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to create tag");
+ }
+
+ return GIT_SUCCESS;
+}
+
static int tag_create(
git_oid *oid,
git_repository *repo,
@@ -202,34 +242,18 @@ static int tag_create(
int type_str_len, tag_name_len, tagger_str_len, message_len;
int error, should_update_ref = 0;
+ if ((error = tag_valid_in_odb(&new_ref, ref_name, target, target_type, repo, tag_name)) < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to create tag");
+
/** Ensure the tag name doesn't conflict with an already existing
- reference unless overwriting has explictly been requested **/
- error = retreive_tag_reference(&new_ref, ref_name, repo, tag_name);
-
- switch (error) {
- case GIT_SUCCESS:
- if (!allow_ref_overwrite)
- return GIT_EEXISTS;
- should_update_ref = 1;
-
- /* Fall trough */
-
- case GIT_ENOTFOUND:
- break;
-
- default:
- return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
- }
-
- if (!git_odb_exists(repo->db, target))
- return git__throw(GIT_ENOTFOUND, "Failed to create tag. Object to tag doesn't exist");
-
- /* Try to find out what the type is */
- if (target_type == GIT_OBJ_ANY) {
- size_t _unused;
- error = git_odb_read_header(&_unused, &target_type, repo->db, target);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to create tag");
+ * reference unless overwriting has explictly been requested **/
+ if(new_ref != NULL) {
+ if(!allow_ref_overwrite) {
+ git_oid_cpy(oid, git_reference_oid(new_ref));
+ return git__throw(GIT_EEXISTS, "Tag already exists");
+ } else {
+ should_update_ref = 1;
+ }
}
type_str = git_object_type2string(target_type);
@@ -283,20 +307,49 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
{
git_tag tag;
int error;
-
+ git_odb_stream *stream;
+
+ git_reference *new_ref;
+ char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH];
+
assert(oid && buffer);
-
+
memset(&tag, 0, sizeof(tag));
-
+
+ /* validate the buffer */
+
if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
-
- error = git_tag_create(oid, repo, tag.tag_name, &tag.target, tag.type, tag.tagger, tag.message);
-
+
+ if ((error = tag_valid_in_odb(&new_ref, ref_name, &tag.target, tag.type, repo, tag.tag_name)) < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to create tag");
+
+ if(new_ref != NULL) {
+ git_oid_cpy(oid, git_reference_oid(new_ref));
+ return git__throw(GIT_EEXISTS, "Tag already exists");
+ }
+
+
+ /* write the buffer */
+
+ if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to create tag");
+
+ stream->write(stream, buffer, strlen(buffer));
+
+ error = stream->finalize_write(oid, stream);
+ stream->free(stream);
+
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to create tag");
+
+
+ error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
+
git_signature_free(tag.tagger);
free(tag.tag_name);
free(tag.message);
-
+
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
}