rugged 0.17.0.b6 → 0.17.0.b7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/README.md +3 -3
  2. data/Rakefile +3 -1
  3. data/ext/rugged/rugged.c +30 -0
  4. data/ext/rugged/rugged.h +9 -0
  5. data/ext/rugged/rugged_branch.c +306 -0
  6. data/ext/rugged/rugged_config.c +16 -13
  7. data/ext/rugged/rugged_index.c +25 -0
  8. data/ext/rugged/rugged_object.c +6 -2
  9. data/ext/rugged/rugged_reference.c +11 -18
  10. data/ext/rugged/rugged_revwalk.c +1 -1
  11. data/lib/rugged.rb +1 -0
  12. data/lib/rugged/branch.rb +28 -0
  13. data/lib/rugged/commit.rb +5 -5
  14. data/lib/rugged/repository.rb +32 -7
  15. data/lib/rugged/tag.rb +5 -1
  16. data/lib/rugged/version.rb +1 -1
  17. data/test/branch_test.rb +227 -0
  18. data/test/config_test.rb +1 -1
  19. data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
  20. data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
  21. data/test/index_test.rb +31 -0
  22. data/test/index_test.rb~ +218 -0
  23. data/test/lib_test.rb +22 -0
  24. data/test/reference_test.rb +5 -3
  25. data/vendor/libgit2/Makefile.embed +1 -1
  26. data/vendor/libgit2/include/git2.h +1 -0
  27. data/vendor/libgit2/include/git2/branch.h +17 -13
  28. data/vendor/libgit2/include/git2/checkout.h +83 -22
  29. data/vendor/libgit2/include/git2/clone.h +6 -3
  30. data/vendor/libgit2/include/git2/common.h +1 -8
  31. data/vendor/libgit2/include/git2/config.h +185 -26
  32. data/vendor/libgit2/include/git2/diff.h +229 -17
  33. data/vendor/libgit2/include/git2/errors.h +39 -1
  34. data/vendor/libgit2/include/git2/ignore.h +6 -3
  35. data/vendor/libgit2/include/git2/indexer.h +1 -0
  36. data/vendor/libgit2/include/git2/merge.h +1 -1
  37. data/vendor/libgit2/include/git2/object.h +7 -4
  38. data/vendor/libgit2/include/git2/odb.h +4 -2
  39. data/vendor/libgit2/include/git2/odb_backend.h +6 -0
  40. data/vendor/libgit2/include/git2/oid.h +2 -0
  41. data/vendor/libgit2/include/git2/pack.h +89 -0
  42. data/vendor/libgit2/include/git2/refs.h +88 -0
  43. data/vendor/libgit2/include/git2/refspec.h +0 -8
  44. data/vendor/libgit2/include/git2/remote.h +34 -1
  45. data/vendor/libgit2/include/git2/repository.h +238 -6
  46. data/vendor/libgit2/include/git2/reset.h +4 -1
  47. data/vendor/libgit2/include/git2/revwalk.h +1 -1
  48. data/vendor/libgit2/include/git2/status.h +19 -14
  49. data/vendor/libgit2/include/git2/strarray.h +54 -0
  50. data/vendor/libgit2/include/git2/submodule.h +451 -45
  51. data/vendor/libgit2/include/git2/tag.h +16 -0
  52. data/vendor/libgit2/include/git2/tree.h +2 -2
  53. data/vendor/libgit2/include/git2/types.h +4 -0
  54. data/vendor/libgit2/src/amiga/map.c +4 -7
  55. data/vendor/libgit2/src/attr.c +21 -13
  56. data/vendor/libgit2/src/attr.h +3 -1
  57. data/vendor/libgit2/src/attr_file.c +14 -14
  58. data/vendor/libgit2/src/attr_file.h +6 -5
  59. data/vendor/libgit2/src/blob.c +22 -12
  60. data/vendor/libgit2/src/branch.c +62 -66
  61. data/vendor/libgit2/src/buffer.c +63 -14
  62. data/vendor/libgit2/src/buffer.h +4 -0
  63. data/vendor/libgit2/src/cache.c +5 -4
  64. data/vendor/libgit2/src/checkout.c +381 -159
  65. data/vendor/libgit2/src/clone.c +221 -94
  66. data/vendor/libgit2/src/common.h +13 -3
  67. data/vendor/libgit2/src/compress.c +53 -0
  68. data/vendor/libgit2/src/compress.h +16 -0
  69. data/vendor/libgit2/src/config.c +380 -175
  70. data/vendor/libgit2/src/config.h +2 -5
  71. data/vendor/libgit2/src/config_file.c +63 -46
  72. data/vendor/libgit2/src/config_file.h +16 -4
  73. data/vendor/libgit2/src/crlf.c +4 -3
  74. data/vendor/libgit2/src/delta.c +491 -0
  75. data/vendor/libgit2/src/delta.h +112 -0
  76. data/vendor/libgit2/src/diff.c +310 -67
  77. data/vendor/libgit2/src/diff.h +10 -1
  78. data/vendor/libgit2/src/diff_output.c +1030 -337
  79. data/vendor/libgit2/src/diff_output.h +86 -0
  80. data/vendor/libgit2/src/errors.c +10 -1
  81. data/vendor/libgit2/src/fetch.c +108 -24
  82. data/vendor/libgit2/src/filebuf.c +8 -2
  83. data/vendor/libgit2/src/fileops.c +342 -177
  84. data/vendor/libgit2/src/fileops.h +84 -7
  85. data/vendor/libgit2/src/filter.c +0 -35
  86. data/vendor/libgit2/src/filter.h +0 -12
  87. data/vendor/libgit2/src/{compat/fnmatch.c → fnmatch.c} +16 -4
  88. data/vendor/libgit2/src/{compat/fnmatch.h → fnmatch.h} +4 -3
  89. data/vendor/libgit2/src/global.c +4 -0
  90. data/vendor/libgit2/src/ignore.c +122 -23
  91. data/vendor/libgit2/src/ignore.h +1 -0
  92. data/vendor/libgit2/src/index.c +56 -10
  93. data/vendor/libgit2/src/index.h +2 -0
  94. data/vendor/libgit2/src/indexer.c +8 -9
  95. data/vendor/libgit2/src/iterator.c +244 -31
  96. data/vendor/libgit2/src/iterator.h +30 -1
  97. data/vendor/libgit2/src/message.c +1 -1
  98. data/vendor/libgit2/src/netops.c +44 -4
  99. data/vendor/libgit2/src/object.c +80 -69
  100. data/vendor/libgit2/src/object.h +39 -0
  101. data/vendor/libgit2/src/odb.c +79 -15
  102. data/vendor/libgit2/src/odb.h +20 -5
  103. data/vendor/libgit2/src/odb_pack.c +65 -33
  104. data/vendor/libgit2/src/oid.c +0 -3
  105. data/vendor/libgit2/src/pack-objects.c +1315 -0
  106. data/vendor/libgit2/src/pack-objects.h +87 -0
  107. data/vendor/libgit2/src/pack.c +36 -12
  108. data/vendor/libgit2/src/pack.h +1 -0
  109. data/vendor/libgit2/src/path.c +42 -9
  110. data/vendor/libgit2/src/path.h +14 -0
  111. data/vendor/libgit2/src/pkt.c +52 -2
  112. data/vendor/libgit2/src/pkt.h +10 -0
  113. data/vendor/libgit2/src/pool.h +11 -0
  114. data/vendor/libgit2/src/posix.h +8 -0
  115. data/vendor/libgit2/src/protocol.c +24 -2
  116. data/vendor/libgit2/src/protocol.h +4 -0
  117. data/vendor/libgit2/src/reflog.c +1 -1
  118. data/vendor/libgit2/src/refs.c +292 -124
  119. data/vendor/libgit2/src/refs.h +4 -2
  120. data/vendor/libgit2/src/refspec.c +117 -19
  121. data/vendor/libgit2/src/refspec.h +19 -0
  122. data/vendor/libgit2/src/remote.c +152 -48
  123. data/vendor/libgit2/src/remote.h +4 -1
  124. data/vendor/libgit2/src/repo_template.h +58 -0
  125. data/vendor/libgit2/src/repository.c +594 -179
  126. data/vendor/libgit2/src/repository.h +23 -22
  127. data/vendor/libgit2/src/reset.c +71 -29
  128. data/vendor/libgit2/src/revparse.c +26 -17
  129. data/vendor/libgit2/src/revwalk.c +36 -19
  130. data/vendor/libgit2/src/sha1.h +7 -0
  131. data/vendor/libgit2/src/{sha1.c → sha1/sha1.c} +0 -0
  132. data/vendor/libgit2/src/signature.c +12 -10
  133. data/vendor/libgit2/src/status.c +52 -6
  134. data/vendor/libgit2/src/submodule.c +1363 -255
  135. data/vendor/libgit2/src/submodule.h +102 -0
  136. data/vendor/libgit2/src/tag.c +42 -26
  137. data/vendor/libgit2/src/thread-utils.h +7 -7
  138. data/vendor/libgit2/src/transport.h +15 -1
  139. data/vendor/libgit2/src/transports/git.c +1 -1
  140. data/vendor/libgit2/src/transports/http.c +197 -36
  141. data/vendor/libgit2/src/tree.c +3 -3
  142. data/vendor/libgit2/src/unix/map.c +2 -0
  143. data/vendor/libgit2/src/unix/posix.h +1 -8
  144. data/vendor/libgit2/src/util.c +6 -1
  145. data/vendor/libgit2/src/util.h +7 -0
  146. data/vendor/libgit2/src/vector.c +16 -0
  147. data/vendor/libgit2/src/vector.h +1 -0
  148. data/vendor/libgit2/src/win32/dir.c +8 -21
  149. data/vendor/libgit2/src/win32/findfile.c +149 -0
  150. data/vendor/libgit2/src/win32/findfile.h +23 -0
  151. data/vendor/libgit2/src/win32/posix.h +3 -7
  152. data/vendor/libgit2/src/win32/posix_w32.c +44 -102
  153. data/vendor/libgit2/src/win32/pthread.c +68 -0
  154. data/vendor/libgit2/src/win32/pthread.h +7 -0
  155. data/vendor/libgit2/src/win32/utf-conv.c +60 -71
  156. data/vendor/libgit2/src/win32/utf-conv.h +4 -3
  157. metadata +70 -71
  158. data/vendor/libgit2/include/git2/windows.h +0 -59
@@ -23,6 +23,7 @@ typedef struct {
23
23
  git_attr_file *ign_internal;
24
24
  git_vector ign_path;
25
25
  git_vector ign_global;
26
+ unsigned int ignore_case:1;
26
27
  } git_ignores;
27
28
 
28
29
  extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign);
@@ -99,6 +99,13 @@ static int index_srch(const void *key, const void *array_member)
99
99
  return strcmp(key, entry->path);
100
100
  }
101
101
 
102
+ static int index_isrch(const void *key, const void *array_member)
103
+ {
104
+ const git_index_entry *entry = array_member;
105
+
106
+ return strcasecmp(key, entry->path);
107
+ }
108
+
102
109
  static int index_cmp(const void *a, const void *b)
103
110
  {
104
111
  const git_index_entry *entry_a = a;
@@ -107,6 +114,14 @@ static int index_cmp(const void *a, const void *b)
107
114
  return strcmp(entry_a->path, entry_b->path);
108
115
  }
109
116
 
117
+ static int index_icmp(const void *a, const void *b)
118
+ {
119
+ const git_index_entry *entry_a = a;
120
+ const git_index_entry *entry_b = b;
121
+
122
+ return strcasecmp(entry_a->path, entry_b->path);
123
+ }
124
+
110
125
  static int unmerged_srch(const void *key, const void *array_member)
111
126
  {
112
127
  const git_index_entry_unmerged *entry = array_member;
@@ -147,6 +162,14 @@ static unsigned int index_merge_mode(
147
162
  return index_create_mode(mode);
148
163
  }
149
164
 
165
+ static void index_set_ignore_case(git_index *index, bool ignore_case)
166
+ {
167
+ index->entries._cmp = ignore_case ? index_icmp : index_cmp;
168
+ index->entries_search = ignore_case ? index_isrch : index_srch;
169
+ index->entries.sorted = 0;
170
+ git_vector_sort(&index->entries);
171
+ }
172
+
150
173
  int git_index_open(git_index **index_out, const char *index_path)
151
174
  {
152
175
  git_index *index;
@@ -162,6 +185,8 @@ int git_index_open(git_index **index_out, const char *index_path)
162
185
  if (git_vector_init(&index->entries, 32, index_cmp) < 0)
163
186
  return -1;
164
187
 
188
+ index->entries_search = index_srch;
189
+
165
190
  /* Check if index file is stored on disk already */
166
191
  if (git_path_exists(index->index_file_path) == true)
167
192
  index->on_disk = 1;
@@ -228,8 +253,12 @@ void git_index_clear(git_index *index)
228
253
 
229
254
  int git_index_set_caps(git_index *index, unsigned int caps)
230
255
  {
256
+ int old_ignore_case;
257
+
231
258
  assert(index);
232
259
 
260
+ old_ignore_case = index->ignore_case;
261
+
233
262
  if (caps == GIT_INDEXCAP_FROM_OWNER) {
234
263
  git_config *cfg;
235
264
  int val;
@@ -247,7 +276,7 @@ int git_index_set_caps(git_index *index, unsigned int caps)
247
276
  if (git_config_get_bool(&val, cfg, "core.filemode") == 0)
248
277
  index->distrust_filemode = (val == 0);
249
278
  if (git_config_get_bool(&val, cfg, "core.symlinks") == 0)
250
- index->no_symlinks = (val != 0);
279
+ index->no_symlinks = (val == 0);
251
280
  }
252
281
  else {
253
282
  index->ignore_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0);
@@ -255,6 +284,11 @@ int git_index_set_caps(git_index *index, unsigned int caps)
255
284
  index->no_symlinks = ((caps & GIT_INDEXCAP_NO_SYMLINKS) != 0);
256
285
  }
257
286
 
287
+ if (old_ignore_case != index->ignore_case)
288
+ {
289
+ index_set_ignore_case(index, index->ignore_case);
290
+ }
291
+
258
292
  return 0;
259
293
  }
260
294
 
@@ -552,14 +586,14 @@ int git_index_remove(git_index *index, int position)
552
586
 
553
587
  int git_index_find(git_index *index, const char *path)
554
588
  {
555
- return git_vector_bsearch2(&index->entries, index_srch, path);
589
+ return git_vector_bsearch2(&index->entries, index->entries_search, path);
556
590
  }
557
591
 
558
592
  unsigned int git_index__prefix_position(git_index *index, const char *path)
559
593
  {
560
594
  unsigned int pos;
561
595
 
562
- git_vector_bsearch3(&pos, &index->entries, index_srch, path);
596
+ git_vector_bsearch3(&pos, &index->entries, index->entries_search, path);
563
597
 
564
598
  return pos;
565
599
  }
@@ -938,16 +972,28 @@ static int write_disk_entry(git_filebuf *file, git_index_entry *entry)
938
972
 
939
973
  static int write_entries(git_index *index, git_filebuf *file)
940
974
  {
975
+ int error = 0;
941
976
  unsigned int i;
942
-
943
- for (i = 0; i < index->entries.length; ++i) {
944
- git_index_entry *entry;
945
- entry = git_vector_get(&index->entries, i);
946
- if (write_disk_entry(file, entry) < 0)
947
- return -1;
977
+ git_vector case_sorted;
978
+ git_index_entry *entry;
979
+ git_vector *out = &index->entries;
980
+
981
+ /* If index->entries is sorted case-insensitively, then we need
982
+ * to re-sort it case-sensitively before writing */
983
+ if (index->ignore_case) {
984
+ git_vector_dup(&case_sorted, &index->entries, index_cmp);
985
+ git_vector_sort(&case_sorted);
986
+ out = &case_sorted;
948
987
  }
949
988
 
950
- return 0;
989
+ git_vector_foreach(out, i, entry)
990
+ if ((error = write_disk_entry(file, entry)) < 0)
991
+ break;
992
+
993
+ if (index->ignore_case)
994
+ git_vector_free(&case_sorted);
995
+
996
+ return error;
951
997
  }
952
998
 
953
999
  static int write_index(git_index *index, git_filebuf *file)
@@ -34,6 +34,8 @@ struct git_index {
34
34
  git_tree_cache *tree;
35
35
 
36
36
  git_vector unmerged;
37
+
38
+ git_vector_cmp entries_search;
37
39
  };
38
40
 
39
41
  extern void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry);
@@ -324,8 +324,8 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
324
324
  if (git_vector_init(&idx->deltas, (unsigned int)(idx->nr_objects / 2), NULL) < 0)
325
325
  return -1;
326
326
 
327
+ memset(stats, 0, sizeof(git_indexer_stats));
327
328
  stats->total = (unsigned int)idx->nr_objects;
328
- stats->processed = 0;
329
329
  }
330
330
 
331
331
  /* Now that we have data in the pack, let's try to parse it */
@@ -361,6 +361,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
361
361
  if (error < 0)
362
362
  return error;
363
363
 
364
+ stats->received++;
364
365
  continue;
365
366
  }
366
367
 
@@ -379,6 +380,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
379
380
  git__free(obj.data);
380
381
 
381
382
  stats->processed = (unsigned int)++processed;
383
+ stats->received++;
382
384
  }
383
385
 
384
386
  return 0;
@@ -577,9 +579,11 @@ void git_indexer_stream_free(git_indexer_stream *idx)
577
579
  git_vector_foreach(&idx->objects, i, e)
578
580
  git__free(e);
579
581
  git_vector_free(&idx->objects);
580
- git_vector_foreach(&idx->pack->cache, i, pe)
581
- git__free(pe);
582
- git_vector_free(&idx->pack->cache);
582
+ if (idx->pack) {
583
+ git_vector_foreach(&idx->pack->cache, i, pe)
584
+ git__free(pe);
585
+ git_vector_free(&idx->pack->cache);
586
+ }
583
587
  git_vector_foreach(&idx->deltas, i, delta)
584
588
  git__free(delta);
585
589
  git_vector_free(&idx->deltas);
@@ -595,11 +599,6 @@ int git_indexer_new(git_indexer **out, const char *packname)
595
599
 
596
600
  assert(out && packname);
597
601
 
598
- if (git_path_root(packname) < 0) {
599
- giterr_set(GITERR_INDEXER, "Path is not absolute");
600
- return -1;
601
- }
602
-
603
602
  idx = git__calloc(1, sizeof(git_indexer));
604
603
  GITERR_CHECK_ALLOC(idx);
605
604
 
@@ -17,6 +17,7 @@
17
17
  (P)->base.type = GIT_ITERATOR_ ## NAME_UC; \
18
18
  (P)->base.start = start ? git__strdup(start) : NULL; \
19
19
  (P)->base.end = end ? git__strdup(end) : NULL; \
20
+ (P)->base.ignore_case = 0; \
20
21
  (P)->base.current = NAME_LC ## _iterator__current; \
21
22
  (P)->base.at_end = NAME_LC ## _iterator__at_end; \
22
23
  (P)->base.advance = NAME_LC ## _iterator__advance; \
@@ -81,7 +82,7 @@ int git_iterator_for_nothing(git_iterator **iter)
81
82
 
82
83
  typedef struct tree_iterator_frame tree_iterator_frame;
83
84
  struct tree_iterator_frame {
84
- tree_iterator_frame *next;
85
+ tree_iterator_frame *next, *prev;
85
86
  git_tree *tree;
86
87
  char *start;
87
88
  unsigned int index;
@@ -90,7 +91,7 @@ struct tree_iterator_frame {
90
91
  typedef struct {
91
92
  git_iterator base;
92
93
  git_repository *repo;
93
- tree_iterator_frame *stack;
94
+ tree_iterator_frame *stack, *tail;
94
95
  git_index_entry entry;
95
96
  git_buf path;
96
97
  bool path_has_filename;
@@ -118,8 +119,10 @@ static void tree_iterator__pop_frame(tree_iterator *ti)
118
119
  {
119
120
  tree_iterator_frame *tf = ti->stack;
120
121
  ti->stack = tf->next;
121
- if (ti->stack != NULL) /* don't free the initial tree */
122
- git_tree_free(tf->tree);
122
+ if (ti->stack != NULL) {
123
+ git_tree_free(tf->tree); /* don't free the initial tree */
124
+ ti->stack->prev = NULL; /* disconnect prev */
125
+ }
123
126
  git__free(tf);
124
127
  }
125
128
 
@@ -220,6 +223,7 @@ static int tree_iterator__expand_tree(tree_iterator *ti)
220
223
 
221
224
  tf->next = ti->stack;
222
225
  ti->stack = tf;
226
+ tf->next->prev = tf;
223
227
 
224
228
  te = tree_iterator__tree_entry(ti);
225
229
  }
@@ -311,7 +315,7 @@ int git_iterator_for_tree_range(
311
315
  ITERATOR_BASE_INIT(ti, tree, TREE);
312
316
 
313
317
  ti->repo = repo;
314
- ti->stack = tree_iterator__alloc_frame(tree, ti->base.start);
318
+ ti->stack = ti->tail = tree_iterator__alloc_frame(tree, ti->base.start);
315
319
 
316
320
  if ((error = tree_iterator__expand_tree(ti)) < 0)
317
321
  git_iterator_free((git_iterator *)ti);
@@ -336,7 +340,7 @@ static int index_iterator__current(
336
340
 
337
341
  if (ie != NULL &&
338
342
  ii->base.end != NULL &&
339
- git__prefixcmp(ie->path, ii->base.end) > 0)
343
+ ITERATOR_PREFIXCMP(ii->base, ie->path, ii->base.end) > 0)
340
344
  {
341
345
  ii->current = git_index_entrycount(ii->index);
342
346
  ie = NULL;
@@ -401,6 +405,7 @@ int git_iterator_for_index_range(
401
405
  if ((error = git_repository_index(&ii->index, repo)) < 0)
402
406
  git__free(ii);
403
407
  else {
408
+ ii->base.ignore_case = ii->index->ignore_case;
404
409
  ii->current = start ? git_index__prefix_position(ii->index, start) : 0;
405
410
  *iter = (git_iterator *)ii;
406
411
  }
@@ -428,12 +433,30 @@ typedef struct {
428
433
  int is_ignored;
429
434
  } workdir_iterator;
430
435
 
431
- static workdir_iterator_frame *workdir_iterator__alloc_frame(void)
436
+ static int git_path_with_stat_cmp_case(const void *a, const void *b)
437
+ {
438
+ const git_path_with_stat *path_with_stat_a = a;
439
+ const git_path_with_stat *path_with_stat_b = b;
440
+
441
+ return strcmp(path_with_stat_a->path, path_with_stat_b->path);
442
+ }
443
+
444
+ static int git_path_with_stat_cmp_icase(const void *a, const void *b)
445
+ {
446
+ const git_path_with_stat *path_with_stat_a = a;
447
+ const git_path_with_stat *path_with_stat_b = b;
448
+
449
+ return strcasecmp(path_with_stat_a->path, path_with_stat_b->path);
450
+ }
451
+
452
+ static workdir_iterator_frame *workdir_iterator__alloc_frame(workdir_iterator *wi)
432
453
  {
433
454
  workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame));
455
+ git_vector_cmp entry_compare = CASESELECT(wi->base.ignore_case, git_path_with_stat_cmp_icase, git_path_with_stat_cmp_case);
456
+
434
457
  if (wf == NULL)
435
458
  return NULL;
436
- if (git_vector_init(&wf->entries, 0, git_path_with_stat_cmp) != 0) {
459
+ if (git_vector_init(&wf->entries, 0, entry_compare) != 0) {
437
460
  git__free(wf);
438
461
  return NULL;
439
462
  }
@@ -453,16 +476,22 @@ static void workdir_iterator__free_frame(workdir_iterator_frame *wf)
453
476
 
454
477
  static int workdir_iterator__update_entry(workdir_iterator *wi);
455
478
 
456
- static int workdir_iterator__entry_cmp(const void *prefix, const void *item)
479
+ static int workdir_iterator__entry_cmp_case(const void *prefix, const void *item)
457
480
  {
458
481
  const git_path_with_stat *ps = item;
459
482
  return git__prefixcmp((const char *)prefix, ps->path);
460
483
  }
461
484
 
485
+ static int workdir_iterator__entry_cmp_icase(const void *prefix, const void *item)
486
+ {
487
+ const git_path_with_stat *ps = item;
488
+ return git__prefixcmp_icase((const char *)prefix, ps->path);
489
+ }
490
+
462
491
  static int workdir_iterator__expand_dir(workdir_iterator *wi)
463
492
  {
464
493
  int error;
465
- workdir_iterator_frame *wf = workdir_iterator__alloc_frame();
494
+ workdir_iterator_frame *wf = workdir_iterator__alloc_frame(wi);
466
495
  GITERR_CHECK_ALLOC(wf);
467
496
 
468
497
  error = git_path_dirload_with_stat(wi->path.ptr, wi->root_len, &wf->entries);
@@ -476,12 +505,15 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi)
476
505
  if (!wi->stack)
477
506
  wf->start = wi->base.start;
478
507
  else if (wi->stack->start &&
479
- git__prefixcmp(wi->stack->start, wi->path.ptr + wi->root_len) == 0)
508
+ ITERATOR_PREFIXCMP(wi->base, wi->stack->start, wi->path.ptr + wi->root_len) == 0)
480
509
  wf->start = wi->stack->start;
481
510
 
482
511
  if (wf->start)
483
512
  git_vector_bsearch3(
484
- &wf->index, &wf->entries, workdir_iterator__entry_cmp, wf->start);
513
+ &wf->index,
514
+ &wf->entries,
515
+ CASESELECT(wi->base.ignore_case, workdir_iterator__entry_cmp_icase, workdir_iterator__entry_cmp_case),
516
+ wf->start);
485
517
 
486
518
  wf->next = wi->stack;
487
519
  wi->stack = wf;
@@ -525,7 +557,9 @@ static int workdir_iterator__advance(
525
557
  while ((wf = wi->stack) != NULL) {
526
558
  next = git_vector_get(&wf->entries, ++wf->index);
527
559
  if (next != NULL) {
528
- if (strcmp(next->path, DOT_GIT "/") == 0)
560
+ /* match git's behavior of ignoring anything named ".git" */
561
+ if (STRCMP_CASESELECT(wi->base.ignore_case, next->path, DOT_GIT "/") == 0 ||
562
+ STRCMP_CASESELECT(wi->base.ignore_case, next->path, DOT_GIT) == 0)
529
563
  continue;
530
564
  /* else found a good entry */
531
565
  break;
@@ -602,13 +636,14 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
602
636
  return -1;
603
637
 
604
638
  if (wi->base.end &&
605
- git__prefixcmp(wi->path.ptr + wi->root_len, wi->base.end) > 0)
639
+ ITERATOR_PREFIXCMP(wi->base, wi->path.ptr + wi->root_len, wi->base.end) > 0)
606
640
  return 0;
607
641
 
608
642
  wi->entry.path = ps->path;
609
643
 
610
- /* skip over .git directory */
611
- if (strcmp(ps->path, DOT_GIT "/") == 0)
644
+ /* skip over .git entry */
645
+ if (STRCMP_CASESELECT(wi->base.ignore_case, ps->path, DOT_GIT "/") == 0 ||
646
+ STRCMP_CASESELECT(wi->base.ignore_case, ps->path, DOT_GIT) == 0)
612
647
  return workdir_iterator__advance((git_iterator *)wi, NULL);
613
648
 
614
649
  /* if there is an error processing the entry, treat as ignored */
@@ -629,15 +664,10 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
629
664
 
630
665
  /* detect submodules */
631
666
  if (S_ISDIR(wi->entry.mode)) {
632
- bool is_submodule = git_path_contains(&wi->path, DOT_GIT);
633
-
634
- /* if there is no .git, still check submodules data */
635
- if (!is_submodule) {
636
- int res = git_submodule_lookup(NULL, wi->repo, wi->entry.path);
637
- is_submodule = (res == 0);
638
- if (res == GIT_ENOTFOUND)
639
- giterr_clear();
640
- }
667
+ int res = git_submodule_lookup(NULL, wi->repo, wi->entry.path);
668
+ bool is_submodule = (res == 0);
669
+ if (res == GIT_ENOTFOUND)
670
+ giterr_clear();
641
671
 
642
672
  /* if submodule, mark as GITLINK and remove trailing slash */
643
673
  if (is_submodule) {
@@ -659,19 +689,28 @@ int git_iterator_for_workdir_range(
659
689
  {
660
690
  int error;
661
691
  workdir_iterator *wi;
692
+ git_index *index;
662
693
 
663
694
  assert(iter && repo);
664
695
 
665
- if (git_repository_is_bare(repo)) {
666
- giterr_set(GITERR_INVALID,
667
- "Cannot scan working directory for bare repo");
668
- return -1;
669
- }
696
+ if ((error = git_repository__ensure_not_bare(repo, "scan working directory")) < 0)
697
+ return error;
670
698
 
671
699
  ITERATOR_BASE_INIT(wi, workdir, WORKDIR);
672
700
 
673
701
  wi->repo = repo;
674
702
 
703
+ if ((error = git_repository_index(&index, repo)) < 0) {
704
+ git__free(wi);
705
+ return error;
706
+ }
707
+
708
+ /* Set the ignore_case flag for the workdir iterator to match
709
+ * that of the index. */
710
+ wi->base.ignore_case = index->ignore_case;
711
+
712
+ git_index_free(index);
713
+
675
714
  if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 ||
676
715
  git_path_to_dir(&wi->path) < 0 ||
677
716
  git_ignore__for_path(repo, "", &wi->ignores) < 0)
@@ -696,6 +735,129 @@ int git_iterator_for_workdir_range(
696
735
  return error;
697
736
  }
698
737
 
738
+ typedef struct {
739
+ git_iterator base;
740
+ git_iterator *wrapped;
741
+ git_vector entries;
742
+ git_vector_cmp comparer;
743
+ git_pool entry_pool;
744
+ git_pool string_pool;
745
+ unsigned int position;
746
+ } spoolandsort_iterator;
747
+
748
+ static int spoolandsort_iterator__current(
749
+ git_iterator *self, const git_index_entry **entry)
750
+ {
751
+ spoolandsort_iterator *si = (spoolandsort_iterator *)self;
752
+
753
+ if (si->position < si->entries.length)
754
+ *entry = (const git_index_entry *)git_vector_get_const(&si->entries, si->position);
755
+ else
756
+ *entry = NULL;
757
+
758
+ return 0;
759
+ }
760
+
761
+ static int spoolandsort_iterator__at_end(git_iterator *self)
762
+ {
763
+ spoolandsort_iterator *si = (spoolandsort_iterator *)self;
764
+
765
+ return 0 == si->entries.length || si->entries.length - 1 <= si->position;
766
+ }
767
+
768
+ static int spoolandsort_iterator__advance(
769
+ git_iterator *self, const git_index_entry **entry)
770
+ {
771
+ spoolandsort_iterator *si = (spoolandsort_iterator *)self;
772
+
773
+ if (si->position < si->entries.length)
774
+ *entry = (const git_index_entry *)git_vector_get_const(&si->entries, ++si->position);
775
+ else
776
+ *entry = NULL;
777
+
778
+ return 0;
779
+ }
780
+
781
+ static int spoolandsort_iterator__seek(git_iterator *self, const char *prefix)
782
+ {
783
+ GIT_UNUSED(self);
784
+ GIT_UNUSED(prefix);
785
+
786
+ return -1;
787
+ }
788
+
789
+ static int spoolandsort_iterator__reset(git_iterator *self)
790
+ {
791
+ spoolandsort_iterator *si = (spoolandsort_iterator *)self;
792
+
793
+ si->position = 0;
794
+
795
+ return 0;
796
+ }
797
+
798
+ static void spoolandsort_iterator__free(git_iterator *self)
799
+ {
800
+ spoolandsort_iterator *si = (spoolandsort_iterator *)self;
801
+
802
+ git_pool_clear(&si->string_pool);
803
+ git_pool_clear(&si->entry_pool);
804
+ git_vector_free(&si->entries);
805
+ git_iterator_free(si->wrapped);
806
+ }
807
+
808
+ int git_iterator_spoolandsort_range(
809
+ git_iterator **iter,
810
+ git_iterator *towrap,
811
+ git_vector_cmp comparer,
812
+ bool ignore_case,
813
+ const char *start,
814
+ const char *end)
815
+ {
816
+ spoolandsort_iterator *si;
817
+ const git_index_entry *item;
818
+
819
+ assert(iter && towrap && comparer);
820
+
821
+ ITERATOR_BASE_INIT(si, spoolandsort, SPOOLANDSORT);
822
+ si->base.ignore_case = ignore_case;
823
+ si->wrapped = towrap;
824
+ si->comparer = comparer;
825
+ si->position = 0;
826
+
827
+ if (git_vector_init(&si->entries, 16, si->comparer) < 0 ||
828
+ git_iterator_current(towrap, &item) < 0 ||
829
+ git_pool_init(&si->entry_pool, sizeof(git_index_entry), 0) ||
830
+ git_pool_init(&si->string_pool, 1, 0))
831
+ {
832
+ git__free(si);
833
+ return -1;
834
+ }
835
+
836
+ while (item)
837
+ {
838
+ git_index_entry *clone = git_pool_malloc(&si->entry_pool, 1);
839
+ memcpy(clone, item, sizeof(git_index_entry));
840
+
841
+ if (item->path)
842
+ {
843
+ clone->path = git_pool_strdup(&si->string_pool, item->path);
844
+ }
845
+
846
+ git_vector_insert(&si->entries, clone);
847
+
848
+ if (git_iterator_advance(towrap, &item) < 0)
849
+ {
850
+ git__free(si);
851
+ return -1;
852
+ }
853
+ }
854
+
855
+ git_vector_sort(&si->entries);
856
+
857
+ *iter = (git_iterator *)si;
858
+
859
+ return 0;
860
+ }
699
861
 
700
862
  int git_iterator_current_tree_entry(
701
863
  git_iterator *iter, const git_tree_entry **tree_entry)
@@ -705,6 +867,45 @@ int git_iterator_current_tree_entry(
705
867
  return 0;
706
868
  }
707
869
 
870
+ int git_iterator_current_parent_tree(
871
+ git_iterator *iter,
872
+ const char *parent_path,
873
+ const git_tree **tree_ptr)
874
+ {
875
+ tree_iterator *ti = (tree_iterator *)iter;
876
+ tree_iterator_frame *tf;
877
+ const char *scan = parent_path;
878
+
879
+ if (iter->type != GIT_ITERATOR_TREE || ti->stack == NULL)
880
+ goto notfound;
881
+
882
+ for (tf = ti->tail; tf != NULL; tf = tf->prev) {
883
+ const git_tree_entry *te;
884
+
885
+ if (!*scan) {
886
+ *tree_ptr = tf->tree;
887
+ return 0;
888
+ }
889
+
890
+ te = git_tree_entry_byindex(tf->tree, tf->index);
891
+
892
+ if (strncmp(scan, te->filename, te->filename_len) != 0)
893
+ goto notfound;
894
+
895
+ scan += te->filename_len;
896
+
897
+ if (*scan) {
898
+ if (*scan != '/')
899
+ goto notfound;
900
+ scan++;
901
+ }
902
+ }
903
+
904
+ notfound:
905
+ *tree_ptr = NULL;
906
+ return 0;
907
+ }
908
+
708
909
  int git_iterator_current_is_ignored(git_iterator *iter)
709
910
  {
710
911
  return (iter->type != GIT_ITERATOR_WORKDIR) ? 0 :
@@ -743,6 +944,18 @@ int git_iterator_cmp(
743
944
  if (!path_prefix)
744
945
  return -1;
745
946
 
746
- return git__prefixcmp(entry->path, path_prefix);
947
+ return ITERATOR_PREFIXCMP(*iter, entry->path, path_prefix);
948
+ }
949
+
950
+ int git_iterator_current_workdir_path(git_iterator *iter, git_buf **path)
951
+ {
952
+ workdir_iterator *wi = (workdir_iterator *)iter;
953
+
954
+ if (iter->type != GIT_ITERATOR_WORKDIR || !wi->entry.path)
955
+ *path = NULL;
956
+ else
957
+ *path = &wi->path;
958
+
959
+ return 0;
747
960
  }
748
961