1 #include <string.h>
2 
3 #include "git2.h"
4 
5 #include "egit.h"
6 #include "egit-options.h"
7 #include "egit-util.h"
8 #include "interface.h"
9 #include "egit-submodule.h"
10 
11 
12 // =============================================================================
13 // Helpers - status values
14 
status_decode(emacs_env * env,emacs_value flag,unsigned int status)15 static emacs_value status_decode(emacs_env *env, emacs_value flag, unsigned int status)
16 {
17     if (EM_EXTRACT_BOOLEAN(flag)) {
18         emacs_value retval;
19         em_checkflag_submodule_status(&retval, env, flag, status, true);
20         return retval;
21     }
22 
23     return em_getlist_submodule_status(env, status);
24 }
25 
26 
27 // =============================================================================
28 // Constructors
29 
30 EGIT_DOC(submodule_add_setup, "REPO URL PATH &optional LINKP",
31          "Set up a new submodule for checkout.\n"
32          "This emulates `git submodule add' up to fetch and checkout.\n"
33          "If LINK is non-nil, PATH will contain a git link to a repo\n"
34          "in REPO's own .git/modules.");
egit_submodule_add_setup(emacs_env * env,emacs_value _repo,emacs_value _url,emacs_value _path,emacs_value linkp)35 emacs_value egit_submodule_add_setup(
36     emacs_env *env, emacs_value _repo, emacs_value _url,
37     emacs_value _path, emacs_value linkp)
38 {
39     EGIT_ASSERT_REPOSITORY(_repo);
40     EM_ASSERT_STRING(_url);
41     EM_ASSERT_STRING(_path);
42 
43     git_repository *repo = EGIT_EXTRACT(_repo);
44     char *url = EM_EXTRACT_STRING(_url);
45     char *path = EM_EXTRACT_STRING(_path);
46     git_submodule *sub;
47     int retval = git_submodule_add_setup(&sub, repo, url, path, EM_EXTRACT_BOOLEAN(linkp));
48     free(url);
49     free(path);
50     EGIT_CHECK_ERROR(retval);
51 
52     return egit_wrap(env, EGIT_SUBMODULE, sub, EM_EXTRACT_USER_PTR(_repo));
53 }
54 
55 EGIT_DOC(submodule_lookup, "REPO NAME", "Look up a submodule in REPO by NAME or path.");
egit_submodule_lookup(emacs_env * env,emacs_value _repo,emacs_value _name)56 emacs_value egit_submodule_lookup(emacs_env *env, emacs_value _repo, emacs_value _name)
57 {
58     EGIT_ASSERT_REPOSITORY(_repo);
59     EM_ASSERT_STRING(_name);
60 
61     git_repository *repo = EGIT_EXTRACT(_repo);
62     char *name = EM_EXTRACT_STRING(_name);
63     git_submodule *sub;
64     int retval = git_submodule_lookup(&sub, repo, name);
65     free(name);
66     EGIT_CHECK_ERROR(retval);
67 
68     return egit_wrap(env, EGIT_SUBMODULE, sub, EM_EXTRACT_USER_PTR(_repo));
69 }
70 
71 
72 // =============================================================================
73 // Getters
74 
75 EGIT_DOC(submodule_branch, "SUBMODULE", "Get the branch name for SUBMODULE.");
egit_submodule_branch(emacs_env * env,emacs_value _sub)76 emacs_value egit_submodule_branch(emacs_env *env, emacs_value _sub)
77 {
78     EGIT_ASSERT_SUBMODULE(_sub);
79     git_submodule *sub = EGIT_EXTRACT(_sub);
80     const char *branch = git_submodule_branch(sub);
81     if (!branch)
82         return esym_nil;
83     return EM_STRING(branch);
84 }
85 
86 EGIT_DOC(submodule_fetch_recurse_submodules, "SUBMODULE",
87          "Get the fetchRecurseSubmodules rule for SUBMODULE.\n"
88          "This is `nil', `ondemand' or `t'.");
egit_submodule_fetch_recurse_submodules(emacs_env * env,emacs_value _sub)89 emacs_value egit_submodule_fetch_recurse_submodules(emacs_env *env, emacs_value _sub)
90 {
91     EGIT_ASSERT_SUBMODULE(_sub);
92     git_submodule *sub = EGIT_EXTRACT(_sub);
93     git_submodule_recurse_t rec = git_submodule_fetch_recurse_submodules(sub);
94     return em_findenum_submodule_recurse(rec);
95 }
96 
97 EGIT_DOC(submodule_head_id, "SUBMODULE", "Get the ID for SUBMODULE in HEAD.");
egit_submodule_head_id(emacs_env * env,emacs_value _sub)98 emacs_value egit_submodule_head_id(emacs_env *env, emacs_value _sub)
99 {
100     EGIT_ASSERT_SUBMODULE(_sub);
101     git_submodule *sub = EGIT_EXTRACT(_sub);
102     const git_oid *oid = git_submodule_head_id(sub);
103     if (!oid)
104         return esym_nil;
105     const char *oid_s = git_oid_tostr_s(oid);
106     return EM_STRING(oid_s);
107 }
108 
109 EGIT_DOC(submodule_ignore, "SUBMODULE",
110          "Get the ignore rule for SUBMODULE.\n"
111          "This is one of the symbols `none', `untracked', `dirty' and `all'.");
egit_submodule_ignore(emacs_env * env,emacs_value _sub)112 emacs_value egit_submodule_ignore(emacs_env *env, emacs_value _sub)
113 {
114     EGIT_ASSERT_SUBMODULE(_sub);
115     git_submodule *sub = EGIT_EXTRACT(_sub);
116     git_submodule_ignore_t ignore = git_submodule_ignore(sub);
117     return em_findenum_submodule_ignore(ignore);
118 }
119 
120 EGIT_DOC(submodule_index_id, "SUBMODULE", "Get the ID for SUBMODULE in the index.");
egit_submodule_index_id(emacs_env * env,emacs_value _sub)121 emacs_value egit_submodule_index_id(emacs_env *env, emacs_value _sub)
122 {
123     EGIT_ASSERT_SUBMODULE(_sub);
124     git_submodule *sub = EGIT_EXTRACT(_sub);
125     const git_oid *oid = git_submodule_index_id(sub);
126     if (!oid)
127         return esym_nil;
128     const char *oid_s = git_oid_tostr_s(oid);
129     return EM_STRING(oid_s);
130 }
131 
132 EGIT_DOC(submodule_location, "SUBMODULE &optional FLAG",
133          "Get the location of SUBMODULE.\n"
134          "This is a lightweight version of `libgit-submodule-status',\n"
135          "only checking the first four status values: `in-head', `in-index',\n"
136          "`in-config' and `in-wd'.\n\n"
137          "See `libgit-submodule-status' for an explanation of FLAG.");
egit_submodule_location(emacs_env * env,emacs_value _sub,emacs_value flag)138 emacs_value egit_submodule_location(emacs_env *env, emacs_value _sub, emacs_value flag)
139 {
140     EGIT_ASSERT_SUBMODULE(_sub);
141     git_submodule *sub = EGIT_EXTRACT(_sub);
142     unsigned int loc;
143     int retval = git_submodule_location(&loc, sub);
144     EGIT_CHECK_ERROR(retval);
145 
146     return status_decode(env, flag, loc);
147 }
148 
149 EGIT_DOC(submodule_name, "SUBMODULE", "Get the name of SUBMODULE.");
egit_submodule_name(emacs_env * env,emacs_value _sub)150 emacs_value egit_submodule_name(emacs_env *env, emacs_value _sub)
151 {
152     EGIT_ASSERT_SUBMODULE(_sub);
153     git_submodule *sub = EGIT_EXTRACT(_sub);
154     const char *name = git_submodule_name(sub);
155     return EM_STRING(name);
156 }
157 
158 EGIT_DOC(submodule_open, "SUBMODULE", "Get the sub-repository associated with SUBMODULE.");
egit_submodule_open(emacs_env * env,emacs_value _sub)159 emacs_value egit_submodule_open(emacs_env *env, emacs_value _sub)
160 {
161     EGIT_ASSERT_SUBMODULE(_sub);
162     git_submodule *sub = EGIT_EXTRACT(_sub);
163     git_repository *repo;
164     int retval = git_submodule_open(&repo, sub);
165     EGIT_CHECK_ERROR(retval);
166     return egit_wrap(env, EGIT_REPOSITORY, repo, NULL);
167 }
168 
169 EGIT_DOC(submodule_owner, "SUBMODULE", "Get the repository in which SUBMODULE lives.");
egit_submodule_owner(emacs_env * env,emacs_value _sub)170 emacs_value egit_submodule_owner(emacs_env *env, emacs_value _sub)
171 {
172     EGIT_ASSERT_SUBMODULE(_sub);
173     egit_object *owner = EGIT_EXTRACT_PARENT(_sub);
174     owner->refcount++;
175     return EM_USER_PTR(owner, egit_finalize);
176 }
177 
178 EGIT_DOC(submodule_path, "SUBMODULE", "Get the path of SUBMODULE.");
egit_submodule_path(emacs_env * env,emacs_value _sub)179 emacs_value egit_submodule_path(emacs_env *env, emacs_value _sub)
180 {
181     EGIT_ASSERT_SUBMODULE(_sub);
182     git_submodule *sub = EGIT_EXTRACT(_sub);
183     const char *path = git_submodule_path(sub);
184     return EM_STRING(path);
185 }
186 
187 EGIT_DOC(submodule_status, "REPO NAME &optional IGNORE FLAG",
188          "Get a list of symbols describing the status of a submodule.\n"
189          "REPO is the repository to search in, and NAME is the name of the submodule.\n"
190          "IGNORE indicates the ignore rule to use, one of `none' (default), `untracked',\n"
191          "`dirty' and `all'.\n\n"
192          "The following are always returned.\n"
193          "- `in-head': superproject head contains submodule\n"
194          "- `in-index': superproject index contains submodule\n"
195          "- `in-config': superproject gitmodules contains submodule\n"
196          "- `in-wd': superproject workdir contains submodule\n\n"
197          "The following are returned as long as IGNORE is not `all'.\n"
198          "- `index-added': submodule is in index, not in head\n"
199          "- `index-deleted': submodule is in head, not in index\n"
200          "- `index-modified': index and head don't match\n"
201          "- `wd-uninitialized': workdir contains empty directory\n"
202          "- `wd-added': in workdir, but not index\n"
203          "- `wd-deleted': in index, but not workdir\n"
204          "- `wd-modified': index and workdir head don't match\n\n"
205          "The following are only returned if IGNORE Is `none' or `untracked'.\n"
206          "- `wd-index-modified': submodule workdir index is dirty\n"
207          "- `wd-wd-modified': submodule workdir has modified files\n\n"
208          "The following is only returned if the IGNORE is `none':\n"
209          "- `wd-untracked': submodule workdir contains untracked files\n\n"
210          "If the optional FLAG is non-nil, it may be any of the above symbols,\n"
211          "in which case the return value is non-nil if that flag is present.\n"
212          "In other words, these are equivalent:\n\n"
213          "(libgit-submodule-status REPO NAME IGNORE FLAG)\n\n"
214          "(memq FLAG (libgit-submodule-status REPO NAME IGNORE))");
egit_submodule_status(emacs_env * env,emacs_value _repo,emacs_value _name,emacs_value _ignore,emacs_value flag)215 emacs_value egit_submodule_status(
216     emacs_env *env, emacs_value _repo, emacs_value _name,
217     emacs_value _ignore, emacs_value flag)
218 {
219     EGIT_ASSERT_REPOSITORY(_repo);
220     EM_ASSERT_STRING(_name);
221 
222     git_submodule_ignore_t ignore;
223     if (!em_findsym_submodule_ignore(&ignore, env, _ignore, true))
224         return esym_nil;
225 
226     git_repository *repo = EGIT_EXTRACT(_repo);
227     char *name = EM_EXTRACT_STRING(_name);
228 
229     unsigned int status;
230     int retval = git_submodule_status(&status, repo, name, ignore);
231     free(name);
232     EGIT_CHECK_ERROR(retval);
233 
234     return status_decode(env, flag, status);
235 }
236 
237 EGIT_DOC(submodule_update_strategy, "SUBMODULE",
238          "Get the update rule for SUBMODULE.\n"
239          "This is one of the symbols `checkout', `rebase', `merge' and `none'.");
egit_submodule_update_strategy(emacs_env * env,emacs_value _sub)240 emacs_value egit_submodule_update_strategy(emacs_env *env, emacs_value _sub)
241 {
242     EGIT_ASSERT_SUBMODULE(_sub);
243     git_submodule *sub = EGIT_EXTRACT(_sub);
244     git_submodule_update_t update = git_submodule_update_strategy(sub);
245     return em_findenum_submodule_update(update);
246 }
247 
248 EGIT_DOC(submodule_url, "SUBMODULE", "Get the url of SUBMODULE.");
egit_submodule_url(emacs_env * env,emacs_value _sub)249 emacs_value egit_submodule_url(emacs_env *env, emacs_value _sub)
250 {
251     EGIT_ASSERT_SUBMODULE(_sub);
252     git_submodule *sub = EGIT_EXTRACT(_sub);
253     const char *url = git_submodule_url(sub);
254     return EM_STRING(url);
255 }
256 
257 EGIT_DOC(submodule_wd_id, "SUBMODULE", "Get the ID for SUBMODULE in the working directory.");
egit_submodule_wd_id(emacs_env * env,emacs_value _sub)258 emacs_value egit_submodule_wd_id(emacs_env *env, emacs_value _sub)
259 {
260     EGIT_ASSERT_SUBMODULE(_sub);
261     git_submodule *sub = EGIT_EXTRACT(_sub);
262     const git_oid *oid = git_submodule_wd_id(sub);
263     if (!oid)
264         return esym_nil;
265     const char *oid_s = git_oid_tostr_s(oid);
266     return EM_STRING(oid_s);
267 }
268 
269 
270 // =============================================================================
271 // Foreach
272 
submodule_callback(git_submodule * sub,const char * name,void * payload)273 static int submodule_callback(git_submodule *sub, const char *name, void *payload)
274 {
275     egit_generic_payload *ctx = (egit_generic_payload*) payload;
276     emacs_env *env = ctx->env;
277 
278     emacs_value args[2];
279     args[0] = egit_wrap(env, EGIT_SUBMODULE, sub, ctx->parent);
280     args[1] = EM_STRING(name);
281     env->funcall(env, ctx->func, 2, args);
282 
283     EM_RETURN_IF_NLE(GIT_EUSER);
284     return 0;
285 }
286 
287 EGIT_DOC(submodule_foreach, "REPO FUNC",
288          "Call FUNC for each submodule in REPO.\n"
289          "FUNC receives two arguments: the submodule object and its name.");
egit_submodule_foreach(emacs_env * env,emacs_value _repo,emacs_value func)290 emacs_value egit_submodule_foreach(emacs_env *env, emacs_value _repo, emacs_value func)
291 {
292     EGIT_ASSERT_REPOSITORY(_repo);
293     EM_ASSERT_FUNCTION(func);
294 
295     egit_generic_payload ctx = {.env = env, .func = func, .parent = EM_EXTRACT_USER_PTR(_repo)};
296     git_repository *repo = EGIT_EXTRACT(_repo);
297     int retval = git_submodule_foreach(repo, &submodule_callback, &ctx);
298 
299     EM_RETURN_NIL_IF_NLE();
300     if (retval == GIT_EUSER)
301         return esym_nil;
302     EGIT_CHECK_ERROR(retval);
303     return esym_nil;
304 }
305 
306 
307 // =============================================================================
308 // Operations
309 
310 EGIT_DOC(submodule_add_finalize, "SUBMODULE",
311          "Resolve the setup of SUBMODULE.\n"
312          "This should be called after `libgit-add-setup', and after clone.");
egit_submodule_add_finalize(emacs_env * env,emacs_value _sub)313 emacs_value egit_submodule_add_finalize(emacs_env *env, emacs_value _sub)
314 {
315     EGIT_ASSERT_SUBMODULE(_sub);
316     git_submodule *sub = EGIT_EXTRACT(_sub);
317     int retval = git_submodule_add_finalize(sub);
318     EGIT_CHECK_ERROR(retval);
319     return esym_nil;
320 }
321 
322 EGIT_DOC(submodule_add_to_index, "SUBMODULE WRITE",
323          "Add HEAD of SUBMODULE to index in superproject.\n"
324          "If WRITE is non-nil, the index will be immediately written.");
egit_submodule_add_to_index(emacs_env * env,emacs_value _sub,emacs_value write)325 emacs_value egit_submodule_add_to_index(emacs_env *env, emacs_value _sub, emacs_value write)
326 {
327     EGIT_ASSERT_SUBMODULE(_sub);
328     git_submodule *sub = EGIT_EXTRACT(_sub);
329     int retval = git_submodule_add_to_index(sub, EM_EXTRACT_BOOLEAN(write));
330     EGIT_CHECK_ERROR(retval);
331     return esym_nil;
332 }
333 
334 EGIT_DOC(submodule_init, "SUBMODULE &optional FORCE",
335          "Copy submodule info to .git/config.\n"
336          "If FORCE is non-nil, overwrite even if an entry already exists.");
egit_submodule_init(emacs_env * env,emacs_value _sub,emacs_value force)337 emacs_value egit_submodule_init(emacs_env *env, emacs_value _sub, emacs_value force)
338 {
339     EGIT_ASSERT_SUBMODULE(_sub);
340     git_submodule *sub = EGIT_EXTRACT(_sub);
341     int retval = git_submodule_init(sub, EM_EXTRACT_BOOLEAN(force));
342     EGIT_CHECK_ERROR(retval);
343     return esym_nil;
344 }
345 
346 EGIT_DOC(submodule_reload, "SUBMODULE &optional FORCE",
347          "Re-read info about SUBMODULE from config, index and HEAD.\n"
348          "If FORCE is non-nil, force reload even if data does not seem\n"
349          "outdated.");
egit_submodule_reload(emacs_env * env,emacs_value _sub,emacs_value force)350 emacs_value egit_submodule_reload(emacs_env *env, emacs_value _sub, emacs_value force)
351 {
352     EGIT_ASSERT_SUBMODULE(_sub);
353     git_submodule *sub = EGIT_EXTRACT(_sub);
354     int retval = git_submodule_reload(sub, EM_EXTRACT_BOOLEAN(force));
355     EGIT_CHECK_ERROR(retval);
356     return esym_nil;
357 }
358 
359 EGIT_DOC(submodule_repo_init, "SUBMODULE &optional LINKP",
360          "Set up and return the subrepo for SUBMODULE in preparation for clone.\n"
361          "If LINK is non-nil, the subrepo will contain a git link to a repo\n"
362          "in the parent repository's own .git/modules.");
egit_submodule_repo_init(emacs_env * env,emacs_value _sub,emacs_value linkp)363 emacs_value egit_submodule_repo_init(emacs_env *env, emacs_value _sub, emacs_value linkp)
364 {
365     EGIT_ASSERT_SUBMODULE(_sub);
366     git_submodule *sub = EGIT_EXTRACT(_sub);
367     git_repository *repo;
368     int retval = git_submodule_repo_init(&repo, sub, EM_EXTRACT_BOOLEAN(linkp));
369     EGIT_CHECK_ERROR(retval);
370     return egit_wrap(env, EGIT_REPOSITORY, repo, NULL);
371 }
372 
373 EGIT_DOC(submodule_set_branch, "REPO NAME BRANCHNAME",
374          "Set the branch of submodule NAME to BRANCHNAME.\n"
375          "After this, you may wish to call `libgit-submodule-sync'.");
egit_submodule_set_branch(emacs_env * env,emacs_value _repo,emacs_value _name,emacs_value _refname)376 emacs_value egit_submodule_set_branch(
377     emacs_env *env, emacs_value _repo, emacs_value _name, emacs_value _refname)
378 {
379     EGIT_ASSERT_REPOSITORY(_repo);
380     EM_ASSERT_STRING(_name);
381     EM_ASSERT_STRING(_refname);
382 
383     git_repository *repo = EGIT_EXTRACT(_repo);
384     char *name = EM_EXTRACT_STRING(_name);
385     char *refname = EM_EXTRACT_STRING(_refname);
386     int retval = git_submodule_set_branch(repo, name, refname);
387     free(name);
388     free(refname);
389     EGIT_CHECK_ERROR(retval);
390 
391     return esym_nil;
392 }
393 
394 EGIT_DOC(submodule_set_fetch_recurse_submodules, "REPO NAME &optional VALUE",
395          "Set the fetchRecurseSubmodules rule for submodule NAME.\n"
396          "Possible VALUE are nil, `ondemand', or other non-nil.");
egit_submodule_set_fetch_recurse_submodules(emacs_env * env,emacs_value _repo,emacs_value _name,emacs_value _value)397 emacs_value egit_submodule_set_fetch_recurse_submodules(
398     emacs_env *env, emacs_value _repo, emacs_value _name, emacs_value _value)
399 {
400     EGIT_ASSERT_REPOSITORY(_repo);
401     EM_ASSERT_STRING(_name);
402 
403     git_submodule_recurse_t value;
404     if (!em_findsym_submodule_recurse(&value, env, _value, false))
405         value = GIT_SUBMODULE_RECURSE_YES;
406 
407     git_repository *repo = EGIT_EXTRACT(_repo);
408     char *name = EM_EXTRACT_STRING(_name);
409     int retval = git_submodule_set_fetch_recurse_submodules(repo, name, value);
410     free(name);
411     EGIT_CHECK_ERROR(retval);
412 
413     return esym_nil;
414 }
415 
416 EGIT_DOC(submodule_set_ignore, "REPO NAME VALUE",
417          "Set the ignore rule for submodule NAME.\n"
418          "Possible VALUE are `none', `dirty', `untracked' and `all'.");
egit_submodule_set_ignore(emacs_env * env,emacs_value _repo,emacs_value _name,emacs_value _value)419 emacs_value egit_submodule_set_ignore(
420     emacs_env *env, emacs_value _repo, emacs_value _name, emacs_value _value)
421 {
422     EGIT_ASSERT_REPOSITORY(_repo);
423     EM_ASSERT_STRING(_name);
424 
425     git_submodule_ignore_t value;
426     if (!em_findsym_submodule_ignore(&value, env, _value, true))
427         return esym_nil;
428 
429     git_repository *repo = EGIT_EXTRACT(_repo);
430     char *name = EM_EXTRACT_STRING(_name);
431     int retval = git_submodule_set_ignore(repo, name, value);
432     free(name);
433     EGIT_CHECK_ERROR(retval);
434 
435     return esym_nil;
436 }
437 
438 EGIT_DOC(submodule_set_update, "REPO NAME VALUE",
439          "Set the ignore rule for submodule NAME.\n"
440          "Possible VALUE are `checkout', `rebase', `merge' and `none'.");
egit_submodule_set_update(emacs_env * env,emacs_value _repo,emacs_value _name,emacs_value _value)441 emacs_value egit_submodule_set_update(
442     emacs_env *env, emacs_value _repo, emacs_value _name, emacs_value _value)
443 {
444     EGIT_ASSERT_REPOSITORY(_repo);
445     EM_ASSERT_STRING(_name);
446 
447     git_submodule_update_t value;
448     if (!em_findsym_submodule_update(&value, env, _value, true))
449         return esym_nil;
450 
451     git_repository *repo = EGIT_EXTRACT(_repo);
452     char *name = EM_EXTRACT_STRING(_name);
453     int retval = git_submodule_set_update(repo, name, value);
454     free(name);
455     EGIT_CHECK_ERROR(retval);
456 
457     return esym_nil;
458 }
459 
460 EGIT_DOC(submodule_set_url, "REPO NAME URL",
461          "Set the URL of submodule NAME to URL.\n"
462          "After this, you may wish to call `libgit-submodule-sync'.");
egit_submodule_set_url(emacs_env * env,emacs_value _repo,emacs_value _name,emacs_value _url)463 emacs_value egit_submodule_set_url(
464     emacs_env *env, emacs_value _repo, emacs_value _name, emacs_value _url)
465 {
466     EGIT_ASSERT_REPOSITORY(_repo);
467     EM_ASSERT_STRING(_name);
468     EM_ASSERT_STRING(_url);
469 
470     git_repository *repo = EGIT_EXTRACT(_repo);
471     char *name = EM_EXTRACT_STRING(_name);
472     char *url = EM_EXTRACT_STRING(_url);
473     int retval = git_submodule_set_url(repo, name, url);
474     free(name);
475     free(url);
476     EGIT_CHECK_ERROR(retval);
477 
478     return esym_nil;
479 }
480 
481 EGIT_DOC(submodule_sync, "SUBMODULE", "Copy SUBMODULE's remote info into its repository.");
egit_submodule_sync(emacs_env * env,emacs_value _sub)482 emacs_value egit_submodule_sync(emacs_env *env, emacs_value _sub)
483 {
484     EGIT_ASSERT_SUBMODULE(_sub);
485     git_submodule *sub = EGIT_EXTRACT(_sub);
486     int retval = git_submodule_sync(sub);
487     EGIT_CHECK_ERROR(retval);
488     return esym_nil;
489 }
490 
491 EGIT_DOC(submodule_update, "SUBMODULE &optional INITP FETCHP CHECKOUT-OPTS FETCH-OPTS",
492          "Update a submodule and checkout the subrepo to the commit\n"
493          "specified in the index of the parent repo.\n"
494          "If the submodule is missing it will be cloned.\n"
495          "If INITP is non-nil, initialize the submodule if not already done.\n"
496          "If FETCHP is non-nil, fetch from the remote if the subrepo does not\n"
497          "contain the desired commit.\n"
498          "For CHECKOUT-OPTS, see `libgit-checkout-head', and for FETCH-OPTS,\n"
499          "see `libgit-remote-fetch'.");
egit_submodule_update(emacs_env * env,emacs_value _sub,emacs_value initp,emacs_value fetchp,emacs_value checkout_opts,emacs_value fetch_opts)500 emacs_value egit_submodule_update(
501     emacs_env *env, emacs_value _sub, emacs_value initp, emacs_value fetchp,
502     emacs_value checkout_opts, emacs_value fetch_opts)
503 {
504     EGIT_ASSERT_SUBMODULE(_sub);
505 
506     git_submodule_update_options opts;
507     opts.allow_fetch = EM_EXTRACT_BOOLEAN(fetchp);
508 
509     egit_checkout_options_parse(env, checkout_opts, &opts.checkout_opts);
510     EM_RETURN_NIL_IF_NLE();
511 
512     egit_fetch_options_parse(env, fetch_opts, &opts.fetch_opts);
513     EM_RETURN_NIL_IF_NLE();
514 
515     git_submodule *sub = EGIT_EXTRACT(_sub);
516     int retval = git_submodule_update(sub, EM_EXTRACT_BOOLEAN(initp), &opts);
517     egit_checkout_options_release(&opts.checkout_opts);
518     egit_fetch_options_release(&opts.fetch_opts);
519     EGIT_CHECK_ERROR(retval);
520 
521     return esym_nil;
522 }
523