Signed-off-by: Jonathan Tan <jonathantanmy@xxxxxxxxxx> --- submodule.c | 76 +++++++++++++++++++++++++++++++++++++------------------------ submodule.h | 3 +++ 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/submodule.c b/submodule.c index bb531e0e5..ce511180e 100644 --- a/submodule.c +++ b/submodule.c @@ -1977,16 +1977,24 @@ void absorb_git_dir_into_superproject(const char *prefix, } } -const char *get_superproject_working_tree(void) +/* + * Get the full filename of the gitlink entry corresponding to the + * superproject having this repo as a submodule. + * + * full_name will point to an internal buffer upon success. + * + * Return 0 if successful, 1 if not (for example, if the parent + * directory is not a repo or an unrelated one). + */ +int get_superproject_entry(const char **full_name) { + static struct strbuf sb = STRBUF_INIT; + struct child_process cp = CHILD_PROCESS_INIT; - struct strbuf sb = STRBUF_INIT; const char *one_up = real_path_if_valid("../"); const char *cwd = xgetcwd(); - const char *ret = NULL; const char *subpath; int code; - ssize_t len; if (!is_inside_work_tree()) /* @@ -1994,11 +2002,15 @@ const char *get_superproject_working_tree(void) * We might have a superproject, but it is harder * to determine. */ - return NULL; + return 1; if (!one_up) - return NULL; + return 1; + /* + * No need to reset sb, since relative_path() will do it if + * necessary. + */ subpath = relative_path(cwd, one_up, &sb); prepare_submodule_repo_env(&cp.env_array); @@ -2017,45 +2029,49 @@ const char *get_superproject_working_tree(void) if (start_command(&cp)) die(_("could not start ls-files in ..")); - len = strbuf_read(&sb, cp.out, PATH_MAX); + strbuf_read(&sb, cp.out, PATH_MAX); close(cp.out); - if (starts_with(sb.buf, "160000")) { - int super_sub_len; - int cwd_len = strlen(cwd); - char *super_sub, *super_wt; + code = finish_command(&cp); + if (starts_with(sb.buf, "160000")) { /* * There is a superproject having this repo as a submodule. * The format is <mode> SP <hash> SP <stage> TAB <full name> \0, * We're only interested in the name after the tab. */ - super_sub = strchr(sb.buf, '\t') + 1; - super_sub_len = sb.buf + sb.len - super_sub - 1; - - if (super_sub_len > cwd_len || - strcmp(&cwd[cwd_len - super_sub_len], super_sub)) - die (_("BUG: returned path string doesn't match cwd?")); - - super_wt = xstrdup(cwd); - super_wt[cwd_len - super_sub_len] = '\0'; - - ret = real_path(super_wt); - free(super_wt); + char *tab = strchr(sb.buf, '\t'); + if (!tab) + die("BUG: ls-files returned line with no tab"); + *full_name = tab + 1; + return 0; } - strbuf_release(&sb); - - code = finish_command(&cp); if (code == 128) /* '../' is not a git repository */ - return NULL; - if (code == 0 && len == 0) + return 1; + if (code == 0) /* There is an unrelated git repository at '../' */ + return 1; + die(_("ls-tree returned unexpected return code %d"), code); +} + +const char *get_superproject_working_tree(void) +{ + const char *full_name; + char *super_wt; + size_t len; + const char *ret; + + if (get_superproject_entry(&full_name)) return NULL; - if (code) - die(_("ls-tree returned unexpected return code %d"), code); + super_wt = xstrdup(xgetcwd()); + if (!strip_suffix(super_wt, full_name, &len)) + die("BUG: returned path string doesn't match cwd?"); + super_wt[len] = '\0'; + ret = real_path(super_wt); + free(super_wt); return ret; } diff --git a/submodule.h b/submodule.h index f0da0277a..29ab302cc 100644 --- a/submodule.h +++ b/submodule.h @@ -134,6 +134,9 @@ extern void absorb_git_dir_into_superproject(const char *prefix, * Return the absolute path of the working tree of the superproject, which this * project is a submodule of. If this repository is not a submodule of * another repository, return NULL. + * + * The return value, if not NULL, points to the same shared buffer as the one + * returned by real_path(). */ extern const char *get_superproject_working_tree(void); -- 2.15.0.531.g2ccb3012c9-goog