Merge branch 'master' of https://github.com/jwiegley/libgit2
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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
diff --git a/src/commit.c b/src/commit.c
index c3fa382..49e2354 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -91,8 +91,10 @@ int git_commit__writeback(git_commit *commit, git_odb_source *src)
git_signature__write(src, "committer", commit->committer);
- if (commit->message != NULL)
- git__source_printf(src, "\n%s", commit->message);
+ if (commit->message != NULL) {
+ git__source_write(src, "\n", 1);
+ git__source_write(src, commit->message, strlen(commit->message));
+ }
/* Mark the commit as having all attributes */
commit->full_parse = 1;
diff --git a/src/git2/tree.h b/src/git2/tree.h
index 9ebb265..6f79ac4 100644
--- a/src/git2/tree.h
+++ b/src/git2/tree.h
@@ -149,6 +149,36 @@ GIT_EXTERN(int) git_tree_entry_2object(git_object **object, git_tree_entry *entr
GIT_EXTERN(int) git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes);
/**
+ * Add a new entry to a tree, returning that new entry.
+ * The only difference with this call is that it does not sort
+ * tree afterwards, this requirement is left to the caller.
+ *
+ * This will mark the tree as modified; the new entry will
+ * be written back to disk on the next git_object_write()
+ *
+ * @param entry Entry object which will be created
+ * @param tree Tree object to store the entry
+ * @iparam id OID for the tree entry
+ * @param filename Filename for the tree entry
+ * @param attributes UNIX file attributes for the entry
+ * @return 0 on success; otherwise error code
+ */
+GIT_EXTERN(int) git_tree_add_entry_unsorted(git_tree_entry **entry, git_tree *tree, const git_oid *id, const char *filename, int attributes);
+
+/**
+ * Sort the entries in a tree created using git_tree_add_entry2.
+ *
+ * This does not mark the tree as modified. It is intended to be used
+ * after several invocations of git_tree_add_entry2.
+ * git_tree_add_entry, on the other hand, sorts after each entry is
+ * added.
+ *
+ * @param tree Tree object whose entries are to be sorted
+ * @return 0 on success; otherwise error code
+ */
+GIT_EXTERN(int) git_tree_sort_entries(git_tree *tree);
+
+/**
* Remove an entry by its index.
*
* Index must be >= 0 and < than git_tree_entrycount().
@@ -175,6 +205,16 @@ GIT_EXTERN(int) git_tree_remove_entry_byindex(git_tree *tree, int idx);
GIT_EXTERN(int) git_tree_remove_entry_byname(git_tree *tree, const char *filename);
/**
+ * Clear all the entries in a tree.
+ *
+ * This will mark the tree as modified; the modified entry will
+ * be written back to disk on the next git_object_write().
+ *
+ * @param tree Tree object whose entries are to be sorted
+ */
+GIT_EXTERN(void) git_tree_clear_entries(git_tree *tree);
+
+/**
* Change the SHA1 id of a tree entry.
*
* This will mark the tree that contains the entry as modified;
diff --git a/src/object.c b/src/object.c
index 87e1b6e..dd84cb5 100644
--- a/src/object.c
+++ b/src/object.c
@@ -97,7 +97,7 @@ static int source_resize(git_odb_source *src)
int git__source_printf(git_odb_source *source, const char *format, ...)
{
va_list arglist;
- int len, did_resize = 0;
+ int len;
assert(source->open && source->write_ptr);
@@ -109,12 +109,9 @@ int git__source_printf(git_odb_source *source, const char *format, ...)
if (source_resize(source) < GIT_SUCCESS)
return GIT_ENOMEM;
- did_resize = 1;
+ len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
}
- if (did_resize)
- vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
-
source->write_ptr = (char *)source->write_ptr + len;
source->written_bytes += len;
diff --git a/src/tree.c b/src/tree.c
index dffe872..ab3bec8 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -40,15 +40,36 @@ int entry_search_cmp(const void *key, const void *array_member)
return strcmp(filename, entry->filename);
}
+static int cache_name_compare(const char *name1, int len1, int isdir1,
+ const char *name2, int len2, int isdir2)
+{
+ int len = len1 < len2 ? len1 : len2;
+ int cmp;
+
+ cmp = memcmp(name1, name2, len);
+ if (cmp)
+ return cmp;
+ if (len1 < len2)
+ return ((isdir1 == isdir2) ? -1 :
+ (isdir1 ? '/' - name2[len1] : name2[len1] - '/'));
+ if (len1 > len2)
+ return ((isdir1 == isdir2) ? 1 :
+ (isdir2 ? name1[len2] - '/' : '/' - name1[len2]));
+ return 0;
+}
+
int entry_sort_cmp(const void *a, const void *b)
{
const git_tree_entry *entry_a = *(const git_tree_entry **)(a);
const git_tree_entry *entry_b = *(const git_tree_entry **)(b);
- return strcmp(entry_a->filename, entry_b->filename);
+ return cache_name_compare(entry_a->filename, strlen(entry_a->filename),
+ entry_a->attr & 040000,
+ entry_b->filename, strlen(entry_b->filename),
+ entry_b->attr & 040000);
}
-static void clear_entries(git_tree *tree)
+void git_tree_clear_entries(git_tree *tree)
{
unsigned int i;
@@ -64,6 +85,8 @@ static void clear_entries(git_tree *tree)
}
git_vector_clear(&tree->entries);
+
+ tree->object.modified = 1;
}
@@ -90,7 +113,7 @@ git_tree *git_tree__new(void)
void git_tree__free(git_tree *tree)
{
- clear_entries(tree);
+ git_tree_clear_entries(tree);
git_vector_free(&tree->entries);
free(tree);
}
@@ -174,12 +197,11 @@ size_t git_tree_entrycount(git_tree *tree)
return tree->entries.length;
}
-int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes)
+int git_tree_add_entry_unsorted(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes)
{
- git_tree_entry *entry;
-
assert(tree && id && filename);
+ git_tree_entry *entry;
if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL)
return GIT_ENOMEM;
@@ -193,8 +215,6 @@ int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid
if (git_vector_insert(&tree->entries, entry) < 0)
return GIT_ENOMEM;
- git_vector_sort(&tree->entries);
-
if (entry_out != NULL)
*entry_out = entry;
@@ -202,6 +222,22 @@ int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid
return GIT_SUCCESS;
}
+int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes)
+{
+ int result = git_tree_add_entry_unsorted(entry_out, tree, id, filename, attributes);
+ if (result == GIT_SUCCESS) {
+ git_vector_sort(&tree->entries);
+ return GIT_SUCCESS;
+ }
+ return result;
+}
+
+int git_tree_sort_entries(git_tree *tree)
+{
+ git_vector_sort(&tree->entries);
+ return GIT_SUCCESS;
+}
+
int git_tree_remove_entry_byindex(git_tree *tree, int idx)
{
git_tree_entry *remove_ptr;
@@ -269,7 +305,7 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
expected_size = (tree->object.source.raw.len / avg_entry_size) + 1;
- clear_entries(tree);
+ git_tree_clear_entries(tree);
while (buffer < buffer_end) {
git_tree_entry *entry;