Commit a7a7ddbe0f097923feb9ed31502857891e02824f

Vicent Marti 2010-09-18T19:16:04

Add generic methods for object writeback git_repository_object has now several internal methods to write back the object information in the repository. - git_repository__dbo_prepare_write() Prepares the DBO object to be modified - git_repository__dbo_write() Writes new bytes to the DBO object - git_repository__dbo_writeback() Writes back the changes to the repository Signed-off-by: Vicent Marti <tanoku@gmail.com>

diff --git a/src/commit.c b/src/commit.c
index 8a3eb5f..ce3a418 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -69,14 +69,14 @@ int git_commit__parse(git_commit *commit, unsigned int parse_flags, int close_db
 {
 	int error = 0;
 
-	if ((error = git_repository__open_dbo((git_repository_object *)commit)) < 0)
+	if ((error = git_repository__dbo_open((git_repository_object *)commit)) < 0)
 		return error;
 
 	error = git_commit__parse_buffer(commit,
 			commit->object.dbo.data, commit->object.dbo.len, parse_flags);
 
 	if (close_db_object)
-		git_repository__close_dbo((git_repository_object *)commit);
+		git_repository__dbo_close((git_repository_object *)commit);
 
 	return error;
 }
diff --git a/src/repository.c b/src/repository.c
index 3f07bd6..4436971 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -91,10 +91,84 @@ void git_repository_free(git_repository *repo)
 	free(repo);
 }
 
-int git_repository__open_dbo(git_repository_object *object)
+void git_repository__dbo_prepare_write(git_repository_object *object)
+{
+	size_t base_size = 512;
+
+	if (object->writeback.write_ptr != NULL || object->dbo_open)
+		git_repository__dbo_close(object);
+
+	/* TODO: proper size calculation */
+	object->dbo.data = git__malloc(base_size);
+	object->dbo.len = 0;
+
+	object->writeback.write_ptr = object->dbo.data;
+	object->writeback.ptr_size = base_size;
+	object->writeback.written_bytes = 0;
+
+	object->dbo_open = 1;
+	object->out_of_sync = 1;
+}
+
+int git_repository__dbo_write(git_repository_object *object, const void *bytes, size_t len)
+{
+	assert(object);
+
+	if (!object->dbo_open || object->writeback.write_ptr == NULL)
+		return GIT_ERROR;
+
+	/* TODO: resize buffer on overflow */
+	if (object->writeback.written_bytes + len >= object->writeback.ptr_size)
+		return GIT_ENOMEM;
+
+	memcpy(object->writeback.write_ptr, bytes, len);
+	object->writeback.write_ptr += len;
+	object->writeback.written_bytes += len;
+
+	return GIT_SUCCESS;
+}
+
+int git_repository__dbo_writeback(git_repository_object *object)
+{
+	int error;
+	git_oid new_id;
+
+	assert(object);
+
+	if (!object->dbo_open)
+		return GIT_ERROR;
+
+	if (!object->out_of_sync)
+		return GIT_SUCCESS;
+	
+	object->dbo.len = object->writeback.written_bytes;
+
+	git_obj_hash(&new_id, &object->dbo);
+
+	if ((error = git_odb_write(&new_id, object->repo->db, &object->dbo)) < 0)
+		return error;
+
+	git_hashtable_remove(object->repo->objects, &object->id);
+	git_oid_cpy(&object->id, &new_id);
+	git_hashtable_insert(object->repo->objects, &object->id, object);
+
+	object->writeback.write_ptr = NULL;
+	object->writeback.ptr_size = 0;
+	object->writeback.written_bytes = 0;
+
+	git_repository__dbo_close(object);
+	return GIT_SUCCESS;
+}
+
+int git_repository__dbo_open(git_repository_object *object)
 {
 	int error;
 
+	assert(object);
+
+	if (object->dbo_open && object->out_of_sync)
+		git_repository__dbo_close(object);
+
 	if (object->dbo_open)
 		return GIT_SUCCESS;
 
@@ -103,19 +177,25 @@ int git_repository__open_dbo(git_repository_object *object)
 		return error;
 
 	object->dbo_open = 1;
+	object->out_of_sync = 0;
 	return GIT_SUCCESS;
 }
 
-void git_repository__close_dbo(git_repository_object *object)
+void git_repository__dbo_close(git_repository_object *object)
 {
+	assert(object);
+
 	if (!object->dbo_open) {
 		git_obj_close(&object->dbo);
 		object->dbo_open = 0;
+		object->out_of_sync = 0;
 	}
 }
 
 void git_repository_object_free(git_repository_object *object)
 {
+	assert(object);
+
 	git_hashtable_remove(object->repo->objects, &object->id);
 	git_obj_close(&object->dbo);
 
diff --git a/src/repository.h b/src/repository.h
index 712874c..1b5e6a0 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -12,7 +12,14 @@ struct git_repository_object {
 	git_oid id;
 	git_repository *repo;
 	git_obj dbo;
-	int dbo_open;
+
+	struct {
+		void *write_ptr;
+		size_t ptr_size;
+		size_t written_bytes;
+	} writeback;
+
+	int dbo_open:1, out_of_sync:1;
 };
 
 struct git_repository {
@@ -21,7 +28,10 @@ struct git_repository {
 };
 
 
-int git_repository__open_dbo(git_repository_object *object);
-void git_repository__close_dbo(git_repository_object *object);
+int git_repository__dbo_open(git_repository_object *object);
+void git_repository__dbo_close(git_repository_object *object);
+void git_repository__dbo_prepare_write(git_repository_object *object);
+int git_repository__dbo_write(git_repository_object *object, const void *bytes, size_t len);
+int git_repository__dbo_writeback(git_repository_object *object);
 
 #endif
diff --git a/src/tag.c b/src/tag.c
index 5d094ea..ec0531b 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -161,13 +161,13 @@ int git_tag__parse(git_tag *tag)
 {
 	int error = 0;
 
-	error = git_repository__open_dbo((git_repository_object *)tag);
+	error = git_repository__dbo_open((git_repository_object *)tag);
 	if (error < 0)
 		return error;
 
 	error = parse_tag_buffer(tag, tag->object.dbo.data, tag->object.dbo.data + tag->object.dbo.len);
 
-	git_repository__close_dbo((git_repository_object *)tag);
+	git_repository__dbo_close((git_repository_object *)tag);
 	return error;
 }
 
diff --git a/src/tree.c b/src/tree.c
index 6760654..7599c3f 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -107,7 +107,7 @@ int git_tree__parse(git_tree *tree)
 	if (tree->entries != NULL)
 		return GIT_SUCCESS;
 
-	error = git_repository__open_dbo((git_repository_object *)tree);
+	error = git_repository__dbo_open((git_repository_object *)tree);
 	if (error < 0)
 		return error;
 
@@ -155,6 +155,6 @@ int git_tree__parse(git_tree *tree)
 		buffer += GIT_OID_RAWSZ;
 	}
 
-	git_repository__close_dbo((git_repository_object *)tree);
+	git_repository__dbo_close((git_repository_object *)tree);
 	return error;
 }