Commit e3f56a2b571483e7cf70d324b61f0681bdda62b8

Vicent Martí 2011-06-08T08:11:26

Merge pull request #216 from glesserd/development git_tag_create{,_o,_frombuffer} correction and improvement

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");
 }