rugged 0.22.2 → 0.23.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged.c +1 -2
  3. data/ext/rugged/rugged_branch_collection.c +6 -44
  4. data/ext/rugged/rugged_config.c +7 -3
  5. data/ext/rugged/rugged_diff_delta.c +1 -1
  6. data/ext/rugged/rugged_diff_line.c +1 -1
  7. data/ext/rugged/rugged_object.c +2 -2
  8. data/ext/rugged/rugged_reference_collection.c +12 -56
  9. data/ext/rugged/rugged_remote.c +4 -33
  10. data/ext/rugged/rugged_remote_collection.c +1 -1
  11. data/ext/rugged/rugged_repo.c +10 -36
  12. data/ext/rugged/rugged_settings.c +3 -3
  13. data/ext/rugged/rugged_tree.c +1 -1
  14. data/lib/rugged/version.rb +1 -1
  15. data/vendor/libgit2/CMakeLists.txt +10 -3
  16. data/vendor/libgit2/COPYING +15 -21
  17. data/vendor/libgit2/include/git2/annotated_commit.h +20 -3
  18. data/vendor/libgit2/include/git2/branch.h +20 -16
  19. data/vendor/libgit2/include/git2/checkout.h +32 -18
  20. data/vendor/libgit2/include/git2/cherrypick.h +2 -2
  21. data/vendor/libgit2/include/git2/clone.h +4 -10
  22. data/vendor/libgit2/include/git2/config.h +66 -12
  23. data/vendor/libgit2/include/git2/describe.h +3 -2
  24. data/vendor/libgit2/include/git2/diff.h +3 -3
  25. data/vendor/libgit2/include/git2/errors.h +1 -0
  26. data/vendor/libgit2/include/git2/filter.h +21 -5
  27. data/vendor/libgit2/include/git2/index.h +32 -0
  28. data/vendor/libgit2/include/git2/merge.h +20 -3
  29. data/vendor/libgit2/include/git2/oid.h +1 -1
  30. data/vendor/libgit2/include/git2/pack.h +13 -0
  31. data/vendor/libgit2/include/git2/patch.h +3 -6
  32. data/vendor/libgit2/include/git2/rebase.h +8 -12
  33. data/vendor/libgit2/include/git2/refs.h +19 -29
  34. data/vendor/libgit2/include/git2/remote.h +5 -11
  35. data/vendor/libgit2/include/git2/repository.h +44 -15
  36. data/vendor/libgit2/include/git2/reset.h +19 -10
  37. data/vendor/libgit2/include/git2/revert.h +2 -2
  38. data/vendor/libgit2/include/git2/submodule.h +3 -9
  39. data/vendor/libgit2/include/git2/sys/config.h +3 -1
  40. data/vendor/libgit2/include/git2/sys/filter.h +10 -2
  41. data/vendor/libgit2/include/git2/sys/hashsig.h +49 -22
  42. data/vendor/libgit2/include/git2/transport.h +1 -1
  43. data/vendor/libgit2/include/git2/types.h +10 -3
  44. data/vendor/libgit2/include/git2/version.h +3 -2
  45. data/vendor/libgit2/src/annotated_commit.c +28 -0
  46. data/vendor/libgit2/src/array.h +19 -8
  47. data/vendor/libgit2/src/attr.c +95 -35
  48. data/vendor/libgit2/src/attr_file.c +51 -17
  49. data/vendor/libgit2/src/attr_file.h +37 -10
  50. data/vendor/libgit2/src/attrcache.c +13 -7
  51. data/vendor/libgit2/src/attrcache.h +1 -0
  52. data/vendor/libgit2/src/blame.c +26 -2
  53. data/vendor/libgit2/src/blame_git.c +6 -2
  54. data/vendor/libgit2/src/blob.c +6 -8
  55. data/vendor/libgit2/src/branch.c +55 -43
  56. data/vendor/libgit2/src/buf_text.c +13 -6
  57. data/vendor/libgit2/src/buffer.c +110 -25
  58. data/vendor/libgit2/src/buffer.h +18 -0
  59. data/vendor/libgit2/src/checkout.c +164 -92
  60. data/vendor/libgit2/src/checkout.h +0 -7
  61. data/vendor/libgit2/src/cherrypick.c +13 -7
  62. data/vendor/libgit2/src/clone.c +23 -25
  63. data/vendor/libgit2/src/commit.c +3 -3
  64. data/vendor/libgit2/src/common.h +23 -1
  65. data/vendor/libgit2/src/config.c +137 -19
  66. data/vendor/libgit2/src/config.h +2 -2
  67. data/vendor/libgit2/src/config_cache.c +2 -1
  68. data/vendor/libgit2/src/config_file.c +39 -18
  69. data/vendor/libgit2/src/config_file.h +1 -1
  70. data/vendor/libgit2/src/crlf.c +1 -1
  71. data/vendor/libgit2/src/delta-apply.c +3 -2
  72. data/vendor/libgit2/src/delta.c +25 -6
  73. data/vendor/libgit2/src/describe.c +2 -0
  74. data/vendor/libgit2/src/diff.c +8 -5
  75. data/vendor/libgit2/src/diff_driver.c +39 -18
  76. data/vendor/libgit2/src/diff_file.c +1 -1
  77. data/vendor/libgit2/src/diff_patch.c +12 -6
  78. data/vendor/libgit2/src/diff_tform.c +21 -24
  79. data/vendor/libgit2/src/filebuf.c +14 -12
  80. data/vendor/libgit2/src/fileops.c +61 -18
  81. data/vendor/libgit2/src/fileops.h +11 -2
  82. data/vendor/libgit2/src/filter.c +351 -99
  83. data/vendor/libgit2/src/filter.h +17 -0
  84. data/vendor/libgit2/src/global.c +38 -9
  85. data/vendor/libgit2/src/hash/hash_generic.c +1 -1
  86. data/vendor/libgit2/src/hashsig.c +28 -16
  87. data/vendor/libgit2/src/ignore.c +2 -2
  88. data/vendor/libgit2/src/index.c +159 -42
  89. data/vendor/libgit2/src/index.h +29 -0
  90. data/vendor/libgit2/src/indexer.c +11 -2
  91. data/vendor/libgit2/src/integer.h +96 -0
  92. data/vendor/libgit2/src/iterator.c +5 -3
  93. data/vendor/libgit2/src/khash.h +41 -29
  94. data/vendor/libgit2/src/merge.c +48 -35
  95. data/vendor/libgit2/src/merge.h +0 -1
  96. data/vendor/libgit2/src/merge_file.c +13 -0
  97. data/vendor/libgit2/src/mwindow.c +1 -1
  98. data/vendor/libgit2/src/notes.c +1 -1
  99. data/vendor/libgit2/src/odb.c +13 -11
  100. data/vendor/libgit2/src/odb_loose.c +22 -10
  101. data/vendor/libgit2/src/odb_mempack.c +4 -2
  102. data/vendor/libgit2/src/offmap.h +3 -2
  103. data/vendor/libgit2/src/oid.c +1 -1
  104. data/vendor/libgit2/src/oidmap.h +2 -1
  105. data/vendor/libgit2/src/openssl_stream.c +6 -3
  106. data/vendor/libgit2/src/pack-objects.c +273 -12
  107. data/vendor/libgit2/src/pack-objects.h +10 -0
  108. data/vendor/libgit2/src/pack.c +17 -6
  109. data/vendor/libgit2/src/pack.h +1 -3
  110. data/vendor/libgit2/src/path.c +68 -38
  111. data/vendor/libgit2/src/pathspec.c +3 -0
  112. data/vendor/libgit2/src/pool.c +9 -8
  113. data/vendor/libgit2/src/posix.c +11 -1
  114. data/vendor/libgit2/src/push.c +15 -17
  115. data/vendor/libgit2/src/push.h +1 -6
  116. data/vendor/libgit2/src/rebase.c +77 -35
  117. data/vendor/libgit2/src/refdb_fs.c +2 -2
  118. data/vendor/libgit2/src/refs.c +107 -81
  119. data/vendor/libgit2/src/refs.h +2 -2
  120. data/vendor/libgit2/src/refspec.c +3 -0
  121. data/vendor/libgit2/src/remote.c +19 -21
  122. data/vendor/libgit2/src/repository.c +258 -67
  123. data/vendor/libgit2/src/repository.h +31 -16
  124. data/vendor/libgit2/src/reset.c +28 -12
  125. data/vendor/libgit2/src/revert.c +12 -7
  126. data/vendor/libgit2/src/revwalk.c +3 -5
  127. data/vendor/libgit2/src/revwalk.h +1 -1
  128. data/vendor/libgit2/src/sortedcache.c +5 -3
  129. data/vendor/libgit2/src/stash.c +3 -5
  130. data/vendor/libgit2/src/strmap.h +2 -1
  131. data/vendor/libgit2/src/submodule.c +5 -6
  132. data/vendor/libgit2/src/tag.c +7 -5
  133. data/vendor/libgit2/src/transaction.c +1 -1
  134. data/vendor/libgit2/src/transports/cred.c +5 -2
  135. data/vendor/libgit2/src/transports/git.c +2 -3
  136. data/vendor/libgit2/src/transports/local.c +15 -34
  137. data/vendor/libgit2/src/transports/smart.c +1 -1
  138. data/vendor/libgit2/src/transports/smart_pkt.c +58 -18
  139. data/vendor/libgit2/src/transports/smart_protocol.c +2 -2
  140. data/vendor/libgit2/src/transports/winhttp.c +2 -2
  141. data/vendor/libgit2/src/tree.c +7 -5
  142. data/vendor/libgit2/src/tsort.c +3 -1
  143. data/vendor/libgit2/src/util.c +25 -0
  144. data/vendor/libgit2/src/util.h +31 -27
  145. data/vendor/libgit2/src/vector.c +2 -7
  146. data/vendor/libgit2/src/win32/dir.c +5 -3
  147. data/vendor/libgit2/src/win32/git2.rc +8 -4
  148. data/vendor/libgit2/src/win32/mingw-compat.h +7 -0
  149. data/vendor/libgit2/src/win32/msvc-compat.h +3 -0
  150. data/vendor/libgit2/src/win32/posix.h +1 -3
  151. data/vendor/libgit2/src/win32/posix_w32.c +31 -7
  152. data/vendor/libgit2/src/win32/utf-conv.c +1 -3
  153. data/vendor/libgit2/src/zstream.c +1 -1
  154. metadata +5 -5
  155. data/vendor/libgit2/src/bswap.h +0 -97
@@ -292,7 +292,7 @@ GIT_EXTERN(int) git_cred_username_new(git_cred **cred, const char *username);
292
292
  *
293
293
  * - cred: The newly created credential object.
294
294
  * - url: The resource for which we are demanding a credential.
295
- * - username_from_url: The username that was embedded in a "user@host"
295
+ * - username_from_url: The username that was embedded in a "user\@host"
296
296
  * remote url, or NULL if not included.
297
297
  * - allowed_types: A bitmask stating which cred types are OK to return.
298
298
  * - payload: The payload provided when specifying this callback.
@@ -302,9 +302,7 @@ typedef struct {
302
302
  /**
303
303
  * Callback for the user's custom certificate checks.
304
304
  *
305
- * @param type The type of certificate or host info, SSH or X.509
306
- * @param data The data for the certificate or host info
307
- * @param len The size of the certificate or host info
305
+ * @param cert The host certificate
308
306
  * @param valid Whether the libgit2 checks (OpenSSL or WinHTTP) think
309
307
  * this certificate is valid
310
308
  * @param host Hostname of the host libgit2 connected to
@@ -412,6 +410,15 @@ typedef enum {
412
410
  GIT_SUBMODULE_RECURSE_ONDEMAND = 2,
413
411
  } git_submodule_recurse_t;
414
412
 
413
+ /** A type to write in a streaming fashion, for example, for filters. */
414
+ typedef struct git_writestream git_writestream;
415
+
416
+ struct git_writestream {
417
+ int (*write)(git_writestream *stream, const char *buffer, size_t len);
418
+ int (*close)(git_writestream *stream);
419
+ void (*free)(git_writestream *stream);
420
+ };
421
+
415
422
  /** @} */
416
423
  GIT_END_DECL
417
424
 
@@ -7,10 +7,11 @@
7
7
  #ifndef INCLUDE_git_version_h__
8
8
  #define INCLUDE_git_version_h__
9
9
 
10
- #define LIBGIT2_VERSION "0.22.2"
10
+ #define LIBGIT2_VERSION "0.22.0"
11
11
  #define LIBGIT2_VER_MAJOR 0
12
12
  #define LIBGIT2_VER_MINOR 22
13
- #define LIBGIT2_VER_REVISION 2
13
+ #define LIBGIT2_VER_REVISION 0
14
+ #define LIBGIT2_VER_PATCH 0
14
15
 
15
16
  #define LIBGIT2_SOVERSION 22
16
17
 
@@ -12,6 +12,7 @@
12
12
  #include "git2/refs.h"
13
13
  #include "git2/repository.h"
14
14
  #include "git2/annotated_commit.h"
15
+ #include "git2/revparse.h"
15
16
 
16
17
  static int annotated_commit_init(
17
18
  git_annotated_commit **out,
@@ -96,6 +97,33 @@ int git_annotated_commit_from_fetchhead(
96
97
  return annotated_commit_init(out, repo, id, branch_name, remote_url);
97
98
  }
98
99
 
100
+ int git_annotated_commit_from_revspec(
101
+ git_annotated_commit **out,
102
+ git_repository *repo,
103
+ const char *revspec)
104
+ {
105
+ git_object *obj, *commit;
106
+ int error;
107
+
108
+ assert(out && repo && revspec);
109
+
110
+ if ((error = git_revparse_single(&obj, repo, revspec)) < 0)
111
+ return error;
112
+
113
+ if ((error = git_object_peel(&commit, obj, GIT_OBJ_COMMIT))) {
114
+ git_object_free(obj);
115
+ return error;
116
+ }
117
+
118
+ error = annotated_commit_init(out, repo, git_object_id(commit), revspec, NULL);
119
+
120
+ git_object_free(obj);
121
+ git_object_free(commit);
122
+
123
+ return error;
124
+ }
125
+
126
+
99
127
  const git_oid *git_annotated_commit_id(
100
128
  const git_annotated_commit *annotated_commit)
101
129
  {
@@ -23,7 +23,7 @@
23
23
  *
24
24
  * typedef git_array_t(my_struct) my_struct_array_t;
25
25
  */
26
- #define git_array_t(type) struct { type *ptr; uint32_t size, asize; }
26
+ #define git_array_t(type) struct { type *ptr; size_t size, asize; }
27
27
 
28
28
  #define GIT_ARRAY_INIT { NULL, 0, 0 }
29
29
 
@@ -45,15 +45,26 @@ typedef git_array_t(char) git_array_generic_t;
45
45
  GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
46
46
  {
47
47
  volatile git_array_generic_t *a = _a;
48
- uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2;
49
- char *new_array = git__realloc(a->ptr, new_size * item_size);
50
- if (!new_array) {
51
- git_array_clear(*a);
52
- return NULL;
48
+ size_t new_size;
49
+ char *new_array;
50
+
51
+ if (a->size < 8) {
52
+ new_size = 8;
53
53
  } else {
54
- a->ptr = new_array; a->asize = new_size; a->size++;
55
- return a->ptr + (a->size - 1) * item_size;
54
+ if (GIT_MULTIPLY_SIZET_OVERFLOW(&new_size, a->size, 3))
55
+ goto on_oom;
56
+ new_size /= 2;
56
57
  }
58
+
59
+ if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL)
60
+ goto on_oom;
61
+
62
+ a->ptr = new_array; a->asize = new_size; a->size++;
63
+ return a->ptr + (a->size - 1) * item_size;
64
+
65
+ on_oom:
66
+ git_array_clear(*a);
67
+ return NULL;
57
68
  }
58
69
 
59
70
  #define git_array_alloc(a) \
@@ -7,7 +7,7 @@
7
7
  #include "git2/oid.h"
8
8
  #include <ctype.h>
9
9
 
10
- GIT__USE_STRMAP;
10
+ GIT__USE_STRMAP
11
11
 
12
12
  const char *git_attr__true = "[internal]__TRUE__";
13
13
  const char *git_attr__false = "[internal]__FALSE__";
@@ -29,6 +29,7 @@ git_attr_t git_attr_value(const char *attr)
29
29
 
30
30
  static int collect_attr_files(
31
31
  git_repository *repo,
32
+ git_attr_session *attr_session,
32
33
  uint32_t flags,
33
34
  const char *path,
34
35
  git_vector *files);
@@ -57,7 +58,7 @@ int git_attr_get(
57
58
  if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
58
59
  return -1;
59
60
 
60
- if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
61
+ if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0)
61
62
  goto cleanup;
62
63
 
63
64
  memset(&attr, 0, sizeof(attr));
@@ -90,9 +91,10 @@ typedef struct {
90
91
  git_attr_assignment *found;
91
92
  } attr_get_many_info;
92
93
 
93
- int git_attr_get_many(
94
+ int git_attr_get_many_with_session(
94
95
  const char **values,
95
96
  git_repository *repo,
97
+ git_attr_session *attr_session,
96
98
  uint32_t flags,
97
99
  const char *pathname,
98
100
  size_t num_attr,
@@ -115,7 +117,7 @@ int git_attr_get_many(
115
117
  if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
116
118
  return -1;
117
119
 
118
- if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
120
+ if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
119
121
  goto cleanup;
120
122
 
121
123
  info = git__calloc(num_attr, sizeof(attr_get_many_info));
@@ -161,6 +163,17 @@ cleanup:
161
163
  return error;
162
164
  }
163
165
 
166
+ int git_attr_get_many(
167
+ const char **values,
168
+ git_repository *repo,
169
+ uint32_t flags,
170
+ const char *pathname,
171
+ size_t num_attr,
172
+ const char **names)
173
+ {
174
+ return git_attr_get_many_with_session(
175
+ values, repo, NULL, flags, pathname, num_attr, names);
176
+ }
164
177
 
165
178
  int git_attr_foreach(
166
179
  git_repository *repo,
@@ -183,7 +196,7 @@ int git_attr_foreach(
183
196
  if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
184
197
  return -1;
185
198
 
186
- if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0 ||
199
+ if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||
187
200
  (error = git_strmap_alloc(&seen)) < 0)
188
201
  goto cleanup;
189
202
 
@@ -219,6 +232,7 @@ cleanup:
219
232
 
220
233
  static int preload_attr_file(
221
234
  git_repository *repo,
235
+ git_attr_session *attr_session,
222
236
  git_attr_file_source source,
223
237
  const char *base,
224
238
  const char *file)
@@ -229,19 +243,60 @@ static int preload_attr_file(
229
243
  if (!file)
230
244
  return 0;
231
245
  if (!(error = git_attr_cache__get(
232
- &preload, repo, source, base, file, git_attr_file__parse_buffer)))
246
+ &preload, repo, attr_session, source, base, file, git_attr_file__parse_buffer)))
233
247
  git_attr_file__free(preload);
234
248
 
235
249
  return error;
236
250
  }
237
251
 
238
- static int attr_setup(git_repository *repo)
252
+ static int system_attr_file(
253
+ git_buf *out,
254
+ git_attr_session *attr_session)
255
+ {
256
+ int error;
257
+
258
+ if (!attr_session) {
259
+ error = git_sysdir_find_system_file(out, GIT_ATTR_FILE_SYSTEM);
260
+
261
+ if (error == GIT_ENOTFOUND)
262
+ giterr_clear();
263
+
264
+ return error;
265
+ }
266
+
267
+ if (!attr_session->init_sysdir) {
268
+ error = git_sysdir_find_system_file(&attr_session->sysdir, GIT_ATTR_FILE_SYSTEM);
269
+
270
+ if (error == GIT_ENOTFOUND)
271
+ giterr_clear();
272
+ else if (error)
273
+ return error;
274
+
275
+ attr_session->init_sysdir = 1;
276
+ }
277
+
278
+ if (attr_session->sysdir.size == 0)
279
+ return GIT_ENOTFOUND;
280
+
281
+ /* We can safely provide a git_buf with no allocation (asize == 0) to
282
+ * a consumer. This allows them to treat this as a regular `git_buf`,
283
+ * but their call to `git_buf_free` will not attempt to free it.
284
+ */
285
+ git_buf_attach_notowned(
286
+ out, attr_session->sysdir.ptr, attr_session->sysdir.size);
287
+ return 0;
288
+ }
289
+
290
+ static int attr_setup(git_repository *repo, git_attr_session *attr_session)
239
291
  {
240
292
  int error = 0;
241
293
  const char *workdir = git_repository_workdir(repo);
242
294
  git_index *idx = NULL;
243
295
  git_buf sys = GIT_BUF_INIT;
244
296
 
297
+ if (attr_session && attr_session->init_setup)
298
+ return 0;
299
+
245
300
  if ((error = git_attr_cache__init(repo)) < 0)
246
301
  return error;
247
302
 
@@ -249,39 +304,39 @@ static int attr_setup(git_repository *repo)
249
304
  * definitions will be available for later file parsing
250
305
  */
251
306
 
252
- if (!(error = git_sysdir_find_system_file(&sys, GIT_ATTR_FILE_SYSTEM))) {
307
+ error = system_attr_file(&sys, attr_session);
308
+
309
+ if (error == 0)
253
310
  error = preload_attr_file(
254
- repo, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
255
- git_buf_free(&sys);
256
- }
257
- if (error < 0) {
258
- if (error == GIT_ENOTFOUND) {
259
- giterr_clear();
260
- error = 0;
261
- } else
262
- return error;
263
- }
311
+ repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
312
+ else if (error != GIT_ENOTFOUND)
313
+ return error;
314
+
315
+ git_buf_free(&sys);
264
316
 
265
317
  if ((error = preload_attr_file(
266
- repo, GIT_ATTR_FILE__FROM_FILE,
318
+ repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
267
319
  NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
268
320
  return error;
269
321
 
270
322
  if ((error = preload_attr_file(
271
- repo, GIT_ATTR_FILE__FROM_FILE,
323
+ repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
272
324
  git_repository_path(repo), GIT_ATTR_FILE_INREPO)) < 0)
273
325
  return error;
274
326
 
275
327
  if (workdir != NULL &&
276
328
  (error = preload_attr_file(
277
- repo, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
329
+ repo, attr_session, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
278
330
  return error;
279
331
 
280
332
  if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
281
333
  (error = preload_attr_file(
282
- repo, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
334
+ repo, attr_session, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
283
335
  return error;
284
336
 
337
+ if (attr_session)
338
+ attr_session->init_setup = 1;
339
+
285
340
  return error;
286
341
  }
287
342
 
@@ -321,6 +376,7 @@ int git_attr_add_macro(
321
376
 
322
377
  typedef struct {
323
378
  git_repository *repo;
379
+ git_attr_session *attr_session;
324
380
  uint32_t flags;
325
381
  const char *workdir;
326
382
  git_index *index;
@@ -356,6 +412,7 @@ static int attr_decide_sources(
356
412
 
357
413
  static int push_attr_file(
358
414
  git_repository *repo,
415
+ git_attr_session *attr_session,
359
416
  git_vector *list,
360
417
  git_attr_file_source source,
361
418
  const char *base,
@@ -364,8 +421,9 @@ static int push_attr_file(
364
421
  int error = 0;
365
422
  git_attr_file *file = NULL;
366
423
 
367
- error = git_attr_cache__get(
368
- &file, repo, source, base, filename, git_attr_file__parse_buffer);
424
+ error = git_attr_cache__get(&file, repo, attr_session,
425
+ source, base, filename, git_attr_file__parse_buffer);
426
+
369
427
  if (error < 0)
370
428
  return error;
371
429
 
@@ -387,8 +445,8 @@ static int push_one_attr(void *ref, const char *path)
387
445
  info->flags, info->workdir != NULL, info->index != NULL, src);
388
446
 
389
447
  for (i = 0; !error && i < n_src; ++i)
390
- error = push_attr_file(
391
- info->repo, info->files, src[i], path, GIT_ATTR_FILE);
448
+ error = push_attr_file(info->repo, info->attr_session,
449
+ info->files, src[i], path, GIT_ATTR_FILE);
392
450
 
393
451
  return error;
394
452
  }
@@ -407,6 +465,7 @@ static void release_attr_files(git_vector *files)
407
465
 
408
466
  static int collect_attr_files(
409
467
  git_repository *repo,
468
+ git_attr_session *attr_session,
410
469
  uint32_t flags,
411
470
  const char *path,
412
471
  git_vector *files)
@@ -416,7 +475,7 @@ static int collect_attr_files(
416
475
  const char *workdir = git_repository_workdir(repo);
417
476
  attr_walk_up_info info = { NULL };
418
477
 
419
- if ((error = attr_setup(repo)) < 0)
478
+ if ((error = attr_setup(repo, attr_session)) < 0)
420
479
  return error;
421
480
 
422
481
  /* Resolve path in a non-bare repo */
@@ -435,12 +494,13 @@ static int collect_attr_files(
435
494
  */
436
495
 
437
496
  error = push_attr_file(
438
- repo, files, GIT_ATTR_FILE__FROM_FILE,
497
+ repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
439
498
  git_repository_path(repo), GIT_ATTR_FILE_INREPO);
440
499
  if (error < 0)
441
500
  goto cleanup;
442
501
 
443
- info.repo = repo;
502
+ info.repo = repo;
503
+ info.attr_session = attr_session;
444
504
  info.flags = flags;
445
505
  info.workdir = workdir;
446
506
  if (git_repository_index__weakptr(&info.index, repo) < 0)
@@ -457,21 +517,21 @@ static int collect_attr_files(
457
517
 
458
518
  if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
459
519
  error = push_attr_file(
460
- repo, files, GIT_ATTR_FILE__FROM_FILE,
520
+ repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
461
521
  NULL, git_repository_attr_cache(repo)->cfg_attr_file);
462
522
  if (error < 0)
463
523
  goto cleanup;
464
524
  }
465
525
 
466
526
  if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
467
- error = git_sysdir_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
527
+ error = system_attr_file(&dir, attr_session);
528
+
468
529
  if (!error)
469
530
  error = push_attr_file(
470
- repo, files, GIT_ATTR_FILE__FROM_FILE, NULL, dir.ptr);
471
- else if (error == GIT_ENOTFOUND) {
472
- giterr_clear();
531
+ repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
532
+ NULL, dir.ptr);
533
+ else if (error == GIT_ENOTFOUND)
473
534
  error = 0;
474
- }
475
535
  }
476
536
 
477
537
  cleanup:
@@ -96,6 +96,7 @@ static int attr_file_oid_from_index(
96
96
  int git_attr_file__load(
97
97
  git_attr_file **out,
98
98
  git_repository *repo,
99
+ git_attr_session *attr_session,
99
100
  git_attr_file_entry *entry,
100
101
  git_attr_file_source source,
101
102
  git_attr_file_parser parser)
@@ -105,6 +106,7 @@ int git_attr_file__load(
105
106
  git_buf content = GIT_BUF_INIT;
106
107
  git_attr_file *file;
107
108
  struct stat st;
109
+ bool nonexistent = false;
108
110
 
109
111
  *out = NULL;
110
112
 
@@ -127,22 +129,16 @@ int git_attr_file__load(
127
129
  case GIT_ATTR_FILE__FROM_FILE: {
128
130
  int fd;
129
131
 
130
- if (p_stat(entry->fullpath, &st) < 0)
131
- return git_path_set_error(errno, entry->fullpath, "stat");
132
- if (S_ISDIR(st.st_mode))
133
- return GIT_ENOTFOUND;
134
-
135
- /* For open or read errors, return ENOTFOUND to skip item */
132
+ /* For open or read errors, pretend that we got ENOTFOUND. */
136
133
  /* TODO: issue warning when warning API is available */
137
134
 
138
- if ((fd = git_futils_open_ro(entry->fullpath)) < 0)
139
- return GIT_ENOTFOUND;
140
-
141
- error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size);
142
- p_close(fd);
143
-
144
- if (error < 0)
145
- return GIT_ENOTFOUND;
135
+ if (p_stat(entry->fullpath, &st) < 0 ||
136
+ S_ISDIR(st.st_mode) ||
137
+ (fd = git_futils_open_ro(entry->fullpath)) < 0 ||
138
+ (error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size)) < 0)
139
+ nonexistent = true;
140
+ else
141
+ p_close(fd);
146
142
 
147
143
  break;
148
144
  }
@@ -154,13 +150,21 @@ int git_attr_file__load(
154
150
  if ((error = git_attr_file__new(&file, entry, source)) < 0)
155
151
  goto cleanup;
156
152
 
153
+ /* store the key of the attr_reader; don't bother with cache
154
+ * invalidation during the same attr reader session.
155
+ */
156
+ if (attr_session)
157
+ file->session_key = attr_session->key;
158
+
157
159
  if (parser && (error = parser(repo, file, git_buf_cstr(&content))) < 0) {
158
160
  git_attr_file__free(file);
159
161
  goto cleanup;
160
162
  }
161
163
 
162
- /* write cache breaker */
163
- if (source == GIT_ATTR_FILE__FROM_INDEX)
164
+ /* write cache breakers */
165
+ if (nonexistent)
166
+ file->nonexistent = 1;
167
+ else if (source == GIT_ATTR_FILE__FROM_INDEX)
164
168
  git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
165
169
  else if (source == GIT_ATTR_FILE__FROM_FILE)
166
170
  git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
@@ -175,11 +179,22 @@ cleanup:
175
179
  return error;
176
180
  }
177
181
 
178
- int git_attr_file__out_of_date(git_repository *repo, git_attr_file *file)
182
+ int git_attr_file__out_of_date(
183
+ git_repository *repo,
184
+ git_attr_session *attr_session,
185
+ git_attr_file *file)
179
186
  {
180
187
  if (!file)
181
188
  return 1;
182
189
 
190
+ /* we are never out of date if we just created this data in the same
191
+ * attr_session; otherwise, nonexistent files must be invalidated
192
+ */
193
+ if (attr_session && attr_session->key == file->session_key)
194
+ return 0;
195
+ else if (file->nonexistent)
196
+ return 1;
197
+
183
198
  switch (file->source) {
184
199
  case GIT_ATTR_FILE__IN_MEMORY:
185
200
  return 0;
@@ -831,3 +846,22 @@ void git_attr_rule__free(git_attr_rule *rule)
831
846
  git__free(rule);
832
847
  }
833
848
 
849
+ int git_attr_session__init(git_attr_session *session, git_repository *repo)
850
+ {
851
+ assert(repo);
852
+
853
+ session->key = git_atomic_inc(&repo->attr_session_key);
854
+
855
+ return 0;
856
+ }
857
+
858
+ void git_attr_session__free(git_attr_session *session)
859
+ {
860
+ if (!session)
861
+ return;
862
+
863
+ git_buf_free(&session->sysdir);
864
+ git_buf_free(&session->tmp);
865
+
866
+ memset(session, 0, sizeof(git_attr_session));
867
+ }