Merge pull request #671 from nulltoken/topic/blob_create_fromdisk Add git_blob_create_fromdisk()
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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
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));
+}