Commit ec25391dbb5ee6800b48362deadd73599701224f

Vicent Marti 2010-10-07T00:20:08

Add write-back support for Tag files Tag files can now be created and modified in-memory (all the setter methods have been implemented), and written back to disk using the generic git_object_write() method. Signed-off-by: Vicent Marti <tanoku@gmail.com>

diff --git a/src/commit.h b/src/commit.h
index 8039930..39a7a52 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -32,12 +32,13 @@ void git_commit__free(git_commit *c);
 int git_commit__parse(git_commit *commit);
 int git_commit__parse_full(git_commit *commit);
 int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags);
-void git_commit__mark_uninteresting(git_commit *commit);
 
 int git_commit__writeback(git_commit *commit, git_odb_source *src);
 
 int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
 int git__parse_person(git_person *person, char **buffer_out, const char *buffer_end, const char *header);
 
+int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid);
+int git__write_person(git_odb_source *src, const char *header, const git_person *person);
 
 #endif
diff --git a/src/git/tag.h b/src/git/tag.h
index 33e3d6f..aa23212 100644
--- a/src/git/tag.h
+++ b/src/git/tag.h
@@ -83,6 +83,34 @@ GIT_EXTERN(const git_person *) git_tag_tagger(git_tag *t);
  */
 GIT_EXTERN(const char *) git_tag_message(git_tag *t);
 
+/**
+ * Set the target of a tag (i.e. the object that the tag points to)
+ * @param tag The tag to modify
+ * @param target the new tagged target
+ */
+GIT_EXTERN(void) git_tag_set_target(git_tag *tag, git_object *target);
+
+/**
+ * Set the name of a tag 
+ * @param tag The tag to modify
+ * @param name the new name for the tag 
+ */
+GIT_EXTERN(void) git_tag_set_name(git_tag *tag, const char *name);
+
+/**
+ * Set the tagger of a tag 
+ * @param tag The tag to modify
+ * @param tagger the new tagger for the tag 
+ */
+GIT_EXTERN(void) git_tag_set_tagger(git_tag *tag, const git_person *tagger);
+
+/**
+ * Set the message of a tag 
+ * @param tag The tag to modify
+ * @param message the new tagger for the tag 
+ */
+GIT_EXTERN(void) git_tag_set_message(git_tag *tag, const char *message);
+
 /** @} */
 GIT_END_DECL
 #endif
diff --git a/src/repository.c b/src/repository.c
index 22f2bba..19f1c4e 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -274,6 +274,9 @@ int git_object_write(git_object *object)
 		break;
 
 	case GIT_OBJ_TAG:
+		error = git_tag__writeback((git_tag *)object, source);
+		break;
+
 	default:
 		error = GIT_ERROR;
 		break;
diff --git a/src/tag.c b/src/tag.c
index 734556b..4a79fbd 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -53,26 +53,79 @@ const git_object *git_tag_target(git_tag *t)
 	return t->target;
 }
 
+void git_tag_set_target(git_tag *tag, git_object *target)
+{
+	assert(tag && target);
+
+	tag->object.modified = 1;
+	tag->target = target;
+	tag->type = git_object_type(target);
+}
+
 git_otype git_tag_type(git_tag *t)
 {
 	return t->type;
 }
 
+void git_tag_set_type(git_tag *tag, git_otype type)
+{
+	assert(tag);
+
+	tag->object.modified = 1;
+	tag->type = type;
+}
+
 const char *git_tag_name(git_tag *t)
 {
 	return t->tag_name;
 }
 
+void git_tag_set_name(git_tag *tag, const char *name)
+{
+	assert(tag && name);
+
+	/* TODO: sanity check? no newlines in message */
+	tag->object.modified = 1;
+
+	if (tag->tag_name)
+		free(tag->tag_name);
+
+	tag->tag_name = git__strdup(name);
+}
+
 const git_person *git_tag_tagger(git_tag *t)
 {
 	return t->tagger;
 }
 
+void git_tag_set_tagger(git_tag *tag, const git_person *tagger)
+{
+	assert(tag && tagger);
+
+	tag->object.modified = 1;
+	if (tag->tagger == NULL)
+		tag->tagger = git__malloc(sizeof(git_person));
+
+	memcpy(tag->tagger, tagger, sizeof(git_person));
+}
+
 const char *git_tag_message(git_tag *t)
 {
 	return t->message;
 }
 
+void git_tag_set_message(git_tag *tag, const char *message)
+{
+	assert(tag && message);
+
+	tag->object.modified = 1;
+
+	if (tag->message)
+		free(tag->message);
+
+	tag->message = git__strdup(message);
+}
+
 static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
 {
 	static const char *tag_types[] = {
@@ -115,10 +168,8 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
 	tag->target = 
 		git_repository_lookup(tag->object.repo, &target_oid, tag->type);
 
-	/* FIXME: is the tag file really corrupted if the tagged object
-	 * cannot be found on the database? */
-	/* if (tag->target == NULL)
-		return GIT_EOBJCORRUPTED; */
+	if (tag->target == NULL)
+		return GIT_EOBJCORRUPTED;
 
 	if (buffer + 4 >= buffer_end)
 		return GIT_EOBJCORRUPTED;
@@ -150,7 +201,7 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
 	if (git__parse_person(tag->tagger, &buffer, buffer_end, "tagger ") != 0)
 		return GIT_EOBJCORRUPTED;
 
-	text_len = buffer_end - buffer;
+	text_len = buffer_end - ++buffer;
 
 	if (tag->message != NULL)
 		free(tag->message);
@@ -162,6 +213,23 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
 	return 0;
 }
 
+int git_tag__writeback(git_tag *tag, git_odb_source *src)
+{
+	if (tag->target == NULL || tag->tag_name == NULL || tag->tagger == NULL)
+		return GIT_ERROR;
+
+	git__write_oid(src, "object", git_object_id(tag->target));
+	git__source_printf(src, "type %s\n", git_obj_type_to_string(tag->type));
+	git__source_printf(src, "tag %s\n", tag->tag_name);
+	git__write_person(src, "tagger", tag->tagger);
+
+	if (tag->message != NULL)
+		git__source_printf(src, "\n%s", tag->message);
+
+	return GIT_SUCCESS;
+}
+
+
 int git_tag__parse(git_tag *tag)
 {
 	int error = 0;
diff --git a/src/tag.h b/src/tag.h
index 6d9cd82..fbf5208 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -16,5 +16,6 @@ struct git_tag {
 
 void git_tag__free(git_tag *tag);
 int git_tag__parse(git_tag *tag);
+int git_tag__writeback(git_tag *tag, git_odb_source *src);
 
 #endif