rugged 0.25.0b2 → 0.25.0b3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/ext/rugged/extconf.rb +3 -1
- data/ext/rugged/rugged.c +1 -1
- data/ext/rugged/rugged.h +1 -1
- data/ext/rugged/rugged_blob.c +29 -38
- data/ext/rugged/rugged_commit.c +215 -78
- data/ext/rugged/rugged_rebase.c +18 -11
- data/ext/rugged/rugged_remote.c +2 -2
- data/ext/rugged/rugged_tree.c +132 -0
- data/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/CMakeLists.txt +11 -3
- data/vendor/libgit2/include/git2.h +1 -0
- data/vendor/libgit2/include/git2/blob.h +39 -28
- data/vendor/libgit2/include/git2/commit.h +30 -0
- data/vendor/libgit2/include/git2/common.h +16 -1
- data/vendor/libgit2/include/git2/merge.h +10 -1
- data/vendor/libgit2/include/git2/proxy.h +92 -0
- data/vendor/libgit2/include/git2/refs.h +11 -0
- data/vendor/libgit2/include/git2/remote.h +17 -4
- data/vendor/libgit2/include/git2/signature.h +13 -0
- data/vendor/libgit2/include/git2/sys/merge.h +177 -0
- data/vendor/libgit2/include/git2/sys/remote.h +16 -0
- data/vendor/libgit2/include/git2/sys/stream.h +2 -1
- data/vendor/libgit2/include/git2/sys/transport.h +3 -1
- data/vendor/libgit2/include/git2/tag.h +9 -0
- data/vendor/libgit2/include/git2/tree.h +55 -0
- data/vendor/libgit2/src/annotated_commit.c +99 -80
- data/vendor/libgit2/src/annotated_commit.h +5 -2
- data/vendor/libgit2/src/array.h +40 -0
- data/vendor/libgit2/src/blame.c +8 -3
- data/vendor/libgit2/src/blame_git.c +2 -1
- data/vendor/libgit2/src/blob.c +71 -39
- data/vendor/libgit2/src/branch.c +2 -1
- data/vendor/libgit2/src/checkout.c +66 -42
- data/vendor/libgit2/src/commit.c +67 -3
- data/vendor/libgit2/src/config_cache.c +2 -1
- data/vendor/libgit2/src/config_file.c +32 -27
- data/vendor/libgit2/src/curl_stream.c +89 -6
- data/vendor/libgit2/src/delta-apply.c +36 -5
- data/vendor/libgit2/src/delta-apply.h +12 -0
- data/vendor/libgit2/src/describe.c +3 -2
- data/vendor/libgit2/src/diff.c +13 -20
- data/vendor/libgit2/src/diff_tform.c +5 -3
- data/vendor/libgit2/src/filebuf.c +12 -2
- data/vendor/libgit2/src/filebuf.h +1 -0
- data/vendor/libgit2/src/fnmatch.c +18 -5
- data/vendor/libgit2/src/global.c +18 -0
- data/vendor/libgit2/src/global.h +1 -0
- data/vendor/libgit2/src/ignore.c +11 -3
- data/vendor/libgit2/src/index.c +11 -5
- data/vendor/libgit2/src/indexer.c +11 -7
- data/vendor/libgit2/src/iterator.c +1575 -1468
- data/vendor/libgit2/src/iterator.h +52 -69
- data/vendor/libgit2/src/merge.c +160 -63
- data/vendor/libgit2/src/merge.h +61 -2
- data/vendor/libgit2/src/merge_driver.c +397 -0
- data/vendor/libgit2/src/merge_driver.h +60 -0
- data/vendor/libgit2/src/merge_file.c +11 -49
- data/vendor/libgit2/src/netops.c +12 -10
- data/vendor/libgit2/src/object.c +3 -6
- data/vendor/libgit2/src/object_api.c +19 -1
- data/vendor/libgit2/src/odb_loose.c +1 -1
- data/vendor/libgit2/src/openssl_stream.c +16 -3
- data/vendor/libgit2/src/pack-objects.c +3 -1
- data/vendor/libgit2/src/pack.c +5 -9
- data/vendor/libgit2/src/path.c +14 -0
- data/vendor/libgit2/src/path.h +12 -0
- data/vendor/libgit2/src/pathspec.c +1 -1
- data/vendor/libgit2/src/posix.c +7 -0
- data/vendor/libgit2/src/posix.h +1 -0
- data/vendor/libgit2/src/proxy.c +32 -0
- data/vendor/libgit2/src/proxy.h +14 -0
- data/vendor/libgit2/src/push.c +7 -7
- data/vendor/libgit2/src/rebase.c +61 -31
- data/vendor/libgit2/src/refdb_fs.c +1 -0
- data/vendor/libgit2/src/refs.c +16 -1
- data/vendor/libgit2/src/remote.c +20 -6
- data/vendor/libgit2/src/repository.c +1 -1
- data/vendor/libgit2/src/reset.c +1 -1
- data/vendor/libgit2/src/settings.c +23 -1
- data/vendor/libgit2/src/signature.c +26 -1
- data/vendor/libgit2/src/stransport_stream.c +5 -2
- data/vendor/libgit2/src/stream.h +2 -2
- data/vendor/libgit2/src/submodule.c +3 -2
- data/vendor/libgit2/src/tag.c +8 -2
- data/vendor/libgit2/src/transports/http.c +32 -9
- data/vendor/libgit2/src/transports/local.c +4 -1
- data/vendor/libgit2/src/transports/smart.c +6 -0
- data/vendor/libgit2/src/transports/smart.h +1 -0
- data/vendor/libgit2/src/transports/smart_protocol.c +61 -17
- data/vendor/libgit2/src/transports/winhttp.c +130 -11
- data/vendor/libgit2/src/tree.c +329 -98
- data/vendor/libgit2/src/tree.h +4 -5
- data/vendor/libgit2/src/unix/map.c +5 -0
- data/vendor/libgit2/src/win32/map.c +24 -5
- data/vendor/libgit2/src/xdiff/xprepare.c +2 -1
- metadata +10 -4
- data/vendor/libgit2/Makefile.embed +0 -60
data/vendor/libgit2/src/tree.c
CHANGED
|
@@ -85,9 +85,10 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* Allocate
|
|
88
|
+
* Allocate a new self-contained entry, with enough space after it to
|
|
89
|
+
* store the filename and the id.
|
|
89
90
|
*/
|
|
90
|
-
static git_tree_entry *
|
|
91
|
+
static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, const git_oid *id)
|
|
91
92
|
{
|
|
92
93
|
git_tree_entry *entry = NULL;
|
|
93
94
|
size_t tree_len;
|
|
@@ -95,44 +96,32 @@ static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, si
|
|
|
95
96
|
TREE_ENTRY_CHECK_NAMELEN(filename_len);
|
|
96
97
|
|
|
97
98
|
if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
|
|
98
|
-
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1)
|
|
99
|
+
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) ||
|
|
100
|
+
GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_RAWSZ))
|
|
99
101
|
return NULL;
|
|
100
102
|
|
|
101
|
-
entry =
|
|
102
|
-
git__malloc(tree_len);
|
|
103
|
+
entry = git__calloc(1, tree_len);
|
|
103
104
|
if (!entry)
|
|
104
105
|
return NULL;
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
entry->filename_len = (uint16_t)filename_len;
|
|
110
|
-
|
|
111
|
-
return entry;
|
|
112
|
-
}
|
|
107
|
+
{
|
|
108
|
+
char *filename_ptr;
|
|
109
|
+
void *id_ptr;
|
|
113
110
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* of small strings but can use the pool.
|
|
118
|
-
*/
|
|
119
|
-
static git_tree_entry *alloc_entry_pooled(git_pool *pool, const char *filename, size_t filename_len)
|
|
120
|
-
{
|
|
121
|
-
git_tree_entry *entry = NULL;
|
|
111
|
+
filename_ptr = ((char *) entry) + sizeof(git_tree_entry);
|
|
112
|
+
memcpy(filename_ptr, filename, filename_len);
|
|
113
|
+
entry->filename = filename_ptr;
|
|
122
114
|
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
id_ptr = filename_ptr + filename_len + 1;
|
|
116
|
+
git_oid_cpy(id_ptr, id);
|
|
117
|
+
entry->oid = id_ptr;
|
|
118
|
+
}
|
|
125
119
|
|
|
126
|
-
entry->
|
|
120
|
+
entry->filename_len = (uint16_t)filename_len;
|
|
127
121
|
|
|
128
122
|
return entry;
|
|
129
123
|
}
|
|
130
124
|
|
|
131
|
-
static git_tree_entry *alloc_entry(const char *filename)
|
|
132
|
-
{
|
|
133
|
-
return alloc_entry_base(NULL, filename, strlen(filename));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
125
|
struct tree_key_search {
|
|
137
126
|
const char *filename;
|
|
138
127
|
uint16_t filename_len;
|
|
@@ -174,7 +163,10 @@ static int homing_search_cmp(const void *key, const void *array_member)
|
|
|
174
163
|
* around the area for our target file.
|
|
175
164
|
*/
|
|
176
165
|
static int tree_key_search(
|
|
177
|
-
size_t *at_pos,
|
|
166
|
+
size_t *at_pos,
|
|
167
|
+
const git_tree *tree,
|
|
168
|
+
const char *filename,
|
|
169
|
+
size_t filename_len)
|
|
178
170
|
{
|
|
179
171
|
struct tree_key_search ksearch;
|
|
180
172
|
const git_tree_entry *entry;
|
|
@@ -187,13 +179,15 @@ static int tree_key_search(
|
|
|
187
179
|
|
|
188
180
|
/* Initial homing search; find an entry on the tree with
|
|
189
181
|
* the same prefix as the filename we're looking for */
|
|
190
|
-
|
|
182
|
+
|
|
183
|
+
if (git_array_search(&homing,
|
|
184
|
+
tree->entries, &homing_search_cmp, &ksearch) < 0)
|
|
191
185
|
return GIT_ENOTFOUND; /* just a signal error; not passed back to user */
|
|
192
186
|
|
|
193
187
|
/* We found a common prefix. Look forward as long as
|
|
194
188
|
* there are entries that share the common prefix */
|
|
195
|
-
for (i = homing; i < entries
|
|
196
|
-
entry = entries
|
|
189
|
+
for (i = homing; i < tree->entries.size; ++i) {
|
|
190
|
+
entry = git_array_get(tree->entries, i);
|
|
197
191
|
|
|
198
192
|
if (homing_search_cmp(&ksearch, entry) < 0)
|
|
199
193
|
break;
|
|
@@ -213,7 +207,7 @@ static int tree_key_search(
|
|
|
213
207
|
i = homing - 1;
|
|
214
208
|
|
|
215
209
|
do {
|
|
216
|
-
entry = entries
|
|
210
|
+
entry = git_array_get(tree->entries, i);
|
|
217
211
|
|
|
218
212
|
if (homing_search_cmp(&ksearch, entry) > 0)
|
|
219
213
|
break;
|
|
@@ -234,7 +228,7 @@ static int tree_key_search(
|
|
|
234
228
|
|
|
235
229
|
void git_tree_entry_free(git_tree_entry *entry)
|
|
236
230
|
{
|
|
237
|
-
if (entry == NULL
|
|
231
|
+
if (entry == NULL)
|
|
238
232
|
return;
|
|
239
233
|
|
|
240
234
|
git__free(entry);
|
|
@@ -242,36 +236,26 @@ void git_tree_entry_free(git_tree_entry *entry)
|
|
|
242
236
|
|
|
243
237
|
int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source)
|
|
244
238
|
{
|
|
245
|
-
|
|
246
|
-
git_tree_entry *copy;
|
|
239
|
+
git_tree_entry *cpy;
|
|
247
240
|
|
|
248
241
|
assert(source);
|
|
249
242
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
copy = git__malloc(total_size);
|
|
254
|
-
GITERR_CHECK_ALLOC(copy);
|
|
255
|
-
|
|
256
|
-
memcpy(copy, source, total_size);
|
|
243
|
+
cpy = alloc_entry(source->filename, source->filename_len, source->oid);
|
|
244
|
+
if (cpy == NULL)
|
|
245
|
+
return -1;
|
|
257
246
|
|
|
258
|
-
|
|
247
|
+
cpy->attr = source->attr;
|
|
259
248
|
|
|
260
|
-
*dest =
|
|
249
|
+
*dest = cpy;
|
|
261
250
|
return 0;
|
|
262
251
|
}
|
|
263
252
|
|
|
264
253
|
void git_tree__free(void *_tree)
|
|
265
254
|
{
|
|
266
255
|
git_tree *tree = _tree;
|
|
267
|
-
size_t i;
|
|
268
|
-
git_tree_entry *e;
|
|
269
|
-
|
|
270
|
-
git_vector_foreach(&tree->entries, i, e)
|
|
271
|
-
git_tree_entry_free(e);
|
|
272
256
|
|
|
273
|
-
|
|
274
|
-
|
|
257
|
+
git_odb_object_free(tree->odb_obj);
|
|
258
|
+
git_array_clear(tree->entries);
|
|
275
259
|
git__free(tree);
|
|
276
260
|
}
|
|
277
261
|
|
|
@@ -294,7 +278,7 @@ const char *git_tree_entry_name(const git_tree_entry *entry)
|
|
|
294
278
|
const git_oid *git_tree_entry_id(const git_tree_entry *entry)
|
|
295
279
|
{
|
|
296
280
|
assert(entry);
|
|
297
|
-
return
|
|
281
|
+
return entry->oid;
|
|
298
282
|
}
|
|
299
283
|
|
|
300
284
|
git_otype git_tree_entry_type(const git_tree_entry *entry)
|
|
@@ -315,7 +299,7 @@ int git_tree_entry_to_object(
|
|
|
315
299
|
const git_tree_entry *entry)
|
|
316
300
|
{
|
|
317
301
|
assert(entry && object_out);
|
|
318
|
-
return git_object_lookup(object_out, repo,
|
|
302
|
+
return git_object_lookup(object_out, repo, entry->oid, GIT_OBJ_ANY);
|
|
319
303
|
}
|
|
320
304
|
|
|
321
305
|
static const git_tree_entry *entry_fromname(
|
|
@@ -323,13 +307,10 @@ static const git_tree_entry *entry_fromname(
|
|
|
323
307
|
{
|
|
324
308
|
size_t idx;
|
|
325
309
|
|
|
326
|
-
|
|
327
|
-
assert(git_vector_is_sorted(&tree->entries));
|
|
328
|
-
|
|
329
|
-
if (tree_key_search(&idx, (git_vector *)&tree->entries, name, name_len) < 0)
|
|
310
|
+
if (tree_key_search(&idx, tree, name, name_len) < 0)
|
|
330
311
|
return NULL;
|
|
331
312
|
|
|
332
|
-
return
|
|
313
|
+
return git_array_get(tree->entries, idx);
|
|
333
314
|
}
|
|
334
315
|
|
|
335
316
|
const git_tree_entry *git_tree_entry_byname(
|
|
@@ -344,7 +325,7 @@ const git_tree_entry *git_tree_entry_byindex(
|
|
|
344
325
|
const git_tree *tree, size_t idx)
|
|
345
326
|
{
|
|
346
327
|
assert(tree);
|
|
347
|
-
return
|
|
328
|
+
return git_array_get(tree->entries, idx);
|
|
348
329
|
}
|
|
349
330
|
|
|
350
331
|
const git_tree_entry *git_tree_entry_byid(
|
|
@@ -355,8 +336,8 @@ const git_tree_entry *git_tree_entry_byid(
|
|
|
355
336
|
|
|
356
337
|
assert(tree);
|
|
357
338
|
|
|
358
|
-
|
|
359
|
-
if (memcmp(&e->oid
|
|
339
|
+
git_array_foreach(tree->entries, i, e) {
|
|
340
|
+
if (memcmp(&e->oid->id, &id->id, sizeof(id->id)) == 0)
|
|
360
341
|
return e;
|
|
361
342
|
}
|
|
362
343
|
|
|
@@ -365,7 +346,6 @@ const git_tree_entry *git_tree_entry_byid(
|
|
|
365
346
|
|
|
366
347
|
int git_tree__prefix_position(const git_tree *tree, const char *path)
|
|
367
348
|
{
|
|
368
|
-
const git_vector *entries = &tree->entries;
|
|
369
349
|
struct tree_key_search ksearch;
|
|
370
350
|
size_t at_pos, path_len;
|
|
371
351
|
|
|
@@ -378,21 +358,20 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
|
|
|
378
358
|
ksearch.filename = path;
|
|
379
359
|
ksearch.filename_len = (uint16_t)path_len;
|
|
380
360
|
|
|
381
|
-
/* be safe when we cast away constness - i.e. don't trigger a sort */
|
|
382
|
-
assert(git_vector_is_sorted(&tree->entries));
|
|
383
|
-
|
|
384
361
|
/* Find tree entry with appropriate prefix */
|
|
385
|
-
|
|
386
|
-
&at_pos,
|
|
362
|
+
git_array_search(
|
|
363
|
+
&at_pos, tree->entries, &homing_search_cmp, &ksearch);
|
|
387
364
|
|
|
388
|
-
for (; at_pos < entries
|
|
389
|
-
const git_tree_entry *entry = entries
|
|
365
|
+
for (; at_pos < tree->entries.size; ++at_pos) {
|
|
366
|
+
const git_tree_entry *entry = git_array_get(tree->entries, at_pos);
|
|
390
367
|
if (homing_search_cmp(&ksearch, entry) < 0)
|
|
391
368
|
break;
|
|
392
369
|
}
|
|
393
370
|
|
|
394
371
|
for (; at_pos > 0; --at_pos) {
|
|
395
|
-
const git_tree_entry *entry =
|
|
372
|
+
const git_tree_entry *entry =
|
|
373
|
+
git_array_get(tree->entries, at_pos - 1);
|
|
374
|
+
|
|
396
375
|
if (homing_search_cmp(&ksearch, entry) > 0)
|
|
397
376
|
break;
|
|
398
377
|
}
|
|
@@ -403,7 +382,7 @@ int git_tree__prefix_position(const git_tree *tree, const char *path)
|
|
|
403
382
|
size_t git_tree_entrycount(const git_tree *tree)
|
|
404
383
|
{
|
|
405
384
|
assert(tree);
|
|
406
|
-
return tree->entries.
|
|
385
|
+
return tree->entries.size;
|
|
407
386
|
}
|
|
408
387
|
|
|
409
388
|
unsigned int git_treebuilder_entrycount(git_treebuilder *bld)
|
|
@@ -444,13 +423,18 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff
|
|
|
444
423
|
int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
|
445
424
|
{
|
|
446
425
|
git_tree *tree = _tree;
|
|
447
|
-
const char *buffer
|
|
448
|
-
const char *buffer_end
|
|
426
|
+
const char *buffer;
|
|
427
|
+
const char *buffer_end;
|
|
449
428
|
|
|
450
|
-
|
|
451
|
-
if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0)
|
|
429
|
+
if (git_odb_object_dup(&tree->odb_obj, odb_obj) < 0)
|
|
452
430
|
return -1;
|
|
453
431
|
|
|
432
|
+
buffer = git_odb_object_data(tree->odb_obj);
|
|
433
|
+
buffer_end = buffer + git_odb_object_size(tree->odb_obj);
|
|
434
|
+
|
|
435
|
+
git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE);
|
|
436
|
+
GITERR_CHECK_ARRAY(tree->entries);
|
|
437
|
+
|
|
454
438
|
while (buffer < buffer_end) {
|
|
455
439
|
git_tree_entry *entry;
|
|
456
440
|
size_t filename_len;
|
|
@@ -464,27 +448,21 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
|
|
|
464
448
|
return tree_error("Failed to parse tree. Object is corrupted", NULL);
|
|
465
449
|
|
|
466
450
|
filename_len = nul - buffer;
|
|
467
|
-
|
|
451
|
+
/* Allocate the entry */
|
|
468
452
|
{
|
|
469
|
-
entry =
|
|
453
|
+
entry = git_array_alloc(tree->entries);
|
|
470
454
|
GITERR_CHECK_ALLOC(entry);
|
|
471
455
|
|
|
472
|
-
if (git_vector_insert(&tree->entries, entry) < 0)
|
|
473
|
-
return -1;
|
|
474
|
-
|
|
475
456
|
entry->attr = attr;
|
|
457
|
+
entry->filename_len = filename_len;
|
|
458
|
+
entry->filename = buffer;
|
|
459
|
+
entry->oid = (git_oid *) ((char *) buffer + filename_len + 1);
|
|
476
460
|
}
|
|
477
461
|
|
|
478
|
-
/* Advance to the ID just after the path */
|
|
479
462
|
buffer += filename_len + 1;
|
|
480
|
-
|
|
481
|
-
git_oid_fromraw(&entry->oid, (const unsigned char *)buffer);
|
|
482
463
|
buffer += GIT_OID_RAWSZ;
|
|
483
464
|
}
|
|
484
465
|
|
|
485
|
-
/* The tree is sorted by definition. Bad inputs give bad outputs */
|
|
486
|
-
tree->entries.flags |= GIT_VECTOR_SORTED;
|
|
487
|
-
|
|
488
466
|
return 0;
|
|
489
467
|
}
|
|
490
468
|
|
|
@@ -517,10 +495,9 @@ static int append_entry(
|
|
|
517
495
|
if (!valid_entry_name(bld->repo, filename))
|
|
518
496
|
return tree_error("Failed to insert entry. Invalid name for a tree entry", filename);
|
|
519
497
|
|
|
520
|
-
entry = alloc_entry(filename);
|
|
498
|
+
entry = alloc_entry(filename, strlen(filename), id);
|
|
521
499
|
GITERR_CHECK_ALLOC(entry);
|
|
522
500
|
|
|
523
|
-
git_oid_cpy(&entry->oid, id);
|
|
524
501
|
entry->attr = (uint16_t)filemode;
|
|
525
502
|
|
|
526
503
|
git_strmap_insert(bld->map, entry->filename, entry, error);
|
|
@@ -709,10 +686,10 @@ int git_treebuilder_new(
|
|
|
709
686
|
if (source != NULL) {
|
|
710
687
|
git_tree_entry *entry_src;
|
|
711
688
|
|
|
712
|
-
|
|
689
|
+
git_array_foreach(source->entries, i, entry_src) {
|
|
713
690
|
if (append_entry(
|
|
714
691
|
bld, entry_src->filename,
|
|
715
|
-
|
|
692
|
+
entry_src->oid,
|
|
716
693
|
entry_src->attr) < 0)
|
|
717
694
|
goto on_error;
|
|
718
695
|
}
|
|
@@ -764,8 +741,9 @@ int git_treebuilder_insert(
|
|
|
764
741
|
pos = git_strmap_lookup_index(bld->map, filename);
|
|
765
742
|
if (git_strmap_valid_index(bld->map, pos)) {
|
|
766
743
|
entry = git_strmap_value_at(bld->map, pos);
|
|
744
|
+
git_oid_cpy((git_oid *) entry->oid, id);
|
|
767
745
|
} else {
|
|
768
|
-
entry = alloc_entry(filename);
|
|
746
|
+
entry = alloc_entry(filename, strlen(filename), id);
|
|
769
747
|
GITERR_CHECK_ALLOC(entry);
|
|
770
748
|
|
|
771
749
|
git_strmap_insert(bld->map, entry->filename, entry, error);
|
|
@@ -777,7 +755,6 @@ int git_treebuilder_insert(
|
|
|
777
755
|
}
|
|
778
756
|
}
|
|
779
757
|
|
|
780
|
-
git_oid_cpy(&entry->oid, id);
|
|
781
758
|
entry->attr = filemode;
|
|
782
759
|
|
|
783
760
|
if (entry_out)
|
|
@@ -848,19 +825,20 @@ int git_treebuilder_write(git_oid *oid, git_treebuilder *bld)
|
|
|
848
825
|
|
|
849
826
|
git_buf_printf(&tree, "%o ", entry->attr);
|
|
850
827
|
git_buf_put(&tree, entry->filename, entry->filename_len + 1);
|
|
851
|
-
git_buf_put(&tree, (char *)entry->oid
|
|
828
|
+
git_buf_put(&tree, (char *)entry->oid->id, GIT_OID_RAWSZ);
|
|
852
829
|
|
|
853
830
|
if (git_buf_oom(&tree))
|
|
854
831
|
error = -1;
|
|
855
832
|
}
|
|
856
833
|
|
|
857
|
-
git_vector_free(&entries);
|
|
858
834
|
|
|
859
835
|
if (!error &&
|
|
860
836
|
!(error = git_repository_odb__weakptr(&odb, bld->repo)))
|
|
861
837
|
error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE);
|
|
862
838
|
|
|
863
839
|
git_buf_free(&tree);
|
|
840
|
+
git_vector_free(&entries);
|
|
841
|
+
|
|
864
842
|
return error;
|
|
865
843
|
}
|
|
866
844
|
|
|
@@ -960,7 +938,7 @@ int git_tree_entry_bypath(
|
|
|
960
938
|
return git_tree_entry_dup(entry_out, entry);
|
|
961
939
|
}
|
|
962
940
|
|
|
963
|
-
if (git_tree_lookup(&subtree, root->object.repo,
|
|
941
|
+
if (git_tree_lookup(&subtree, root->object.repo, entry->oid) < 0)
|
|
964
942
|
return -1;
|
|
965
943
|
|
|
966
944
|
error = git_tree_entry_bypath(
|
|
@@ -984,7 +962,7 @@ static int tree_walk(
|
|
|
984
962
|
size_t i;
|
|
985
963
|
const git_tree_entry *entry;
|
|
986
964
|
|
|
987
|
-
|
|
965
|
+
git_array_foreach(tree->entries, i, entry) {
|
|
988
966
|
if (preorder) {
|
|
989
967
|
error = callback(path->ptr, entry, payload);
|
|
990
968
|
if (error < 0) { /* negative value stops iteration */
|
|
@@ -1001,7 +979,7 @@ static int tree_walk(
|
|
|
1001
979
|
git_tree *subtree;
|
|
1002
980
|
size_t path_len = git_buf_len(path);
|
|
1003
981
|
|
|
1004
|
-
error = git_tree_lookup(&subtree, tree->object.repo,
|
|
982
|
+
error = git_tree_lookup(&subtree, tree->object.repo, entry->oid);
|
|
1005
983
|
if (error < 0)
|
|
1006
984
|
break;
|
|
1007
985
|
|
|
@@ -1056,3 +1034,256 @@ int git_tree_walk(
|
|
|
1056
1034
|
return error;
|
|
1057
1035
|
}
|
|
1058
1036
|
|
|
1037
|
+
static int compare_entries(const void *_a, const void *_b)
|
|
1038
|
+
{
|
|
1039
|
+
const git_tree_update *a = (git_tree_update *) _a;
|
|
1040
|
+
const git_tree_update *b = (git_tree_update *) _b;
|
|
1041
|
+
|
|
1042
|
+
return strcmp(a->path, b->path);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
static int on_dup_entry(void **old, void *new)
|
|
1046
|
+
{
|
|
1047
|
+
GIT_UNUSED(old); GIT_UNUSED(new);
|
|
1048
|
+
|
|
1049
|
+
giterr_set(GITERR_TREE, "duplicate entries given for update");
|
|
1050
|
+
return -1;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/*
|
|
1054
|
+
* We keep the previous tree and the new one at each level of the
|
|
1055
|
+
* stack. When we leave a level we're done with that tree and we can
|
|
1056
|
+
* write it out to the odb.
|
|
1057
|
+
*/
|
|
1058
|
+
typedef struct {
|
|
1059
|
+
git_treebuilder *bld;
|
|
1060
|
+
git_tree *tree;
|
|
1061
|
+
char *name;
|
|
1062
|
+
} tree_stack_entry;
|
|
1063
|
+
|
|
1064
|
+
/** Count how many slashes (i.e. path components) there are in this string */
|
|
1065
|
+
GIT_INLINE(size_t) count_slashes(const char *path)
|
|
1066
|
+
{
|
|
1067
|
+
size_t count = 0;
|
|
1068
|
+
const char *slash;
|
|
1069
|
+
|
|
1070
|
+
while ((slash = strchr(path, '/')) != NULL) {
|
|
1071
|
+
count++;
|
|
1072
|
+
path = slash + 1;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
return count;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
static bool next_component(git_buf *out, const char *in)
|
|
1079
|
+
{
|
|
1080
|
+
const char *slash = strchr(in, '/');
|
|
1081
|
+
|
|
1082
|
+
git_buf_clear(out);
|
|
1083
|
+
|
|
1084
|
+
if (slash)
|
|
1085
|
+
git_buf_put(out, in, slash - in);
|
|
1086
|
+
|
|
1087
|
+
return !!slash;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
static int create_popped_tree(tree_stack_entry *current, tree_stack_entry *popped, git_buf *component)
|
|
1091
|
+
{
|
|
1092
|
+
int error;
|
|
1093
|
+
git_oid new_tree;
|
|
1094
|
+
|
|
1095
|
+
git_tree_free(popped->tree);
|
|
1096
|
+
error = git_treebuilder_write(&new_tree, popped->bld);
|
|
1097
|
+
git_treebuilder_free(popped->bld);
|
|
1098
|
+
|
|
1099
|
+
if (error < 0) {
|
|
1100
|
+
git__free(popped->name);
|
|
1101
|
+
return error;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/* We've written out the tree, now we have to put the new value into its parent */
|
|
1105
|
+
git_buf_clear(component);
|
|
1106
|
+
git_buf_puts(component, popped->name);
|
|
1107
|
+
git__free(popped->name);
|
|
1108
|
+
|
|
1109
|
+
GITERR_CHECK_ALLOC(component->ptr);
|
|
1110
|
+
|
|
1111
|
+
/* Error out if this would create a D/F conflict in this update */
|
|
1112
|
+
if (current->tree) {
|
|
1113
|
+
const git_tree_entry *to_replace;
|
|
1114
|
+
to_replace = git_tree_entry_byname(current->tree, component->ptr);
|
|
1115
|
+
if (to_replace && git_tree_entry_type(to_replace) != GIT_OBJ_TREE) {
|
|
1116
|
+
giterr_set(GITERR_TREE, "D/F conflict when updating tree");
|
|
1117
|
+
return -1;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
return git_treebuilder_insert(NULL, current->bld, component->ptr, &new_tree, GIT_FILEMODE_TREE);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
int git_tree_create_updated(git_oid *out, git_repository *repo, git_tree *baseline, size_t nupdates, const git_tree_update *updates)
|
|
1125
|
+
{
|
|
1126
|
+
git_array_t(tree_stack_entry) stack = GIT_ARRAY_INIT;
|
|
1127
|
+
tree_stack_entry *root_elem;
|
|
1128
|
+
git_vector entries;
|
|
1129
|
+
int error;
|
|
1130
|
+
size_t i;
|
|
1131
|
+
git_buf component = GIT_BUF_INIT;
|
|
1132
|
+
|
|
1133
|
+
if ((error = git_vector_init(&entries, nupdates, compare_entries)) < 0)
|
|
1134
|
+
return error;
|
|
1135
|
+
|
|
1136
|
+
/* Sort the entries for treversal */
|
|
1137
|
+
for (i = 0 ; i < nupdates; i++) {
|
|
1138
|
+
if ((error = git_vector_insert_sorted(&entries, (void *) &updates[i], on_dup_entry)) < 0)
|
|
1139
|
+
goto cleanup;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
root_elem = git_array_alloc(stack);
|
|
1143
|
+
GITERR_CHECK_ALLOC(root_elem);
|
|
1144
|
+
memset(root_elem, 0, sizeof(*root_elem));
|
|
1145
|
+
|
|
1146
|
+
if (baseline && (error = git_tree_dup(&root_elem->tree, baseline)) < 0)
|
|
1147
|
+
goto cleanup;
|
|
1148
|
+
|
|
1149
|
+
if ((error = git_treebuilder_new(&root_elem->bld, repo, root_elem->tree)) < 0)
|
|
1150
|
+
goto cleanup;
|
|
1151
|
+
|
|
1152
|
+
for (i = 0; i < nupdates; i++) {
|
|
1153
|
+
const git_tree_update *last_update = i == 0 ? NULL : &updates[i-1];
|
|
1154
|
+
const git_tree_update *update = &updates[i];
|
|
1155
|
+
size_t common_prefix = 0, steps_up, j;
|
|
1156
|
+
const char *path;
|
|
1157
|
+
|
|
1158
|
+
/* Figure out how much we need to change from the previous tree */
|
|
1159
|
+
if (last_update)
|
|
1160
|
+
common_prefix = git_path_common_dirlen(last_update->path, update->path);
|
|
1161
|
+
|
|
1162
|
+
/*
|
|
1163
|
+
* The entries are sorted, so when we find we're no
|
|
1164
|
+
* longer in the same directory, we need to abandon
|
|
1165
|
+
* the old tree (steps up) and dive down to the next
|
|
1166
|
+
* one.
|
|
1167
|
+
*/
|
|
1168
|
+
steps_up = last_update == NULL ? 0 : count_slashes(&last_update->path[common_prefix]);
|
|
1169
|
+
|
|
1170
|
+
for (j = 0; j < steps_up; j++) {
|
|
1171
|
+
tree_stack_entry *current, *popped = git_array_pop(stack);
|
|
1172
|
+
assert(popped);
|
|
1173
|
+
|
|
1174
|
+
current = git_array_last(stack);
|
|
1175
|
+
assert(current);
|
|
1176
|
+
|
|
1177
|
+
if ((error = create_popped_tree(current, popped, &component)) < 0)
|
|
1178
|
+
goto cleanup;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
/* Now that we've created the trees we popped from the stack, let's go back down */
|
|
1182
|
+
path = &update->path[common_prefix];
|
|
1183
|
+
while (next_component(&component, path)) {
|
|
1184
|
+
tree_stack_entry *last, *new_entry;
|
|
1185
|
+
const git_tree_entry *entry;
|
|
1186
|
+
|
|
1187
|
+
last = git_array_last(stack);
|
|
1188
|
+
entry = last->tree ? git_tree_entry_byname(last->tree, component.ptr) : NULL;
|
|
1189
|
+
if (entry && git_tree_entry_type(entry) != GIT_OBJ_TREE) {
|
|
1190
|
+
giterr_set(GITERR_TREE, "D/F conflict when updating tree");
|
|
1191
|
+
error = -1;
|
|
1192
|
+
goto cleanup;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
new_entry = git_array_alloc(stack);
|
|
1196
|
+
GITERR_CHECK_ALLOC(new_entry);
|
|
1197
|
+
memset(new_entry, 0, sizeof(*new_entry));
|
|
1198
|
+
|
|
1199
|
+
new_entry->tree = NULL;
|
|
1200
|
+
if (entry && (error = git_tree_lookup(&new_entry->tree, repo, git_tree_entry_id(entry))) < 0)
|
|
1201
|
+
goto cleanup;
|
|
1202
|
+
|
|
1203
|
+
if ((error = git_treebuilder_new(&new_entry->bld, repo, new_entry->tree)) < 0)
|
|
1204
|
+
goto cleanup;
|
|
1205
|
+
|
|
1206
|
+
new_entry->name = git__strdup(component.ptr);
|
|
1207
|
+
GITERR_CHECK_ALLOC(new_entry->name);
|
|
1208
|
+
|
|
1209
|
+
/* Get to the start of the next component */
|
|
1210
|
+
path += component.size + 1;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/* After all that, we're finally at the place where we want to perform the update */
|
|
1214
|
+
switch (update->action) {
|
|
1215
|
+
case GIT_TREE_UPDATE_UPSERT:
|
|
1216
|
+
{
|
|
1217
|
+
/* Make sure we're replacing something of the same type */
|
|
1218
|
+
tree_stack_entry *last = git_array_last(stack);
|
|
1219
|
+
char *basename = git_path_basename(update->path);
|
|
1220
|
+
const git_tree_entry *e = git_treebuilder_get(last->bld, basename);
|
|
1221
|
+
if (e && git_tree_entry_type(e) != git_object__type_from_filemode(update->filemode)) {
|
|
1222
|
+
git__free(basename);
|
|
1223
|
+
giterr_set(GITERR_TREE, "Cannot replace '%s' with '%s' at '%s'",
|
|
1224
|
+
git_object_type2string(git_tree_entry_type(e)),
|
|
1225
|
+
git_object_type2string(git_object__type_from_filemode(update->filemode)),
|
|
1226
|
+
update->path);
|
|
1227
|
+
error = -1;
|
|
1228
|
+
goto cleanup;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
error = git_treebuilder_insert(NULL, last->bld, basename, &update->id, update->filemode);
|
|
1232
|
+
git__free(basename);
|
|
1233
|
+
break;
|
|
1234
|
+
}
|
|
1235
|
+
case GIT_TREE_UPDATE_REMOVE:
|
|
1236
|
+
{
|
|
1237
|
+
char *basename = git_path_basename(update->path);
|
|
1238
|
+
error = git_treebuilder_remove(git_array_last(stack)->bld, basename);
|
|
1239
|
+
git__free(basename);
|
|
1240
|
+
break;
|
|
1241
|
+
}
|
|
1242
|
+
default:
|
|
1243
|
+
giterr_set(GITERR_TREE, "unkown action for update");
|
|
1244
|
+
error = -1;
|
|
1245
|
+
goto cleanup;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
if (error < 0)
|
|
1249
|
+
goto cleanup;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/* We're done, go up the stack again and write out the tree */
|
|
1253
|
+
{
|
|
1254
|
+
tree_stack_entry *current = NULL, *popped = NULL;
|
|
1255
|
+
while ((popped = git_array_pop(stack)) != NULL) {
|
|
1256
|
+
current = git_array_last(stack);
|
|
1257
|
+
/* We've reached the top, current is the root tree */
|
|
1258
|
+
if (!current)
|
|
1259
|
+
break;
|
|
1260
|
+
|
|
1261
|
+
if ((error = create_popped_tree(current, popped, &component)) < 0)
|
|
1262
|
+
goto cleanup;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/* Write out the root tree */
|
|
1266
|
+
git__free(popped->name);
|
|
1267
|
+
git_tree_free(popped->tree);
|
|
1268
|
+
|
|
1269
|
+
error = git_treebuilder_write(out, popped->bld);
|
|
1270
|
+
git_treebuilder_free(popped->bld);
|
|
1271
|
+
if (error < 0)
|
|
1272
|
+
goto cleanup;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
cleanup:
|
|
1276
|
+
{
|
|
1277
|
+
tree_stack_entry *e;
|
|
1278
|
+
while ((e = git_array_pop(stack)) != NULL) {
|
|
1279
|
+
git_treebuilder_free(e->bld);
|
|
1280
|
+
git_tree_free(e->tree);
|
|
1281
|
+
git__free(e->name);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
git_buf_free(&component);
|
|
1286
|
+
git_array_clear(stack);
|
|
1287
|
+
git_vector_free(&entries);
|
|
1288
|
+
return error;
|
|
1289
|
+
}
|