Commit e49cb1687e7400aeccac161a1b080fdc23897522

Vicent Martí 2012-05-14T11:03:30

Merge pull request #671 from nulltoken/topic/blob_create_fromdisk Add git_blob_create_fromdisk()

diff --git a/include/git2/blob.h b/include/git2/blob.h
index 44b29d7..afa350b 100644
--- a/include/git2/blob.h
+++ b/include/git2/blob.h
@@ -103,6 +103,18 @@ GIT_EXTERN(size_t) git_blob_rawsize(git_blob *blob);
  */
 GIT_EXTERN(int) git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path);
 
+/**
+ * Read a file from the filesystem and write its content
+ * to the Object Database as a loose blob
+ *
+ * @param oid return the id of the written blob
+ * @param repo repository where the blob will be written.
+ *	this repository can be bare or not
+ * @param path file from which the blob will be created
+ * @return GIT_SUCCESS or an error code
+ */
+GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path);
+
 
 /**
  * Write an in-memory buffer to the ODB as a blob
diff --git a/src/blob.c b/src/blob.c
index 36571c7..e25944b 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -148,30 +148,20 @@ static int write_symlink(
 	return error;
 }
 
-int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
+static int blob_create_internal(git_oid *oid, git_repository *repo, const char *path)
 {
 	int error;
-	git_buf full_path = GIT_BUF_INIT;
-	git_off_t size;
 	struct stat st;
-	const char *workdir;
 	git_odb *odb = NULL;
+	git_off_t size;
 
-	workdir = git_repository_workdir(repo);
-	assert(workdir); /* error to call this on bare repo */
-
-	if ((error = git_buf_joinpath(&full_path, workdir, path)) < 0 ||
-		(error = git_path_lstat(full_path.ptr, &st)) < 0 ||
-		(error = git_repository_odb__weakptr(&odb, repo)) < 0)
-	{
-		git_buf_free(&full_path);
+	if ((error = git_path_lstat(path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0)
 		return error;
-	}
 
 	size = st.st_size;
 
 	if (S_ISLNK(st.st_mode)) {
-		error = write_symlink(oid, odb, full_path.ptr, (size_t)size);
+		error = write_symlink(oid, odb, path, (size_t)size);
 	} else {
 		git_vector write_filters = GIT_VECTOR_INIT;
 		int filter_count;
@@ -186,10 +176,10 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
 		} else if (filter_count == 0) {
 			/* No filters need to be applied to the document: we can stream
 			 * directly from disk */
-			error = write_file_stream(oid, odb, full_path.ptr, size);
+			error = write_file_stream(oid, odb, path, size);
 		} else {
 			/* We need to apply one or more filters */
-			error = write_file_filtered(oid, odb, full_path.ptr, &write_filters);
+			error = write_file_filtered(oid, odb, path, &write_filters);
 		}
 
 		git_filters_free(&write_filters);
@@ -209,7 +199,41 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
 		 */
 	}
 
+	return error;
+}
+
+int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
+{
+	git_buf full_path = GIT_BUF_INIT;
+	const char *workdir;
+	int error;
+
+	workdir = git_repository_workdir(repo);
+	assert(workdir); /* error to call this on bare repo */
+
+	if (git_buf_joinpath(&full_path, workdir, path) < 0) {
+		git_buf_free(&full_path);
+		return -1;
+	}
+
+	error = blob_create_internal(oid, repo, git_buf_cstr(&full_path));
+
 	git_buf_free(&full_path);
 	return error;
 }
 
+int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path)
+{
+	int error;
+	git_buf full_path = GIT_BUF_INIT;
+
+	if ((error = git_path_prettify(&full_path, path, NULL)) < 0) {
+		git_buf_free(&full_path);
+		return error;
+	}
+
+	error = blob_create_internal(oid, repo, git_buf_cstr(&full_path));
+
+	git_buf_free(&full_path);
+	return error;
+}
diff --git a/tests-clar/object/blob/write.c b/tests-clar/object/blob/write.c
new file mode 100644
index 0000000..722c7b9
--- /dev/null
+++ b/tests-clar/object/blob/write.c
@@ -0,0 +1,69 @@
+#include "clar_libgit2.h"
+#include "buffer.h"
+#include "posix.h"
+#include "path.h"
+#include "fileops.h"
+
+static git_repository *repo;
+
+#define WORKDIR "empty_standard_repo"
+#define BARE_REPO "testrepo.git"
+#define ELSEWHERE "elsewhere"
+
+typedef int (*blob_creator_fn)(
+	git_oid *,
+	git_repository *,
+	const char *);
+
+void test_object_blob_write__cleanup(void)
+{
+	cl_git_sandbox_cleanup();
+}
+
+static void assert_blob_creation(const char *path_to_file, const char *blob_from_path, blob_creator_fn creator)
+{
+	git_oid oid;
+	cl_git_mkfile(path_to_file, "1..2...3... Can you hear me?\n");
+
+	cl_must_pass(creator(&oid, repo, blob_from_path));
+	cl_assert(git_oid_streq(&oid, "da5e4f20c91c81b44a7e298f3d3fb3fe2f178e32") == 0);
+}
+
+void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_file_located_in_the_working_directory(void)
+{
+	repo = cl_git_sandbox_init(WORKDIR);
+
+	assert_blob_creation(WORKDIR "/test.txt", "test.txt", &git_blob_create_fromfile);
+}
+
+void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolute_filepath_pointing_outside_of_the_working_directory(void)
+{
+	git_buf full_path = GIT_BUF_INIT;
+
+	repo = cl_git_sandbox_init(WORKDIR);
+
+	cl_must_pass(p_mkdir(ELSEWHERE, 0777));
+	cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL));
+	cl_must_pass(git_buf_puts(&full_path, "test.txt"));
+
+	assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
+
+	git_buf_free(&full_path);
+	cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS));
+}
+
+void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_filepath(void)
+{
+	git_buf full_path = GIT_BUF_INIT;
+
+	repo = cl_git_sandbox_init(BARE_REPO);
+
+	cl_must_pass(p_mkdir(ELSEWHERE, 0777));
+	cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL));
+	cl_must_pass(git_buf_puts(&full_path, "test.txt"));
+
+	assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
+
+	git_buf_free(&full_path);
+	cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS));
+}