rugged 0.23.0b2 → 0.23.0b4

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.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_blob.c +39 -0
  3. data/ext/rugged/rugged_diff.c +7 -3
  4. data/ext/rugged/rugged_index.c +2 -2
  5. data/ext/rugged/rugged_remote.c +27 -148
  6. data/ext/rugged/rugged_remote_collection.c +134 -12
  7. data/ext/rugged/rugged_repo.c +74 -5
  8. data/ext/rugged/rugged_submodule.c +18 -208
  9. data/ext/rugged/rugged_submodule_collection.c +148 -0
  10. data/lib/rugged/version.rb +1 -1
  11. data/vendor/libgit2/AUTHORS +1 -0
  12. data/vendor/libgit2/CMakeLists.txt +33 -25
  13. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -29
  14. data/vendor/libgit2/include/git2.h +1 -1
  15. data/vendor/libgit2/include/git2/blob.h +4 -6
  16. data/vendor/libgit2/include/git2/checkout.h +10 -1
  17. data/vendor/libgit2/include/git2/clone.h +6 -7
  18. data/vendor/libgit2/include/git2/commit.h +11 -0
  19. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  20. data/vendor/libgit2/include/git2/describe.h +1 -1
  21. data/vendor/libgit2/include/git2/diff.h +68 -11
  22. data/vendor/libgit2/include/git2/errors.h +4 -1
  23. data/vendor/libgit2/include/git2/filter.h +16 -0
  24. data/vendor/libgit2/include/git2/index.h +38 -11
  25. data/vendor/libgit2/include/git2/odb.h +1 -1
  26. data/vendor/libgit2/include/git2/odb_backend.h +2 -2
  27. data/vendor/libgit2/include/git2/remote.h +300 -207
  28. data/vendor/libgit2/include/git2/reset.h +1 -0
  29. data/vendor/libgit2/include/git2/stash.h +135 -4
  30. data/vendor/libgit2/include/git2/status.h +1 -0
  31. data/vendor/libgit2/include/git2/submodule.h +46 -75
  32. data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
  33. data/vendor/libgit2/include/git2/sys/stream.h +2 -0
  34. data/vendor/libgit2/include/git2/sys/transport.h +1 -21
  35. data/vendor/libgit2/include/git2/transport.h +27 -0
  36. data/vendor/libgit2/include/git2/types.h +20 -10
  37. data/vendor/libgit2/include/git2/version.h +3 -3
  38. data/vendor/libgit2/libgit2.pc.in +4 -2
  39. data/vendor/libgit2/src/attr.c +2 -1
  40. data/vendor/libgit2/src/attr_file.c +18 -37
  41. data/vendor/libgit2/src/blame.c +2 -2
  42. data/vendor/libgit2/src/blob.c +4 -3
  43. data/vendor/libgit2/src/branch.c +6 -3
  44. data/vendor/libgit2/src/buf_text.c +4 -6
  45. data/vendor/libgit2/src/buf_text.h +1 -2
  46. data/vendor/libgit2/src/buffer.c +8 -6
  47. data/vendor/libgit2/src/buffer.h +1 -1
  48. data/vendor/libgit2/src/cache.c +1 -0
  49. data/vendor/libgit2/src/checkout.c +34 -20
  50. data/vendor/libgit2/src/clone.c +29 -29
  51. data/vendor/libgit2/src/commit.c +65 -0
  52. data/vendor/libgit2/src/common.h +5 -0
  53. data/vendor/libgit2/src/config.c +20 -0
  54. data/vendor/libgit2/src/config.h +6 -0
  55. data/vendor/libgit2/src/config_file.c +2 -2
  56. data/vendor/libgit2/src/crlf.c +39 -17
  57. data/vendor/libgit2/src/curl_stream.c +257 -0
  58. data/vendor/libgit2/src/curl_stream.h +14 -0
  59. data/vendor/libgit2/src/diff.c +223 -88
  60. data/vendor/libgit2/src/diff.h +21 -1
  61. data/vendor/libgit2/src/diff_file.c +23 -13
  62. data/vendor/libgit2/src/diff_file.h +4 -2
  63. data/vendor/libgit2/src/diff_patch.c +266 -71
  64. data/vendor/libgit2/src/diff_patch.h +36 -0
  65. data/vendor/libgit2/src/diff_print.c +156 -126
  66. data/vendor/libgit2/src/diff_tform.c +32 -54
  67. data/vendor/libgit2/src/fetch.c +27 -10
  68. data/vendor/libgit2/src/fetch.h +2 -2
  69. data/vendor/libgit2/src/filebuf.c +1 -1
  70. data/vendor/libgit2/src/fileops.c +6 -2
  71. data/vendor/libgit2/src/filter.c +28 -7
  72. data/vendor/libgit2/src/fnmatch.c +5 -5
  73. data/vendor/libgit2/src/global.c +16 -0
  74. data/vendor/libgit2/src/ident.c +2 -2
  75. data/vendor/libgit2/src/ignore.c +1 -0
  76. data/vendor/libgit2/src/index.c +338 -80
  77. data/vendor/libgit2/src/index.h +4 -1
  78. data/vendor/libgit2/src/indexer.c +19 -5
  79. data/vendor/libgit2/src/iterator.c +118 -11
  80. data/vendor/libgit2/src/iterator.h +25 -0
  81. data/vendor/libgit2/src/merge.c +96 -106
  82. data/vendor/libgit2/src/merge.h +14 -4
  83. data/vendor/libgit2/src/netops.c +3 -3
  84. data/vendor/libgit2/src/odb.c +17 -9
  85. data/vendor/libgit2/src/odb.h +1 -1
  86. data/vendor/libgit2/src/odb_loose.c +2 -2
  87. data/vendor/libgit2/src/odb_pack.c +1 -1
  88. data/vendor/libgit2/src/openssl_stream.c +118 -27
  89. data/vendor/libgit2/src/pack-objects.c +28 -0
  90. data/vendor/libgit2/src/pack-objects.h +1 -0
  91. data/vendor/libgit2/src/pack.c +18 -10
  92. data/vendor/libgit2/src/path.c +16 -11
  93. data/vendor/libgit2/src/path.h +1 -1
  94. data/vendor/libgit2/src/push.c +26 -42
  95. data/vendor/libgit2/src/push.h +2 -34
  96. data/vendor/libgit2/src/rebase.c +1 -1
  97. data/vendor/libgit2/src/refs.c +1 -1
  98. data/vendor/libgit2/src/refspec.c +6 -0
  99. data/vendor/libgit2/src/remote.c +381 -274
  100. data/vendor/libgit2/src/remote.h +0 -4
  101. data/vendor/libgit2/src/repository.c +33 -12
  102. data/vendor/libgit2/src/repository.h +0 -1
  103. data/vendor/libgit2/src/reset.c +1 -0
  104. data/vendor/libgit2/src/stash.c +439 -17
  105. data/vendor/libgit2/src/status.c +6 -0
  106. data/vendor/libgit2/src/stransport_stream.c +58 -21
  107. data/vendor/libgit2/src/stream.h +15 -0
  108. data/vendor/libgit2/src/submodule.c +410 -664
  109. data/vendor/libgit2/src/submodule.h +0 -24
  110. data/vendor/libgit2/src/transaction.c +1 -0
  111. data/vendor/libgit2/src/transports/cred.c +55 -1
  112. data/vendor/libgit2/src/transports/http.c +18 -2
  113. data/vendor/libgit2/src/transports/local.c +60 -59
  114. data/vendor/libgit2/src/transports/smart.h +1 -1
  115. data/vendor/libgit2/src/transports/smart_protocol.c +11 -11
  116. data/vendor/libgit2/src/transports/ssh.c +46 -7
  117. data/vendor/libgit2/src/unix/posix.h +4 -0
  118. data/vendor/libgit2/src/util.c +9 -9
  119. data/vendor/libgit2/src/util.h +9 -0
  120. data/vendor/libgit2/src/win32/posix.h +3 -0
  121. data/vendor/libgit2/src/win32/posix_w32.c +38 -0
  122. data/vendor/libgit2/src/win32/w32_util.h +10 -0
  123. metadata +4 -3
  124. data/vendor/libgit2/include/git2/push.h +0 -94
@@ -44,6 +44,9 @@ static unsigned int index_delta2status(const git_diff_delta *head2idx)
44
44
  case GIT_DELTA_TYPECHANGE:
45
45
  st = GIT_STATUS_INDEX_TYPECHANGE;
46
46
  break;
47
+ case GIT_DELTA_CONFLICTED:
48
+ st = GIT_STATUS_CONFLICTED;
49
+ break;
47
50
  default:
48
51
  break;
49
52
  }
@@ -102,6 +105,9 @@ static unsigned int workdir_delta2status(
102
105
  case GIT_DELTA_TYPECHANGE:
103
106
  st = GIT_STATUS_WT_TYPECHANGE;
104
107
  break;
108
+ case GIT_DELTA_CONFLICTED:
109
+ st = GIT_STATUS_CONFLICTED;
110
+ break;
105
111
  default:
106
112
  break;
107
113
  }
@@ -14,6 +14,7 @@
14
14
  #include "git2/transport.h"
15
15
 
16
16
  #include "socket_stream.h"
17
+ #include "curl_stream.h"
17
18
 
18
19
  int stransport_error(OSStatus ret)
19
20
  {
@@ -24,11 +25,16 @@ int stransport_error(OSStatus ret)
24
25
  return 0;
25
26
  }
26
27
 
28
+ #if !TARGET_OS_IPHONE
27
29
  message = SecCopyErrorMessageString(ret, NULL);
28
30
  GITERR_CHECK_ALLOC(message);
29
31
 
30
32
  giterr_set(GITERR_NET, "SecureTransport error: %s", CFStringGetCStringPtr(message, kCFStringEncodingUTF8));
31
33
  CFRelease(message);
34
+ #else
35
+ giterr_set(GITERR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret);
36
+ #endif
37
+
32
38
  return -1;
33
39
  }
34
40
 
@@ -110,19 +116,33 @@ int stransport_certificate(git_cert **out, git_stream *stream)
110
116
  return 0;
111
117
  }
112
118
 
119
+ int stransport_set_proxy(git_stream *stream, const char *proxy)
120
+ {
121
+ stransport_stream *st = (stransport_stream *) stream;
122
+
123
+ return git_stream_set_proxy(st->io, proxy);
124
+ }
125
+
126
+ /*
127
+ * Contrary to typical network IO callbacks, Secure Transport write callback is
128
+ * expected to write *all* passed data, not just as much as it can, and any
129
+ * other case would be considered a failure.
130
+ *
131
+ * This behavior is actually not specified in the Apple documentation, but is
132
+ * required for things to work correctly (and incidentally, that's also how
133
+ * Apple implements it in its projects at opensource.apple.com).
134
+ *
135
+ * Libgit2 streams happen to already have this very behavior so this is just
136
+ * passthrough.
137
+ */
113
138
  static OSStatus write_cb(SSLConnectionRef conn, const void *data, size_t *len)
114
139
  {
115
140
  git_stream *io = (git_stream *) conn;
116
- ssize_t ret;
117
141
 
118
- ret = git_stream_write(io, data, *len, 0);
119
- if (ret < 0) {
120
- *len = 0;
121
- return -1;
142
+ if (git_stream_write(io, data, *len, 0) < 0) {
143
+ return -36; /* "ioErr" from MacErrors.h which is not available on iOS */
122
144
  }
123
145
 
124
- *len = ret;
125
-
126
146
  return noErr;
127
147
  }
128
148
 
@@ -141,29 +161,38 @@ ssize_t stransport_write(git_stream *stream, const char *data, size_t len, int f
141
161
  return processed;
142
162
  }
143
163
 
164
+ /*
165
+ * Contrary to typical network IO callbacks, Secure Transport read callback is
166
+ * expected to read *exactly* the requested number of bytes, not just as much
167
+ * as it can, and any other case would be considered a failure.
168
+ *
169
+ * This behavior is actually not specified in the Apple documentation, but is
170
+ * required for things to work correctly (and incidentally, that's also how
171
+ * Apple implements it in its projects at opensource.apple.com).
172
+ */
144
173
  static OSStatus read_cb(SSLConnectionRef conn, void *data, size_t *len)
145
174
  {
146
175
  git_stream *io = (git_stream *) conn;
176
+ OSStatus error = noErr;
177
+ size_t off = 0;
147
178
  ssize_t ret;
148
- size_t left, requested;
149
179
 
150
- requested = left = *len;
151
180
  do {
152
- ret = git_stream_read(io, data + (requested - left), left);
181
+ ret = git_stream_read(io, data + off, *len - off);
153
182
  if (ret < 0) {
154
- *len = 0;
155
- return -1;
183
+ error = -36; /* "ioErr" from MacErrors.h which is not available on iOS */
184
+ break;
185
+ }
186
+ if (ret == 0) {
187
+ error = errSSLClosedGraceful;
188
+ break;
156
189
  }
157
190
 
158
- left -= ret;
159
- } while (left);
160
-
161
- *len = requested;
162
-
163
- if (ret == 0)
164
- return errSSLClosedGraceful;
191
+ off += ret;
192
+ } while (off < *len);
165
193
 
166
- return noErr;
194
+ *len = off;
195
+ return error;
167
196
  }
168
197
 
169
198
  ssize_t stransport_read(git_stream *stream, void *data, size_t len)
@@ -212,7 +241,13 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po
212
241
  st = git__calloc(1, sizeof(stransport_stream));
213
242
  GITERR_CHECK_ALLOC(st);
214
243
 
215
- if ((error = git_socket_stream_new(&st->io, host, port)) < 0){
244
+ #ifdef GIT_CURL
245
+ error = git_curl_stream_new(&st->io, host, port);
246
+ #else
247
+ error = git_socket_stream_new(&st->io, host, port);
248
+ #endif
249
+
250
+ if (error < 0){
216
251
  git__free(st);
217
252
  return error;
218
253
  }
@@ -235,8 +270,10 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po
235
270
 
236
271
  st->parent.version = GIT_STREAM_VERSION;
237
272
  st->parent.encrypted = 1;
273
+ st->parent.proxy_support = git_stream_supports_proxy(st->io);
238
274
  st->parent.connect = stransport_connect;
239
275
  st->parent.certificate = stransport_certificate;
276
+ st->parent.set_proxy = stransport_set_proxy;
240
277
  st->parent.read = stransport_read;
241
278
  st->parent.write = stransport_write;
242
279
  st->parent.close = stransport_close;
@@ -30,6 +30,21 @@ GIT_INLINE(int) git_stream_certificate(git_cert **out, git_stream *st)
30
30
  return st->certificate(out, st);
31
31
  }
32
32
 
33
+ GIT_INLINE(int) git_stream_supports_proxy(git_stream *st)
34
+ {
35
+ return st->proxy_support;
36
+ }
37
+
38
+ GIT_INLINE(int) git_stream_set_proxy(git_stream *st, const char *proxy_url)
39
+ {
40
+ if (!st->proxy_support) {
41
+ giterr_set(GITERR_INVALID, "proxy not supported on this stream");
42
+ return -1;
43
+ }
44
+
45
+ return st->set_proxy(st, proxy_url);
46
+ }
47
+
33
48
  GIT_INLINE(ssize_t) git_stream_read(git_stream *st, void *data, size_t len)
34
49
  {
35
50
  return st->read(st, data, len);
@@ -87,17 +87,16 @@ __KHASH_IMPL(
87
87
  str, static kh_inline, const char *, void *, 1,
88
88
  str_hash_no_trailing_slash, str_equal_no_trailing_slash)
89
89
 
90
- static int submodule_cache_init(git_repository *repo, int refresh);
91
- static void submodule_cache_free(git_submodule_cache *cache);
92
-
93
- static git_config_backend *open_gitmodules(git_submodule_cache *, int gitmod);
90
+ static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
91
+ static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
94
92
  static int get_url_base(git_buf *url, git_repository *repo);
95
93
  static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo);
96
- static int submodule_get(git_submodule **, git_submodule_cache *, const char *, const char *);
97
94
  static int submodule_load_from_config(const git_config_entry *, void *);
98
95
  static int submodule_load_from_wd_lite(git_submodule *);
99
96
  static void submodule_get_index_status(unsigned int *, git_submodule *);
100
97
  static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t);
98
+ static void submodule_update_from_index_entry(git_submodule *sm, const git_index_entry *ie);
99
+ static void submodule_update_from_head_data(git_submodule *sm, mode_t mode, const git_oid *id);
101
100
 
102
101
  static int submodule_cmp(const void *a, const void *b)
103
102
  {
@@ -111,69 +110,10 @@ static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
111
110
  return git_buf_puts(key, suffix);
112
111
  }
113
112
 
114
- /* lookup submodule or return ENOTFOUND if it doesn't exist */
115
- static int submodule_lookup(
116
- git_submodule **out,
117
- git_submodule_cache *cache,
118
- const char *name,
119
- const char *alternate)
120
- {
121
- khiter_t pos;
122
-
123
- /* lock cache */
124
-
125
- pos = git_strmap_lookup_index(cache->submodules, name);
126
-
127
- if (!git_strmap_valid_index(cache->submodules, pos) && alternate)
128
- pos = git_strmap_lookup_index(cache->submodules, alternate);
129
-
130
- if (!git_strmap_valid_index(cache->submodules, pos)) {
131
- /* unlock cache */
132
- return GIT_ENOTFOUND; /* don't set error - caller will cope */
133
- }
134
-
135
- if (out != NULL) {
136
- git_submodule *sm = git_strmap_value_at(cache->submodules, pos);
137
- GIT_REFCOUNT_INC(sm);
138
- *out = sm;
139
- }
140
-
141
- /* unlock cache */
142
-
143
- return 0;
144
- }
145
-
146
- /* clear a set of flags on all submodules */
147
- static void submodule_cache_clear_flags(
148
- git_submodule_cache *cache, uint32_t mask)
149
- {
150
- git_submodule *sm;
151
- uint32_t inverted_mask = ~mask;
152
-
153
- git_strmap_foreach_value(cache->submodules, sm, {
154
- sm->flags &= inverted_mask;
155
- });
156
- }
157
-
158
113
  /*
159
114
  * PUBLIC APIS
160
115
  */
161
116
 
162
- bool git_submodule__is_submodule(git_repository *repo, const char *name)
163
- {
164
- git_strmap *map;
165
-
166
- if (submodule_cache_init(repo, CACHE_OK) < 0) {
167
- giterr_clear();
168
- return false;
169
- }
170
-
171
- if (!repo->_submodules || !(map = repo->_submodules->submodules))
172
- return false;
173
-
174
- return git_strmap_valid_index(map, git_strmap_lookup_index(map, name));
175
- }
176
-
177
117
  static void submodule_set_lookup_error(int error, const char *name)
178
118
  {
179
119
  if (!error)
@@ -184,22 +124,24 @@ static void submodule_set_lookup_error(int error, const char *name)
184
124
  "Submodule '%s' has not been added yet", name);
185
125
  }
186
126
 
187
- int git_submodule__lookup(
188
- git_submodule **out, /* NULL if user only wants to test existence */
189
- git_repository *repo,
190
- const char *name) /* trailing slash is allowed */
191
- {
192
- int error;
193
-
194
- assert(repo && name);
127
+ typedef struct {
128
+ const char *path;
129
+ char *name;
130
+ } fbp_data;
195
131
 
196
- if ((error = submodule_cache_init(repo, CACHE_OK)) < 0)
197
- return error;
132
+ static int find_by_path(const git_config_entry *entry, void *payload)
133
+ {
134
+ fbp_data *data = payload;
198
135
 
199
- if ((error = submodule_lookup(out, repo->_submodules, name, NULL)) < 0)
200
- submodule_set_lookup_error(error, name);
136
+ if (!strcmp(entry->value, data->path)) {
137
+ const char *fdot, *ldot;
138
+ fdot = strchr(entry->name, '.');
139
+ ldot = strrchr(entry->name, '.');
140
+ data->name = git__strndup(fdot + 1, ldot - fdot - 1);
141
+ GITERR_CHECK_ALLOC(data->name);
142
+ }
201
143
 
202
- return error;
144
+ return 0;
203
145
  }
204
146
 
205
147
  int git_submodule_lookup(
@@ -208,20 +150,71 @@ int git_submodule_lookup(
208
150
  const char *name) /* trailing slash is allowed */
209
151
  {
210
152
  int error;
153
+ unsigned int location;
154
+ git_submodule *sm;
211
155
 
212
156
  assert(repo && name);
213
157
 
214
- if ((error = submodule_cache_init(repo, CACHE_REFRESH)) < 0)
158
+ if ((error = submodule_alloc(&sm, repo, name)) < 0)
215
159
  return error;
216
160
 
217
- if ((error = submodule_lookup(out, repo->_submodules, name, NULL)) < 0) {
161
+ if ((error = git_submodule_reload(sm, false)) < 0) {
162
+ git_submodule_free(sm);
163
+ return error;
164
+ }
165
+
166
+ if ((error = git_submodule_location(&location, sm)) < 0) {
167
+ git_submodule_free(sm);
168
+ return error;
169
+ }
170
+
171
+ /* If it's not configured, we need to check for the path */
172
+ if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
173
+ git_config_backend *mods;
174
+ const char *pattern = "submodule\\..*\\.path";
175
+ fbp_data data = { name, NULL };
176
+
177
+ mods = open_gitmodules(repo, GITMODULES_EXISTING);
178
+
179
+ if (mods)
180
+ error = git_config_file_foreach_match(mods, pattern, find_by_path, &data);
218
181
 
219
- /* check if a plausible submodule exists at path */
182
+ git_config_file_free(mods);
183
+
184
+ if (error < 0) {
185
+ git_submodule_free(sm);
186
+ return error;
187
+ }
188
+
189
+ if (data.name) {
190
+ git__free(sm->name);
191
+ sm->name = data.name;
192
+ sm->path = git__strdup(name);
193
+ GITERR_CHECK_ALLOC(sm->path);
194
+
195
+ /* Try to load again with the right name */
196
+ if ((error = git_submodule_reload(sm, false)) < 0) {
197
+ git_submodule_free(sm);
198
+ return error;
199
+ }
200
+ }
201
+ }
202
+
203
+ if ((error = git_submodule_location(&location, sm)) < 0) {
204
+ git_submodule_free(sm);
205
+ return error;
206
+ }
207
+
208
+ /* If we still haven't found it, do the WD check */
209
+ if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
210
+ git_submodule_free(sm);
211
+ error = GIT_ENOTFOUND;
212
+
213
+ /* If it's not configured, we still check if there's a repo at the path */
220
214
  if (git_repository_workdir(repo)) {
221
215
  git_buf path = GIT_BUF_INIT;
222
-
223
216
  if (git_buf_join3(&path,
224
- '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
217
+ '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
225
218
  return -1;
226
219
 
227
220
  if (git_path_exists(path.ptr))
@@ -231,9 +224,15 @@ int git_submodule_lookup(
231
224
  }
232
225
 
233
226
  submodule_set_lookup_error(error, name);
227
+ return error;
234
228
  }
235
229
 
236
- return error;
230
+ if (out)
231
+ *out = sm;
232
+ else
233
+ git_submodule_free(sm);
234
+
235
+ return 0;
237
236
  }
238
237
 
239
238
  static void submodule_free_dup(void *sm)
@@ -241,41 +240,221 @@ static void submodule_free_dup(void *sm)
241
240
  git_submodule_free(sm);
242
241
  }
243
242
 
243
+ static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
244
+ {
245
+ int error = 0;
246
+ khiter_t pos;
247
+ git_submodule *sm = NULL;
248
+
249
+ pos = git_strmap_lookup_index(map, name);
250
+ if (git_strmap_valid_index(map, pos)) {
251
+ sm = git_strmap_value_at(map, pos);
252
+ goto done;
253
+ }
254
+
255
+ /* if the submodule doesn't exist yet in the map, create it */
256
+ if ((error = submodule_alloc(&sm, repo, name)) < 0)
257
+ return error;
258
+
259
+ pos = kh_put(str, map, sm->name, &error);
260
+ /* nobody can beat us to adding it */
261
+ assert(error != 0);
262
+ if (error < 0) {
263
+ git_submodule_free(sm);
264
+ return error;
265
+ }
266
+
267
+ git_strmap_set_value_at(map, pos, sm);
268
+
269
+ done:
270
+ GIT_REFCOUNT_INC(sm);
271
+ *out = sm;
272
+ return 0;
273
+ }
274
+
275
+ static int submodules_from_index(git_strmap *map, git_index *idx)
276
+ {
277
+ int error;
278
+ git_iterator *i;
279
+ const git_index_entry *entry;
280
+
281
+ if ((error = git_iterator_for_index(&i, idx, 0, NULL, NULL)) < 0)
282
+ return error;
283
+
284
+ while (!(error = git_iterator_advance(&entry, i))) {
285
+ khiter_t pos = git_strmap_lookup_index(map, entry->path);
286
+ git_submodule *sm;
287
+
288
+ if (git_strmap_valid_index(map, pos)) {
289
+ sm = git_strmap_value_at(map, pos);
290
+
291
+ if (S_ISGITLINK(entry->mode))
292
+ submodule_update_from_index_entry(sm, entry);
293
+ else
294
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
295
+ } else if (S_ISGITLINK(entry->mode)) {
296
+ if (!submodule_get_or_create(&sm, git_index_owner(idx), map, entry->path)) {
297
+ submodule_update_from_index_entry(sm, entry);
298
+ git_submodule_free(sm);
299
+ }
300
+ }
301
+ }
302
+
303
+ if (error == GIT_ITEROVER)
304
+ error = 0;
305
+
306
+ git_iterator_free(i);
307
+
308
+ return error;
309
+ }
310
+
311
+ static int submodules_from_head(git_strmap *map, git_tree *head)
312
+ {
313
+ int error;
314
+ git_iterator *i;
315
+ const git_index_entry *entry;
316
+
317
+ if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0)
318
+ return error;
319
+
320
+ while (!(error = git_iterator_advance(&entry, i))) {
321
+ khiter_t pos = git_strmap_lookup_index(map, entry->path);
322
+ git_submodule *sm;
323
+
324
+ if (git_strmap_valid_index(map, pos)) {
325
+ sm = git_strmap_value_at(map, pos);
326
+
327
+ if (S_ISGITLINK(entry->mode))
328
+ submodule_update_from_head_data(sm, entry->mode, &entry->id);
329
+ else
330
+ sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
331
+ } else if (S_ISGITLINK(entry->mode)) {
332
+ if (!submodule_get_or_create(&sm, git_tree_owner(head), map, entry->path)) {
333
+ submodule_update_from_head_data(
334
+ sm, entry->mode, &entry->id);
335
+ git_submodule_free(sm);
336
+ }
337
+ }
338
+ }
339
+
340
+ if (error == GIT_ITEROVER)
341
+ error = 0;
342
+
343
+ git_iterator_free(i);
344
+
345
+ return error;
346
+ }
347
+
348
+ /* If have_sm is true, sm is populated, otherwise map an repo are. */
349
+ typedef struct {
350
+ int have_sm;
351
+ git_submodule *sm;
352
+ git_strmap *map;
353
+ git_repository *repo;
354
+ } lfc_data;
355
+
356
+ static int all_submodules(git_repository *repo, git_strmap *map)
357
+ {
358
+ int error = 0;
359
+ git_index *idx = NULL;
360
+ git_tree *head = NULL;
361
+ const char *wd = NULL;
362
+ git_buf path = GIT_BUF_INIT;
363
+ git_submodule *sm;
364
+ git_config_backend *mods = NULL;
365
+ uint32_t mask;
366
+
367
+ assert(repo && map);
368
+
369
+ /* get sources that we will need to check */
370
+ if (git_repository_index(&idx, repo) < 0)
371
+ giterr_clear();
372
+ if (git_repository_head_tree(&head, repo) < 0)
373
+ giterr_clear();
374
+
375
+ wd = git_repository_workdir(repo);
376
+ if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
377
+ goto cleanup;
378
+
379
+ /* clear submodule flags that are to be refreshed */
380
+ mask = 0;
381
+ mask |= GIT_SUBMODULE_STATUS_IN_INDEX |
382
+ GIT_SUBMODULE_STATUS__INDEX_FLAGS |
383
+ GIT_SUBMODULE_STATUS__INDEX_OID_VALID |
384
+ GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
385
+
386
+ mask |= GIT_SUBMODULE_STATUS_IN_HEAD |
387
+ GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
388
+ mask |= GIT_SUBMODULE_STATUS_IN_CONFIG;
389
+ if (mask != 0)
390
+ mask |= GIT_SUBMODULE_STATUS_IN_WD |
391
+ GIT_SUBMODULE_STATUS__WD_SCANNED |
392
+ GIT_SUBMODULE_STATUS__WD_FLAGS |
393
+ GIT_SUBMODULE_STATUS__WD_OID_VALID;
394
+
395
+ /* add back submodule information from index */
396
+ if (idx) {
397
+ if ((error = submodules_from_index(map, idx)) < 0)
398
+ goto cleanup;
399
+ }
400
+ /* add submodule information from HEAD */
401
+ if (head) {
402
+ if ((error = submodules_from_head(map, head)) < 0)
403
+ goto cleanup;
404
+ }
405
+ /* add submodule information from .gitmodules */
406
+ if (wd) {
407
+ lfc_data data = { 0 };
408
+ data.map = map;
409
+ data.repo = repo;
410
+ if ((mods = open_gitmodules(repo, false)) != NULL &&
411
+ (error = git_config_file_foreach(
412
+ mods, submodule_load_from_config, &data)) < 0)
413
+ goto cleanup;
414
+ }
415
+ /* shallow scan submodules in work tree as needed */
416
+ if (wd && mask != 0) {
417
+ git_strmap_foreach_value(map, sm, {
418
+ submodule_load_from_wd_lite(sm);
419
+ });
420
+ }
421
+
422
+ cleanup:
423
+ git_config_file_free(mods);
424
+ /* TODO: if we got an error, mark submodule config as invalid? */
425
+ git_index_free(idx);
426
+ git_tree_free(head);
427
+ git_buf_free(&path);
428
+ return error;
429
+ }
430
+
244
431
  int git_submodule_foreach(
245
432
  git_repository *repo,
246
433
  int (*callback)(git_submodule *sm, const char *name, void *payload),
247
434
  void *payload)
248
435
  {
436
+ git_vector snapshot = GIT_VECTOR_INIT;
437
+ git_strmap *submodules;
438
+ git_submodule *sm;
249
439
  int error;
250
440
  size_t i;
251
- git_submodule *sm;
252
- git_submodule_cache *cache;
253
- git_vector snapshot = GIT_VECTOR_INIT;
254
-
255
- assert(repo && callback);
256
441
 
257
- if ((error = submodule_cache_init(repo, CACHE_REFRESH)) < 0)
442
+ if ((error = git_strmap_alloc(&submodules)) < 0)
258
443
  return error;
259
444
 
260
- cache = repo->_submodules;
261
-
262
- if (git_mutex_lock(&cache->lock) < 0) {
263
- giterr_set(GITERR_OS, "Unable to acquire lock on submodule cache");
264
- return -1;
265
- }
445
+ if ((error = all_submodules(repo, submodules)) < 0)
446
+ goto done;
266
447
 
267
448
  if (!(error = git_vector_init(
268
- &snapshot, kh_size(cache->submodules), submodule_cmp))) {
449
+ &snapshot, kh_size(submodules), submodule_cmp))) {
269
450
 
270
- git_strmap_foreach_value(cache->submodules, sm, {
451
+ git_strmap_foreach_value(submodules, sm, {
271
452
  if ((error = git_vector_insert(&snapshot, sm)) < 0)
272
453
  break;
273
454
  GIT_REFCOUNT_INC(sm);
274
455
  });
275
456
  }
276
457
 
277
- git_mutex_unlock(&cache->lock);
278
-
279
458
  if (error < 0)
280
459
  goto done;
281
460
 
@@ -293,17 +472,12 @@ done:
293
472
  git_submodule_free(sm);
294
473
  git_vector_free(&snapshot);
295
474
 
296
- return error;
297
- }
298
-
299
- void git_submodule_cache_free(git_repository *repo)
300
- {
301
- git_submodule_cache *cache;
302
-
303
- assert(repo);
475
+ git_strmap_foreach_value(submodules, sm, {
476
+ git_submodule_free(sm);
477
+ });
478
+ git_strmap_free(submodules);
304
479
 
305
- if ((cache = git__swap(repo->_submodules, NULL)) != NULL)
306
- submodule_cache_free(cache);
480
+ return error;
307
481
  }
308
482
 
309
483
  static int submodule_repo_init(
@@ -394,7 +568,7 @@ int git_submodule_add_setup(
394
568
 
395
569
  /* update .gitmodules */
396
570
 
397
- if (!(mods = open_gitmodules(repo->_submodules, GITMODULES_CREATE))) {
571
+ if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
398
572
  giterr_set(GITERR_SUBMODULE,
399
573
  "Adding submodules to a bare repository is not supported");
400
574
  return -1;
@@ -430,19 +604,10 @@ int git_submodule_add_setup(
430
604
  goto cleanup;
431
605
  }
432
606
 
433
- /* add submodule to hash and "reload" it */
434
-
435
- if (git_mutex_lock(&repo->_submodules->lock) < 0) {
436
- giterr_set(GITERR_OS, "Unable to acquire lock on submodule cache");
437
- error = -1;
607
+ if ((error = git_submodule_lookup(&sm, repo, path)) < 0)
438
608
  goto cleanup;
439
- }
440
-
441
- if (!(error = submodule_get(&sm, repo->_submodules, path, NULL)) &&
442
- !(error = git_submodule_reload(sm, false)))
443
- error = git_submodule_init(sm, false);
444
609
 
445
- git_mutex_unlock(&repo->_submodules->lock);
610
+ error = git_submodule_init(sm, false);
446
611
 
447
612
  cleanup:
448
613
  if (error && sm) {
@@ -572,15 +737,6 @@ cleanup:
572
737
  return error;
573
738
  }
574
739
 
575
- const char *git_submodule_ignore_to_str(git_submodule_ignore_t ignore)
576
- {
577
- int i;
578
- for (i = 0; i < (int)ARRAY_SIZE(_sm_ignore_map); ++i)
579
- if (_sm_ignore_map[i].map_value == ignore)
580
- return _sm_ignore_map[i].str_match;
581
- return NULL;
582
- }
583
-
584
740
  const char *git_submodule_update_to_str(git_submodule_update_t update)
585
741
  {
586
742
  int i;
@@ -590,132 +746,90 @@ const char *git_submodule_update_to_str(git_submodule_update_t update)
590
746
  return NULL;
591
747
  }
592
748
 
593
- const char *git_submodule_recurse_to_str(git_submodule_recurse_t recurse)
749
+ git_repository *git_submodule_owner(git_submodule *submodule)
594
750
  {
595
- int i;
596
- for (i = 0; i < (int)ARRAY_SIZE(_sm_recurse_map); ++i)
597
- if (_sm_recurse_map[i].map_value == recurse)
598
- return _sm_recurse_map[i].str_match;
599
- return NULL;
751
+ assert(submodule);
752
+ return submodule->repo;
600
753
  }
601
754
 
602
- int git_submodule_save(git_submodule *submodule)
755
+ const char *git_submodule_name(git_submodule *submodule)
603
756
  {
604
- int error = 0;
605
- git_config_backend *mods;
606
- git_buf key = GIT_BUF_INIT;
607
- const char *val;
608
-
609
757
  assert(submodule);
758
+ return submodule->name;
759
+ }
610
760
 
611
- mods = open_gitmodules(submodule->repo->_submodules, GITMODULES_CREATE);
612
- if (!mods) {
613
- giterr_set(GITERR_SUBMODULE,
614
- "Adding submodules to a bare repository is not supported");
615
- return -1;
616
- }
761
+ const char *git_submodule_path(git_submodule *submodule)
762
+ {
763
+ assert(submodule);
764
+ return submodule->path;
765
+ }
617
766
 
618
- if ((error = git_buf_printf(&key, "submodule.%s.", submodule->name)) < 0)
619
- goto cleanup;
767
+ const char *git_submodule_url(git_submodule *submodule)
768
+ {
769
+ assert(submodule);
770
+ return submodule->url;
771
+ }
620
772
 
621
- /* save values for path, url, update, ignore, fetchRecurseSubmodules */
773
+ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
774
+ {
775
+ int error = 0;
622
776
 
623
- if ((error = submodule_config_key_trunc_puts(&key, "path")) < 0 ||
624
- (error = git_config_file_set_string(mods, key.ptr, submodule->path)) < 0)
625
- goto cleanup;
777
+ assert(out && repo && url);
626
778
 
627
- if ((error = submodule_config_key_trunc_puts(&key, "url")) < 0 ||
628
- (error = git_config_file_set_string(mods, key.ptr, submodule->url)) < 0)
629
- goto cleanup;
779
+ git_buf_sanitize(out);
630
780
 
631
- if ((error = submodule_config_key_trunc_puts(&key, "branch")) < 0)
632
- goto cleanup;
633
- if (submodule->branch == NULL)
634
- error = git_config_file_delete(mods, key.ptr);
635
- else
636
- error = git_config_file_set_string(mods, key.ptr, submodule->branch);
637
- if (error == GIT_ENOTFOUND) {
638
- error = 0;
639
- giterr_clear();
781
+ if (git_path_is_relative(url)) {
782
+ if (!(error = get_url_base(out, repo)))
783
+ error = git_path_apply_relative(out, url);
784
+ } else if (strchr(url, ':') != NULL || url[0] == '/') {
785
+ error = git_buf_sets(out, url);
786
+ } else {
787
+ giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL");
788
+ error = -1;
640
789
  }
641
- if (error < 0)
642
- goto cleanup;
643
-
644
- if (!(error = submodule_config_key_trunc_puts(&key, "update")) &&
645
- (val = git_submodule_update_to_str(submodule->update)) != NULL)
646
- error = git_config_file_set_string(mods, key.ptr, val);
647
- if (error < 0)
648
- goto cleanup;
649
-
650
- if (!(error = submodule_config_key_trunc_puts(&key, "ignore")) &&
651
- (val = git_submodule_ignore_to_str(submodule->ignore)) != NULL)
652
- error = git_config_file_set_string(mods, key.ptr, val);
653
- if (error < 0)
654
- goto cleanup;
655
-
656
- if (!(error = submodule_config_key_trunc_puts(&key, "fetchRecurseSubmodules")) &&
657
- (val = git_submodule_recurse_to_str(submodule->fetch_recurse)) != NULL)
658
- error = git_config_file_set_string(mods, key.ptr, val);
659
- if (error < 0)
660
- goto cleanup;
661
-
662
- /* update internal defaults */
663
-
664
- submodule->ignore_default = submodule->ignore;
665
- submodule->update_default = submodule->update;
666
- submodule->fetch_recurse_default = submodule->fetch_recurse;
667
- submodule->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
668
-
669
- cleanup:
670
- git_config_file_free(mods);
671
- git_buf_free(&key);
672
790
 
673
791
  return error;
674
792
  }
675
793
 
676
- git_repository *git_submodule_owner(git_submodule *submodule)
794
+ static int write_var(git_repository *repo, const char *name, const char *var, const char *val)
677
795
  {
678
- assert(submodule);
679
- return submodule->repo;
680
- }
796
+ git_buf key = GIT_BUF_INIT;
797
+ git_config_backend *mods;
798
+ int error;
681
799
 
682
- const char *git_submodule_name(git_submodule *submodule)
683
- {
684
- assert(submodule);
685
- return submodule->name;
686
- }
800
+ mods = open_gitmodules(repo, GITMODULES_CREATE);
801
+ if (!mods)
802
+ return -1;
687
803
 
688
- const char *git_submodule_path(git_submodule *submodule)
689
- {
690
- assert(submodule);
691
- return submodule->path;
692
- }
804
+ if ((error = git_buf_printf(&key, "submodule.%s.%s", name, var)) < 0)
805
+ goto cleanup;
806
+
807
+ if (val)
808
+ error = git_config_file_set_string(mods, key.ptr, val);
809
+ else
810
+ error = git_config_file_delete(mods, key.ptr);
811
+
812
+ git_buf_free(&key);
693
813
 
694
- const char *git_submodule_url(git_submodule *submodule)
695
- {
696
- assert(submodule);
697
- return submodule->url;
814
+ cleanup:
815
+ git_config_file_free(mods);
816
+ return error;
698
817
  }
699
818
 
700
- int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
819
+ static int write_mapped_var(git_repository *repo, const char *name, git_cvar_map *maps, size_t nmaps, const char *var, int ival)
701
820
  {
702
- int error = 0;
703
-
704
- assert(out && repo && url);
705
-
706
- git_buf_sanitize(out);
821
+ git_cvar_t type;
822
+ const char *val;
707
823
 
708
- if (git_path_is_relative(url)) {
709
- if (!(error = get_url_base(out, repo)))
710
- error = git_path_apply_relative(out, url);
711
- } else if (strchr(url, ':') != NULL || url[0] == '/') {
712
- error = git_buf_sets(out, url);
713
- } else {
714
- giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL");
715
- error = -1;
824
+ if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
825
+ giterr_set(GITERR_SUBMODULE, "invalid value for %s", var);
826
+ return -1;
716
827
  }
717
828
 
718
- return error;
829
+ if (type == GIT_CVAR_TRUE)
830
+ val = "true";
831
+
832
+ return write_var(repo, name, var, val);
719
833
  }
720
834
 
721
835
  const char *git_submodule_branch(git_submodule *submodule)
@@ -724,31 +838,19 @@ const char *git_submodule_branch(git_submodule *submodule)
724
838
  return submodule->branch;
725
839
  }
726
840
 
727
- int git_submodule_set_branch(git_submodule *submodule, const char *branch)
841
+ int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch)
728
842
  {
729
- assert(submodule);
730
843
 
731
- git__free(submodule->branch);
732
- submodule->branch = NULL;
733
-
734
- if (branch != NULL) {
735
- submodule->branch = git__strdup(branch);
736
- GITERR_CHECK_ALLOC(submodule->branch);
737
- }
844
+ assert(repo && name);
738
845
 
739
- return 0;
846
+ return write_var(repo, name, "branch", branch);
740
847
  }
741
848
 
742
- int git_submodule_set_url(git_submodule *submodule, const char *url)
849
+ int git_submodule_set_url(git_repository *repo, const char *name, const char *url)
743
850
  {
744
- assert(submodule && url);
745
-
746
- git__free(submodule->url);
747
-
748
- submodule->url = git__strdup(url);
749
- GITERR_CHECK_ALLOC(submodule->url);
851
+ assert(repo && name && url);
750
852
 
751
- return 0;
853
+ return write_var(repo, name, "url", url);
752
854
  }
753
855
 
754
856
  const git_oid *git_submodule_index_id(git_submodule *submodule)
@@ -799,19 +901,11 @@ git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule)
799
901
  GIT_SUBMODULE_IGNORE_NONE : submodule->ignore;
800
902
  }
801
903
 
802
- git_submodule_ignore_t git_submodule_set_ignore(
803
- git_submodule *submodule, git_submodule_ignore_t ignore)
904
+ int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore)
804
905
  {
805
- git_submodule_ignore_t old;
806
-
807
- assert(submodule);
808
-
809
- if (ignore == GIT_SUBMODULE_IGNORE_RESET)
810
- ignore = submodule->ignore_default;
906
+ assert(repo && name);
811
907
 
812
- old = submodule->ignore;
813
- submodule->ignore = ignore;
814
- return old;
908
+ return write_mapped_var(repo, name, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), "ignore", ignore);
815
909
  }
816
910
 
817
911
  git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
@@ -821,19 +915,11 @@ git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
821
915
  GIT_SUBMODULE_UPDATE_CHECKOUT : submodule->update;
822
916
  }
823
917
 
824
- git_submodule_update_t git_submodule_set_update(
825
- git_submodule *submodule, git_submodule_update_t update)
918
+ int git_submodule_set_update(git_repository *repo, const char *name, git_submodule_update_t update)
826
919
  {
827
- git_submodule_update_t old;
828
-
829
- assert(submodule);
830
-
831
- if (update == GIT_SUBMODULE_UPDATE_RESET)
832
- update = submodule->update_default;
920
+ assert(repo && name);
833
921
 
834
- old = submodule->update;
835
- submodule->update = update;
836
- return old;
922
+ return write_mapped_var(repo, name, _sm_update_map, ARRAY_SIZE(_sm_update_map), "update", update);
837
923
  }
838
924
 
839
925
  git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
@@ -843,20 +929,11 @@ git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
843
929
  return submodule->fetch_recurse;
844
930
  }
845
931
 
846
- git_submodule_recurse_t git_submodule_set_fetch_recurse_submodules(
847
- git_submodule *submodule,
848
- git_submodule_recurse_t fetch_recurse_submodules)
932
+ int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t recurse)
849
933
  {
850
- git_submodule_recurse_t old;
851
-
852
- assert(submodule);
853
-
854
- if (fetch_recurse_submodules == GIT_SUBMODULE_RECURSE_RESET)
855
- fetch_recurse_submodules = submodule->fetch_recurse_default;
934
+ assert(repo && name);
856
935
 
857
- old = submodule->fetch_recurse;
858
- submodule->fetch_recurse = fetch_recurse_submodules;
859
- return old;
936
+ return write_mapped_var(repo, name, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), "fetchRecurseSubmodules", recurse);
860
937
  }
861
938
 
862
939
  static int submodule_repo_create(
@@ -950,10 +1027,10 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio
950
1027
  GITERR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
951
1028
 
952
1029
  /* Copy over the remote callbacks */
953
- clone_options.remote_callbacks = update_options.remote_callbacks;
1030
+ memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
954
1031
 
955
1032
  /* Get the status of the submodule to determine if it is already initialized */
956
- if ((error = git_submodule_status(&submodule_status, sm)) < 0)
1033
+ if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0)
957
1034
  goto done;
958
1035
 
959
1036
  /*
@@ -1197,11 +1274,6 @@ int git_submodule_open(git_repository **subrepo, git_submodule *sm)
1197
1274
  return git_submodule__open(subrepo, sm, false);
1198
1275
  }
1199
1276
 
1200
- int git_submodule_reload_all(git_repository *repo, int force)
1201
- {
1202
- return submodule_cache_init(repo, force ? CACHE_FLUSH : CACHE_REFRESH);
1203
- }
1204
-
1205
1277
  static void submodule_update_from_index_entry(
1206
1278
  git_submodule *sm, const git_index_entry *ie)
1207
1279
  {
@@ -1280,14 +1352,12 @@ int git_submodule_reload(git_submodule *sm, int force)
1280
1352
  {
1281
1353
  int error = 0;
1282
1354
  git_config_backend *mods;
1283
- git_submodule_cache *cache;
1355
+ lfc_data data = { 0 };
1284
1356
 
1285
1357
  GIT_UNUSED(force);
1286
1358
 
1287
1359
  assert(sm);
1288
1360
 
1289
- cache = sm->repo->_submodules;
1290
-
1291
1361
  /* refresh index data */
1292
1362
  if ((error = submodule_update_index(sm)) < 0)
1293
1363
  return error;
@@ -1301,7 +1371,7 @@ int git_submodule_reload(git_submodule *sm, int force)
1301
1371
  return error;
1302
1372
 
1303
1373
  /* refresh config data */
1304
- mods = open_gitmodules(cache, GITMODULES_EXISTING);
1374
+ mods = open_gitmodules(sm->repo, GITMODULES_EXISTING);
1305
1375
  if (mods != NULL) {
1306
1376
  git_buf path = GIT_BUF_INIT;
1307
1377
 
@@ -1309,11 +1379,14 @@ int git_submodule_reload(git_submodule *sm, int force)
1309
1379
  git_buf_text_puts_escape_regex(&path, sm->name);
1310
1380
  git_buf_puts(&path, ".*");
1311
1381
 
1312
- if (git_buf_oom(&path))
1382
+ if (git_buf_oom(&path)) {
1313
1383
  error = -1;
1314
- else
1384
+ } else {
1385
+ data.have_sm = 1;
1386
+ data.sm = sm;
1315
1387
  error = git_config_file_foreach_match(
1316
- mods, path.ptr, submodule_load_from_config, cache);
1388
+ mods, path.ptr, submodule_load_from_config, &data);
1389
+ }
1317
1390
 
1318
1391
  git_buf_free(&path);
1319
1392
  git_config_file_free(mods);
@@ -1352,7 +1425,7 @@ int git_submodule__status(
1352
1425
  unsigned int status;
1353
1426
  git_repository *smrepo = NULL;
1354
1427
 
1355
- if (ign < GIT_SUBMODULE_IGNORE_NONE)
1428
+ if (ign == GIT_SUBMODULE_IGNORE_UNSPECIFIED)
1356
1429
  ign = sm->ignore;
1357
1430
 
1358
1431
  /* only return location info if ignore == all */
@@ -1401,11 +1474,20 @@ int git_submodule__status(
1401
1474
  return 0;
1402
1475
  }
1403
1476
 
1404
- int git_submodule_status(unsigned int *status, git_submodule *sm)
1477
+ int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore)
1405
1478
  {
1406
- assert(status && sm);
1479
+ git_submodule *sm;
1480
+ int error;
1481
+
1482
+ assert(status && repo && name);
1483
+
1484
+ if ((error = git_submodule_lookup(&sm, repo, name)) < 0)
1485
+ return error;
1486
+
1487
+ error = git_submodule__status(status, NULL, NULL, NULL, sm, ignore);
1488
+ git_submodule_free(sm);
1407
1489
 
1408
- return git_submodule__status(status, NULL, NULL, NULL, sm, 0);
1490
+ return error;
1409
1491
  }
1410
1492
 
1411
1493
  int git_submodule_location(unsigned int *location, git_submodule *sm)
@@ -1422,7 +1504,7 @@ int git_submodule_location(unsigned int *location, git_submodule *sm)
1422
1504
  */
1423
1505
 
1424
1506
  static int submodule_alloc(
1425
- git_submodule **out, git_submodule_cache *cache, const char *name)
1507
+ git_submodule **out, git_repository *repo, const char *name)
1426
1508
  {
1427
1509
  size_t namelen;
1428
1510
  git_submodule *sm;
@@ -1445,56 +1527,20 @@ static int submodule_alloc(
1445
1527
  sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
1446
1528
  sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
1447
1529
  sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
1448
- sm->repo = cache->repo;
1530
+ sm->repo = repo;
1449
1531
  sm->branch = NULL;
1450
1532
 
1451
1533
  *out = sm;
1452
1534
  return 0;
1453
1535
  }
1454
1536
 
1455
- static void submodule_cache_remove_item(
1456
- git_submodule_cache *cache,
1457
- git_submodule *item,
1458
- bool free_after_remove)
1459
- {
1460
- git_strmap *map;
1461
- const char *name, *alt;
1462
-
1463
- if (!cache || !(map = cache->submodules) || !item)
1464
- return;
1465
-
1466
- name = item->name;
1467
- alt = (item->path != item->name) ? item->path : NULL;
1468
-
1469
- for (; name; name = alt, alt = NULL) {
1470
- khiter_t pos = git_strmap_lookup_index(map, name);
1471
- git_submodule *found;
1472
-
1473
- if (!git_strmap_valid_index(map, pos))
1474
- continue;
1475
-
1476
- found = git_strmap_value_at(map, pos);
1477
-
1478
- if (found != item)
1479
- continue;
1480
-
1481
- git_strmap_set_value_at(map, pos, NULL);
1482
- git_strmap_delete_at(map, pos);
1483
-
1484
- if (free_after_remove)
1485
- git_submodule_free(found);
1486
- }
1487
- }
1488
-
1489
1537
  static void submodule_release(git_submodule *sm)
1490
1538
  {
1491
1539
  if (!sm)
1492
1540
  return;
1493
1541
 
1494
1542
  if (sm->repo) {
1495
- git_submodule_cache *cache = sm->repo->_submodules;
1496
1543
  sm->repo = NULL;
1497
- submodule_cache_remove_item(cache, sm, false);
1498
1544
  }
1499
1545
 
1500
1546
  if (sm->path != sm->name)
@@ -1513,54 +1559,6 @@ void git_submodule_free(git_submodule *sm)
1513
1559
  GIT_REFCOUNT_DEC(sm, submodule_release);
1514
1560
  }
1515
1561
 
1516
- static int submodule_get(
1517
- git_submodule **out,
1518
- git_submodule_cache *cache,
1519
- const char *name,
1520
- const char *alternate)
1521
- {
1522
- int error = 0;
1523
- khiter_t pos;
1524
- git_submodule *sm;
1525
-
1526
- pos = git_strmap_lookup_index(cache->submodules, name);
1527
-
1528
- if (!git_strmap_valid_index(cache->submodules, pos) && alternate)
1529
- pos = git_strmap_lookup_index(cache->submodules, alternate);
1530
-
1531
- if (!git_strmap_valid_index(cache->submodules, pos)) {
1532
- if ((error = submodule_alloc(&sm, cache, name)) < 0)
1533
- return error;
1534
-
1535
- /* insert value at name - if another thread beats us to it, then use
1536
- * their record and release our own.
1537
- */
1538
- pos = kh_put(str, cache->submodules, sm->name, &error);
1539
-
1540
- if (error < 0)
1541
- goto done;
1542
- else if (error == 0) {
1543
- git_submodule_free(sm);
1544
- sm = git_strmap_value_at(cache->submodules, pos);
1545
- } else {
1546
- error = 0;
1547
- git_strmap_set_value_at(cache->submodules, pos, sm);
1548
- }
1549
- } else {
1550
- sm = git_strmap_value_at(cache->submodules, pos);
1551
- }
1552
-
1553
- done:
1554
- if (error < 0)
1555
- git_submodule_free(sm);
1556
- else if (out) {
1557
- GIT_REFCOUNT_INC(sm);
1558
- *out = sm;
1559
- }
1560
-
1561
- return error;
1562
- }
1563
-
1564
1562
  static int submodule_config_error(const char *property, const char *value)
1565
1563
  {
1566
1564
  giterr_set(GITERR_INVALID,
@@ -1613,12 +1611,12 @@ int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
1613
1611
  static int submodule_load_from_config(
1614
1612
  const git_config_entry *entry, void *payload)
1615
1613
  {
1616
- git_submodule_cache *cache = payload;
1617
1614
  const char *namestart, *property;
1618
1615
  const char *key = entry->name, *value = entry->value, *path;
1619
1616
  char *alternate = NULL, *replaced = NULL;
1620
1617
  git_buf name = GIT_BUF_INIT;
1621
- git_submodule *sm = NULL;
1618
+ lfc_data *data = payload;
1619
+ git_submodule *sm;
1622
1620
  int error = 0;
1623
1621
 
1624
1622
  if (git__prefixcmp(key, "submodule.") != 0)
@@ -1633,10 +1631,29 @@ static int submodule_load_from_config(
1633
1631
  property++;
1634
1632
  path = !strcasecmp(property, "path") ? value : NULL;
1635
1633
 
1636
- if ((error = git_buf_set(&name, namestart, property - namestart - 1)) < 0 ||
1637
- (error = submodule_get(&sm, cache, name.ptr, path)) < 0)
1634
+ if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
1638
1635
  goto done;
1639
1636
 
1637
+ if (data->have_sm) {
1638
+ sm = data->sm;
1639
+ } else {
1640
+ khiter_t pos;
1641
+ git_strmap *map = data->map;
1642
+ pos = git_strmap_lookup_index(map, name.ptr);
1643
+ if (git_strmap_valid_index(map, pos)) {
1644
+ sm = git_strmap_value_at(map, pos);
1645
+ } else {
1646
+ if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
1647
+ goto done;
1648
+
1649
+ git_strmap_insert(map, sm->name, sm, error);
1650
+ assert(error != 0);
1651
+ if (error < 0)
1652
+ goto done;
1653
+ error = 0;
1654
+ }
1655
+ }
1656
+
1640
1657
  sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
1641
1658
 
1642
1659
  /* Only from config might we get differing names & paths. If so, then
@@ -1648,7 +1665,7 @@ static int submodule_load_from_config(
1648
1665
  */
1649
1666
 
1650
1667
  if (strcmp(sm->name, name.ptr) != 0) { /* name changed */
1651
- if (!strcmp(sm->path, name.ptr)) { /* already set as path */
1668
+ if (sm->path && !strcmp(sm->path, name.ptr)) { /* already set as path */
1652
1669
  replaced = sm->name;
1653
1670
  sm->name = sm->path;
1654
1671
  } else {
@@ -1674,7 +1691,6 @@ static int submodule_load_from_config(
1674
1691
 
1675
1692
  /* Deregister under name being replaced */
1676
1693
  if (replaced) {
1677
- git_strmap_delete(cache->submodules, replaced);
1678
1694
  git_submodule_free(sm);
1679
1695
  git__free(replaced);
1680
1696
  }
@@ -1682,7 +1698,6 @@ static int submodule_load_from_config(
1682
1698
  /* Insert under alternate key */
1683
1699
  if (alternate) {
1684
1700
  void *old_sm = NULL;
1685
- git_strmap_insert2(cache->submodules, alternate, sm, old_sm, error);
1686
1701
 
1687
1702
  if (error < 0)
1688
1703
  goto done;
@@ -1742,7 +1757,6 @@ static int submodule_load_from_config(
1742
1757
  /* ignore other unknown submodule properties */
1743
1758
 
1744
1759
  done:
1745
- git_submodule_free(sm); /* offset refcount inc from submodule_get() */
1746
1760
  git_buf_free(&name);
1747
1761
  return error;
1748
1762
  }
@@ -1764,86 +1778,11 @@ static int submodule_load_from_wd_lite(git_submodule *sm)
1764
1778
  return 0;
1765
1779
  }
1766
1780
 
1767
- static int submodule_cache_refresh_from_index(
1768
- git_submodule_cache *cache, git_index *idx)
1769
- {
1770
- int error;
1771
- git_iterator *i;
1772
- const git_index_entry *entry;
1773
-
1774
- if ((error = git_iterator_for_index(&i, idx, 0, NULL, NULL)) < 0)
1775
- return error;
1776
-
1777
- while (!(error = git_iterator_advance(&entry, i))) {
1778
- khiter_t pos = git_strmap_lookup_index(cache->submodules, entry->path);
1779
- git_submodule *sm;
1780
-
1781
- if (git_strmap_valid_index(cache->submodules, pos)) {
1782
- sm = git_strmap_value_at(cache->submodules, pos);
1783
-
1784
- if (S_ISGITLINK(entry->mode))
1785
- submodule_update_from_index_entry(sm, entry);
1786
- else
1787
- sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
1788
- } else if (S_ISGITLINK(entry->mode)) {
1789
- if (!submodule_get(&sm, cache, entry->path, NULL)) {
1790
- submodule_update_from_index_entry(sm, entry);
1791
- git_submodule_free(sm);
1792
- }
1793
- }
1794
- }
1795
-
1796
- if (error == GIT_ITEROVER)
1797
- error = 0;
1798
-
1799
- git_iterator_free(i);
1800
-
1801
- return error;
1802
- }
1803
-
1804
- static int submodule_cache_refresh_from_head(
1805
- git_submodule_cache *cache, git_tree *head)
1806
- {
1807
- int error;
1808
- git_iterator *i;
1809
- const git_index_entry *entry;
1810
-
1811
- if ((error = git_iterator_for_tree(&i, head, 0, NULL, NULL)) < 0)
1812
- return error;
1813
-
1814
- while (!(error = git_iterator_advance(&entry, i))) {
1815
- khiter_t pos = git_strmap_lookup_index(cache->submodules, entry->path);
1816
- git_submodule *sm;
1817
-
1818
- if (git_strmap_valid_index(cache->submodules, pos)) {
1819
- sm = git_strmap_value_at(cache->submodules, pos);
1820
-
1821
- if (S_ISGITLINK(entry->mode))
1822
- submodule_update_from_head_data(sm, entry->mode, &entry->id);
1823
- else
1824
- sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
1825
- } else if (S_ISGITLINK(entry->mode)) {
1826
- if (!submodule_get(&sm, cache, entry->path, NULL)) {
1827
- submodule_update_from_head_data(
1828
- sm, entry->mode, &entry->id);
1829
- git_submodule_free(sm);
1830
- }
1831
- }
1832
- }
1833
-
1834
- if (error == GIT_ITEROVER)
1835
- error = 0;
1836
-
1837
- git_iterator_free(i);
1838
-
1839
- return error;
1840
- }
1841
-
1842
1781
  static git_config_backend *open_gitmodules(
1843
- git_submodule_cache *cache,
1782
+ git_repository *repo,
1844
1783
  int okay_to_create)
1845
1784
  {
1846
- const char *workdir = git_repository_workdir(cache->repo);
1785
+ const char *workdir = git_repository_workdir(repo);
1847
1786
  git_buf path = GIT_BUF_INIT;
1848
1787
  git_config_backend *mods = NULL;
1849
1788
 
@@ -1868,199 +1807,6 @@ static git_config_backend *open_gitmodules(
1868
1807
  return mods;
1869
1808
  }
1870
1809
 
1871
- static void submodule_cache_free(git_submodule_cache *cache)
1872
- {
1873
- git_submodule *sm;
1874
-
1875
- if (!cache)
1876
- return;
1877
-
1878
- git_strmap_foreach_value(cache->submodules, sm, {
1879
- sm->repo = NULL; /* disconnect from repo */
1880
- git_submodule_free(sm);
1881
- });
1882
- git_strmap_free(cache->submodules);
1883
-
1884
- git_buf_free(&cache->gitmodules_path);
1885
- git_mutex_free(&cache->lock);
1886
- git__free(cache);
1887
- }
1888
-
1889
- static int submodule_cache_alloc(
1890
- git_submodule_cache **out, git_repository *repo)
1891
- {
1892
- git_submodule_cache *cache = git__calloc(1, sizeof(git_submodule_cache));
1893
- GITERR_CHECK_ALLOC(cache);
1894
-
1895
- if (git_mutex_init(&cache->lock) < 0) {
1896
- giterr_set(GITERR_OS, "Unable to initialize submodule cache lock");
1897
- git__free(cache);
1898
- return -1;
1899
- }
1900
-
1901
- if (git_strmap_alloc(&cache->submodules) < 0) {
1902
- submodule_cache_free(cache);
1903
- return -1;
1904
- }
1905
-
1906
- cache->repo = repo;
1907
- git_buf_init(&cache->gitmodules_path, 0);
1908
-
1909
- *out = cache;
1910
- return 0;
1911
- }
1912
-
1913
- static int submodule_cache_refresh(git_submodule_cache *cache, int refresh)
1914
- {
1915
- int error = 0, update_index, update_head, update_gitmod;
1916
- git_index *idx = NULL;
1917
- git_tree *head = NULL;
1918
- const char *wd = NULL;
1919
- git_buf path = GIT_BUF_INIT;
1920
- git_submodule *sm;
1921
- git_config_backend *mods = NULL;
1922
- uint32_t mask;
1923
-
1924
- if (!cache || !cache->repo || !refresh)
1925
- return 0;
1926
-
1927
- if (git_mutex_lock(&cache->lock) < 0) {
1928
- giterr_set(GITERR_OS, "Unable to acquire lock on submodule cache");
1929
- return -1;
1930
- }
1931
-
1932
- /* get sources that we will need to check */
1933
-
1934
- if (git_repository_index(&idx, cache->repo) < 0)
1935
- giterr_clear();
1936
- if (git_repository_head_tree(&head, cache->repo) < 0)
1937
- giterr_clear();
1938
-
1939
- wd = git_repository_workdir(cache->repo);
1940
- if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
1941
- goto cleanup;
1942
-
1943
- /* check for invalidation */
1944
-
1945
- if (refresh == CACHE_FLUSH)
1946
- update_index = update_head = update_gitmod = true;
1947
- else {
1948
- update_index =
1949
- !idx || git_index__changed_relative_to(idx, &cache->index_stamp);
1950
- update_head =
1951
- !head || !git_oid_equal(&cache->head_id, git_tree_id(head));
1952
-
1953
- update_gitmod = (wd != NULL) ?
1954
- git_futils_filestamp_check(&cache->gitmodules_stamp, path.ptr) :
1955
- (cache->gitmodules_stamp.mtime != 0);
1956
- }
1957
-
1958
- /* clear submodule flags that are to be refreshed */
1959
-
1960
- mask = 0;
1961
- if (!idx || update_index)
1962
- mask |= GIT_SUBMODULE_STATUS_IN_INDEX |
1963
- GIT_SUBMODULE_STATUS__INDEX_FLAGS |
1964
- GIT_SUBMODULE_STATUS__INDEX_OID_VALID |
1965
- GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
1966
- if (!head || update_head)
1967
- mask |= GIT_SUBMODULE_STATUS_IN_HEAD |
1968
- GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
1969
- if (update_gitmod)
1970
- mask |= GIT_SUBMODULE_STATUS_IN_CONFIG;
1971
- if (mask != 0)
1972
- mask |= GIT_SUBMODULE_STATUS_IN_WD |
1973
- GIT_SUBMODULE_STATUS__WD_SCANNED |
1974
- GIT_SUBMODULE_STATUS__WD_FLAGS |
1975
- GIT_SUBMODULE_STATUS__WD_OID_VALID;
1976
- else
1977
- goto cleanup; /* nothing to do */
1978
-
1979
- submodule_cache_clear_flags(cache, mask);
1980
-
1981
- /* add back submodule information from index */
1982
-
1983
- if (idx && update_index) {
1984
- if ((error = submodule_cache_refresh_from_index(cache, idx)) < 0)
1985
- goto cleanup;
1986
-
1987
- git_futils_filestamp_set(
1988
- &cache->index_stamp, git_index__filestamp(idx));
1989
- }
1990
-
1991
- /* add submodule information from HEAD */
1992
-
1993
- if (head && update_head) {
1994
- if ((error = submodule_cache_refresh_from_head(cache, head)) < 0)
1995
- goto cleanup;
1996
-
1997
- git_oid_cpy(&cache->head_id, git_tree_id(head));
1998
- }
1999
-
2000
- /* add submodule information from .gitmodules */
2001
-
2002
- if (wd && update_gitmod > 0) {
2003
- if ((mods = open_gitmodules(cache, false)) != NULL &&
2004
- (error = git_config_file_foreach(
2005
- mods, submodule_load_from_config, cache)) < 0)
2006
- goto cleanup;
2007
- }
2008
-
2009
- /* shallow scan submodules in work tree as needed */
2010
-
2011
- if (wd && mask != 0) {
2012
- git_strmap_foreach_value(cache->submodules, sm, {
2013
- submodule_load_from_wd_lite(sm);
2014
- });
2015
- }
2016
-
2017
- /* remove submodules that no longer exist */
2018
-
2019
- git_strmap_foreach_value(cache->submodules, sm, {
2020
- /* purge unless in HEAD, index, or .gitmodules; no sm for wd only */
2021
- if (sm != NULL &&
2022
- !(sm->flags &
2023
- (GIT_SUBMODULE_STATUS_IN_HEAD |
2024
- GIT_SUBMODULE_STATUS_IN_INDEX |
2025
- GIT_SUBMODULE_STATUS_IN_CONFIG)))
2026
- submodule_cache_remove_item(cache, sm, true);
2027
- });
2028
-
2029
- cleanup:
2030
- git_config_file_free(mods);
2031
-
2032
- /* TODO: if we got an error, mark submodule config as invalid? */
2033
-
2034
- git_mutex_unlock(&cache->lock);
2035
-
2036
- git_index_free(idx);
2037
- git_tree_free(head);
2038
- git_buf_free(&path);
2039
-
2040
- return error;
2041
- }
2042
-
2043
- static int submodule_cache_init(git_repository *repo, int cache_refresh)
2044
- {
2045
- int error = 0;
2046
- git_submodule_cache *cache = NULL;
2047
-
2048
- /* if submodules already exist, just refresh as requested */
2049
- if (repo->_submodules)
2050
- return submodule_cache_refresh(repo->_submodules, cache_refresh);
2051
-
2052
- /* otherwise create a new cache, load it, and atomically swap it in */
2053
- if (!(error = submodule_cache_alloc(&cache, repo)) &&
2054
- !(error = submodule_cache_refresh(cache, CACHE_FLUSH)))
2055
- cache = git__compare_and_swap(&repo->_submodules, NULL, cache);
2056
-
2057
- /* might have raced with another thread to set cache, so free if needed */
2058
- if (cache)
2059
- submodule_cache_free(cache);
2060
-
2061
- return error;
2062
- }
2063
-
2064
1810
  /* Lookup name of remote of the local tracking branch HEAD points to */
2065
1811
  static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
2066
1812
  {