git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCHv2] submodule: Port resolve_relative_url from shell to C

From
Johannes Sixt <j6t@kdbg.org>
Date
Dec 17, 2015, 18:55 UTC
Message-ID
<5673052F.7050000@kdbg.org>
In-Reply-To
<1450311999-3992-2-git-send-email-sbeller@google.com>
Am 17.12.2015 um 01:26 schrieb Stefan Beller:
Show 22 quoted lines
> This reimplements the helper function `resolve_relative_url` in shell
> in C. This functionality is needed in C for introducing the groups
> feature later on. When using groups, the user should not need to run
> `git submodule init`, but it should be implicit at all appropriate places,
> which are all in C code. As the we would not just call out to `git
> submodule init`, but do a more fine grained structure there, we actually
> need all the init functionality in C before attempting the groups
> feature. To get the init functionality in C, rewriting the
> resolve_relative_url subfunction is a major step.
>
> This also improves the performance:
> (Best out of 3) time ./t7400-submodule-basic.sh
> Before:
> real	0m9.575s
> user	0m2.683s
> sys	0m6.773s
> After:
> real	0m9.293s
> user	0m2.691s
> sys	0m6.549s
>
> That's about 3%.

I appreciate this effort as it should help us on Windows. Although the numbers (and my own timings) suggest that this is only a small step forward. That's not surprising as the patch removes only two forks.

As to the implementation, find a patch below that removes the ifdefs and a few other suggestions. It is a mechanical conversion without understanding what relative_url() does. I have the gut feeling that the two strbuf_addf towards the end of the function can be contracted and the temporarily allocate copy in 'out' can be removed.

If there were a few examples in the comment above the function, it would be much simpler to understand.

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b925bed..8ec0975 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -11,6 +11,7 @@
 #include "run-command.h"
 #include "remote.h"
 #include "refs.h"
+#include "connect.h"
 
 static const char *get_default_remote(void)
 {
@@ -31,34 +32,23 @@ static const char *get_default_remote(void)
 		return xstrdup(dest);
 }
 
-static int has_same_dir_prefix(const char *str, const char **out)
+static int starts_with_dot_slash(const char *str)
 {
-#ifdef GIT_WINDOWS_NATIVE
-	return skip_prefix(str, "./", out)
-		|| skip_prefix(str, ".\\", out);
-#else
-	return skip_prefix(str, "./", out);
-#endif
+	return str[0] == '.' && is_dir_sep(str[1]);
 }
 
-static int has_upper_dir_prefix(const char *str, const char **out)
+static int starts_with_dot_dot_slash(const char *str)
 {
-#ifdef GIT_WINDOWS_NATIVE
-	return skip_prefix(str, "../", out)
-		|| skip_prefix(str, "..\\", out);
-#else
-	return skip_prefix(str, "../", out);
-#endif
+	return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
 }
 
-static char *last_dir_separator(const char *str)
+static char *last_dir_separator(char *str)
 {
-#ifdef GIT_WINDOWS_NATIVE
-	return strrchr(str, "/")
-		|| strrchr(str, "\\");
-#else
-	return strrchr(str, '/');
-#endif
+	char* p = str + strlen(str);
+	while (p-- != str)
+		if (is_dir_sep(*p))
+			return p;
+	return NULL;
 }
 
 /*
@@ -85,9 +75,10 @@ static const char *relative_url(const char *url, const char *up_path)
 	size_t len;
 	char *remoteurl = NULL;
 	char *sep = "/";
-	const char *out;
+	char *out;
 	struct strbuf sb = STRBUF_INIT;
 	const char *remote = get_default_remote();
+
 	strbuf_addf(&sb, "remote.%s.url", remote);
 
 	if (git_config_get_string(sb.buf, &remoteurl))
@@ -98,22 +89,23 @@ static const char *relative_url(const char *url, const char *up_path)
 	if (is_dir_sep(remoteurl[len]))
 		remoteurl[len] = '\0';
 
-	if (strchr(remoteurl, ':') || is_dir_sep(*remoteurl))
+	if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
 		is_relative = 0;
-	else if (has_same_dir_prefix(remoteurl, &out) ||
-		    has_upper_dir_prefix(remoteurl, &out))
+	else if (starts_with_dot_slash(remoteurl) ||
+		    starts_with_dot_dot_slash(remoteurl))
 		is_relative = 1;
 	else {
 		is_relative = 1;
 		strbuf_reset(&sb);
 		strbuf_addf(&sb, "./%s", remoteurl);
+		free(remoteurl);
 		remoteurl = strbuf_detach(&sb, NULL);
 	}
 
 	while (url) {
-		if (has_upper_dir_prefix(url, &out)) {
+		if (starts_with_dot_dot_slash(url)) {
 			char *rfind;
-			url = out;
+			url += 3;
 
 			rfind = last_dir_separator(remoteurl);
 			if (rfind)
@@ -130,22 +122,23 @@ static const char *relative_url(const char *url, const char *up_path)
 						remoteurl = ".";
 				}
 			}
-		} else if (has_same_dir_prefix(url, &out))
-			url = out;
-		else
+		} else if (starts_with_dot_slash(url)) {
+			url += 2;
+		} else
 			break;
 	}
 	strbuf_reset(&sb);
 	strbuf_addf(&sb, "%s%s%s", remoteurl, sep, url);
 
-	if (!has_same_dir_prefix(sb.buf, &out))
-		out = sb.buf;
-	out = xstrdup(out);
+	if (starts_with_dot_slash(sb.buf))
+		out = strdup(sb.buf + 2);
+	else
+		out = xstrdup(sb.buf);
 
 	strbuf_reset(&sb);
 	strbuf_addf(&sb, "%s%s", is_relative && up_path ? up_path : "", out);
 
-	free((char*)out);
+	free(out);
 	return strbuf_detach(&sb, NULL);
 }
 
Previous: Eric SunshineNext: Johannes Sixt
Message 7 of 11 in “submodule: Port resolve_relative_url from shell to C”
  1. submodule: Port resolve_relative_url from shell to CStefan Beller, Dec 10, 2015
  2. Johannes SixtDec 10, 2015
  3. Stefan BellerDec 16, 2015
  4. [PATCHv2] Porting resolve_relative_url from shell to CStefan Beller, Dec 17, 2015
  5. [PATCHv2] submodule: Port resolve_relative_url from shell to CStefan Beller, Dec 17, 2015
  6. Eric SunshineDec 17, 2015
  7. Johannes SixtDec 17, 2015
  8. Johannes SixtDec 17, 2015
  9. Jeff KingDec 18, 2015
  10. Stefan BellerJan 11, 2016
  11. Torsten BögershausenDec 17, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.