New external API method: `git_tree_create` Creates a tree by scanning the index file. The method handles recursive creation of trees for subdirectories and adds them to the parent tree.
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
diff --git a/include/git2/tree.h b/include/git2/tree.h
index 164aec9..bd1f970 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -138,6 +138,18 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry);
*/
GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry);
+/**
+ * Create tree by scanning the index file.
+ *
+ * @param object identity for the tree
+ * @param repository where to lookup for object db
+ * @param base directory path
+ * @param path length for base
+ * @param index entry offset to start scan
+ * @return number of items added to the tree
+ */
+GIT_EXTERN(int) git_tree_create(git_oid *oid, git_repository *repo, const char *base, int baselen, int entry_no);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/src/tree.c b/src/tree.c
index dea5046..299fc69 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -178,3 +178,90 @@ int git_tree__parse(git_tree *tree, git_odb_object *obj)
return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
}
+int git_tree_create(git_oid *oid, git_repository *repo, const char *base, int baselen, int entry_no)
+{
+ unsigned long size, offset;
+ char *buffer;
+ int nr, maxentries;
+ git_index *index;
+ git_odb_stream *stream;
+ int error;
+
+ git_index_open_inrepo(&index,repo);
+ maxentries = git_index_entrycount (index);
+
+ /* FIXME: A matching error code could not be found. Hence used a close error code GIT_EBAREINDEX */
+ if (maxentries <= 0) {
+ return GIT_EBAREINDEX;
+ }
+
+ /* Guess at some random initial size */
+ size = 8192;
+ buffer = git__malloc(size);
+ if (buffer == NULL)
+ return GIT_ENOMEM;
+
+ offset = 0;
+ nr = entry_no;
+
+ do {
+ git_index_entry *entry = git_index_get(index, nr);
+ const char *pathname = entry->path, *filename, *dirname;
+ int pathlen = strlen(pathname), entrylen;
+ git_oid *entry_oid;
+ unsigned int mode;
+ unsigned char *sha1;
+
+ /* Did we hit the end of the directory? Return how many we wrote */
+ if (baselen >= pathlen || memcmp(base, pathname, baselen))
+ break;
+
+ entry_oid = &entry->oid;
+ mode = entry->mode;
+ sha1 = entry_oid->id;
+
+ /* Do we have _further_ subdirectories? */
+ filename = pathname + baselen;
+ dirname = strchr(filename, '/');
+ if (dirname) {
+ int subdir_written;
+ subdir_written = git_tree_create(oid, repo, pathname, dirname-pathname+1, nr);
+
+ if (subdir_written == GIT_ENOMEM)
+ return GIT_ENOMEM;
+
+ nr += subdir_written;
+
+ /* Now we need to write out the directory entry into this tree.. */
+ mode = S_IFDIR;
+ pathlen = dirname - pathname;
+
+ /* ..but the directory entry doesn't count towards the total count */
+ nr--;
+ sha1 = oid->id;
+ }
+
+ entrylen = pathlen - baselen;
+ if (offset + entrylen + 100 > size) {
+ size = alloc_nr(offset + entrylen + 100);
+ buffer = git__realloc(buffer, size);
+
+ if (buffer == NULL)
+ return GIT_ENOMEM;
+ }
+ offset += sprintf(buffer + offset, "%o %.*s", mode, entrylen, filename);
+ buffer[offset++] = 0;
+ memcpy(buffer + offset, sha1, GIT_OID_RAWSZ);
+ offset += GIT_OID_RAWSZ;
+ nr++;
+ } while (nr < maxentries);
+
+ if ((error = git_odb_open_wstream(&stream, repo->db, offset, GIT_OBJ_TREE)) < GIT_SUCCESS)
+ return error;
+
+ stream->write(stream, buffer, offset);
+ error = stream->finalize_write(oid, stream);
+ stream->free(stream);
+
+ return nr;
+}
diff --git a/src/util.h b/src/util.h
index 653b34d..f477b64 100644
--- a/src/util.h
+++ b/src/util.h
@@ -14,6 +14,7 @@
*/
#define git__malloc malloc
#define git__calloc calloc
+#define git__realloc realloc
#define git__strdup strdup
extern int git__fmt(char *, size_t, const char *, ...)