rugged 0.23.0b2 → 0.23.0b4

Sign up to get free protection for your applications and to get access to all the features.
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
  {