git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Johannes Sixt <j6t@kdbg.org>
To: Stefan Beller <sbeller@google.com>
Cc: gitster@pobox.com, git@vger.kernel.org, jens.lehmann@web.de
Subject: Re: [PATCH] submodule: Port resolve_relative_url from shell to C
Date: Thu, 10 Dec 2015 07:48:12 +0100	[thread overview]
Message-ID: <5669202C.2090100@kdbg.org> (raw)
In-Reply-To: <1449709654-30189-1-git-send-email-sbeller@google.com>

Am 10.12.2015 um 02:07 schrieb Stefan Beller:
> 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.

I see lots of '/', but no is_dir_sep() in the C version. Did you 
consider that local URLs can use a backslash as path separator on 
Windows? In the shell version, this did not matter because bash converts 
the backslashes to forward slashes for us. But when rewritten in C, this 
does not happen.

Valid URLs are

   D:\foo\bar.git
   \\server\share\foo\bar
   ..\..\foo\bar

and all of them with some or all backslashes replaced by forward slashes.

See also connect.c:url_is_local_not_ssh, which ensures that the first 
example above is considered a local path with a drive letter, not a 
remote ssh path.

>
> 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
>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---
>
>   This applies on origin/master, and I'd carry as its own feature branch
>   as I am nowhere near done with the groups feature after reading Jens feedback.
>   (It took me a while to identify this as a next best step.)
>
>   Thanks,
>   Stefan
>
>   builtin/submodule--helper.c | 120 ++++++++++++++++++++++++++++++++++++++++++++
>   git-submodule.sh            |  81 ++----------------------------
>   2 files changed, 124 insertions(+), 77 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index f4c3eff..f48b5b5 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -9,6 +9,125 @@
>   #include "submodule-config.h"
>   #include "string-list.h"
>   #include "run-command.h"
> +#include "remote.h"
> +#include "refs.h"
> +
> +static const char *get_default_remote(void)
> +{
> +	char *dest = NULL;
> +	unsigned char sha1[20];
> +	int flag;
> +	struct strbuf sb = STRBUF_INIT;
> +	const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
> +
> +	if (!refname)
> +		die("No such ref: HEAD");
> +
> +	refname = shorten_unambiguous_ref(refname, 0);
> +	strbuf_addf(&sb, "branch.%s.remote", refname);
> +	if (git_config_get_string(sb.buf, &dest))
> +		return "origin";
> +	else
> +		return xstrdup(dest);
> +}
> +
> +/*
> + * The function takes at most 2 arguments. The first argument is the
> + * URL that navigates to the submodule origin repo. When relative, this URL
> + * is relative to the superproject origin URL repo. The second up_path
> + * argument, if specified, is the relative path that navigates
> + * from the submodule working tree to the superproject working tree.
> + *
> + * The output of the function is the origin URL of the submodule.
> + *
> + * The output will either be an absolute URL or filesystem path (if the
> + * superproject origin URL is an absolute URL or filesystem path,
> + * respectively) or a relative file system path (if the superproject
> + * origin URL is a relative file system path).
> + *
> + * When the output is a relative file system path, the path is either
> + * relative to the submodule working tree, if up_path is specified, or to
> + * the superproject working tree otherwise.
> + */
> +static const char *relative_url(const char *url, const char *up_path)
> +{
> +	int is_relative = 0;
> +	size_t len;
> +	char *remoteurl = NULL;
> +	char *sep = "/";
> +	const 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))
> +		/* the repository is its own authoritative upstream */
> +		remoteurl = xgetcwd();
> +
> +	if (strip_suffix(remoteurl, "/", &len))
> +		remoteurl[len] = '\0';
> +
> +	if (strchr(remoteurl, ':') || skip_prefix(remoteurl, "/", &out))
> +		is_relative = 0;
> +	else if (skip_prefix(remoteurl, "./", &out) ||
> +		    skip_prefix(remoteurl, "../", &out))
> +		is_relative = 1;
> +	else {
> +		is_relative = 1;
> +		strbuf_reset(&sb);
> +		strbuf_addf(&sb, "./%s", remoteurl);
> +		remoteurl = strbuf_detach(&sb, NULL);
> +	}
> +
> +	while (url) {
> +		if (skip_prefix(url, "../", &out)) {
> +			char *rfind;
> +			url = out;
> +
> +			rfind = strrchr(remoteurl, '/');
> +			if (rfind)
> +				*rfind = '\0';
> +			else {
> +				rfind = strrchr(remoteurl, ':');
> +				if (rfind) {
> +					*rfind = '\0';
> +					sep = ":";
> +				} else {
> +					if (is_relative || !strcmp(".", remoteurl))
> +						die(N_("cannot strip one component off url '%s'"), remoteurl);
> +					else
> +						remoteurl = ".";
> +				}
> +			}
> +		} else if (skip_prefix(url, "./", &out))
> +			url = out;
> +		else
> +			break;
> +	}
> +	strbuf_reset(&sb);
> +	strbuf_addf(&sb, "%s%s%s", remoteurl, sep, url);
> +
> +	if (!skip_prefix(sb.buf, "./", &out))
> +		out = sb.buf;
> +	out = xstrdup(out);
> +
> +	strbuf_reset(&sb);
> +	strbuf_addf(&sb, "%s%s", is_relative && up_path ? up_path : "", out);
> +
> +	free((char*)out);
> +	return strbuf_detach(&sb, NULL);
> +}
> +
> +static int resolve_relative_url(int argc, const char **argv, const char *prefix)
> +{
> +	if (argc == 2)
> +		printf("%s\n", relative_url(argv[1], NULL));
> +	else if (argc == 3)
> +		printf("%s\n", relative_url(argv[1], argv[2]));
> +	else
> +		die("BUG: resolve_relative_url only accepts one or two arguments");
> +	return 0;
> +}
>
>   struct module_list {
>   	const struct cache_entry **entries;
> @@ -264,6 +383,7 @@ static struct cmd_struct commands[] = {
>   	{"list", module_list},
>   	{"name", module_name},
>   	{"clone", module_clone},
> +	{"resolve_relative_url", resolve_relative_url},
>   };
>
>   int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
> diff --git a/git-submodule.sh b/git-submodule.sh
> index 9bc5c5f..6a7a3e4 100755
> --- a/git-submodule.sh
> +++ b/git-submodule.sh
> @@ -46,79 +46,6 @@ prefix=
>   custom_name=
>   depth=
>
> -# The function takes at most 2 arguments. The first argument is the
> -# URL that navigates to the submodule origin repo. When relative, this URL
> -# is relative to the superproject origin URL repo. The second up_path
> -# argument, if specified, is the relative path that navigates
> -# from the submodule working tree to the superproject working tree.
> -#
> -# The output of the function is the origin URL of the submodule.
> -#
> -# The output will either be an absolute URL or filesystem path (if the
> -# superproject origin URL is an absolute URL or filesystem path,
> -# respectively) or a relative file system path (if the superproject
> -# origin URL is a relative file system path).
> -#
> -# When the output is a relative file system path, the path is either
> -# relative to the submodule working tree, if up_path is specified, or to
> -# the superproject working tree otherwise.
> -resolve_relative_url ()
> -{
> -	remote=$(get_default_remote)
> -	remoteurl=$(git config "remote.$remote.url") ||
> -		remoteurl=$(pwd) # the repository is its own authoritative upstream
> -	url="$1"
> -	remoteurl=${remoteurl%/}
> -	sep=/
> -	up_path="$2"
> -
> -	case "$remoteurl" in
> -	*:*|/*)
> -		is_relative=
> -		;;
> -	./*|../*)
> -		is_relative=t
> -		;;
> -	*)
> -		is_relative=t
> -		remoteurl="./$remoteurl"
> -		;;
> -	esac
> -
> -	while test -n "$url"
> -	do
> -		case "$url" in
> -		../*)
> -			url="${url#../}"
> -			case "$remoteurl" in
> -			*/*)
> -				remoteurl="${remoteurl%/*}"
> -				;;
> -			*:*)
> -				remoteurl="${remoteurl%:*}"
> -				sep=:
> -				;;
> -			*)
> -				if test -z "$is_relative" || test "." = "$remoteurl"
> -				then
> -					die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
> -				else
> -					remoteurl=.
> -				fi
> -				;;
> -			esac
> -			;;
> -		./*)
> -			url="${url#./}"
> -			;;
> -		*)
> -			break;;
> -		esac
> -	done
> -	remoteurl="$remoteurl$sep${url%/}"
> -	echo "${is_relative:+${up_path}}${remoteurl#./}"
> -}
> -
>   # Resolve a path to be relative to another path.  This is intended for
>   # converting submodule paths when git-submodule is run in a subdirectory
>   # and only handles paths where the directory separator is '/'.
> @@ -281,7 +208,7 @@ cmd_add()
>   		die "$(gettext "Relative path can only be used from the toplevel of the working tree")"
>
>   		# dereference source url relative to parent's url
> -		realrepo=$(resolve_relative_url "$repo") || exit
> +		realrepo=$(git submodule--helper resolve_relative_url "$repo") || exit
>   		;;
>   	*:*|/*)
>   		# absolute url
> @@ -485,7 +412,7 @@ cmd_init()
>   			# Possibly a url relative to parent
>   			case "$url" in
>   			./*|../*)
> -				url=$(resolve_relative_url "$url") || exit
> +				url=$(git submodule--helper resolve_relative_url "$url") || exit
>   				;;
>   			esac
>   			git config submodule."$name".url "$url" ||
> @@ -1190,9 +1117,9 @@ cmd_sync()
>   			# guarantee a trailing /
>   			up_path=${up_path%/}/ &&
>   			# path from submodule work tree to submodule origin repo
> -			sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
> +			sub_origin_url=$(git submodule--helper resolve_relative_url "$url" "$up_path") &&
>   			# path from superproject work tree to submodule origin repo
> -			super_config_url=$(resolve_relative_url "$url") || exit
> +			super_config_url=$(git submodule--helper resolve_relative_url "$url") || exit
>   			;;
>   		*)
>   			sub_origin_url="$url"
>

  reply	other threads:[~2015-12-10  6:48 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-10  1:07 [PATCH] submodule: Port resolve_relative_url from shell to C Stefan Beller
2015-12-10  6:48 ` Johannes Sixt [this message]
2015-12-16 22:36   ` Stefan Beller
2015-12-17  0:26 ` [PATCHv2] Porting " Stefan Beller
2015-12-17  7:47   ` Torsten Bögershausen
2015-12-17  0:26 ` [PATCHv2] submodule: Port " Stefan Beller
2015-12-17  8:17   ` Eric Sunshine
2015-12-17 18:55   ` Johannes Sixt
2015-12-17 19:17     ` Johannes Sixt
2015-12-18  3:27     ` Jeff King
2016-01-11 20:17     ` Stefan Beller
  -- strict thread matches above, loose matches on Subject: below --
2016-01-13 18:15 [PATCH] " Stefan Beller
2016-01-13 22:03 ` Junio C Hamano
2016-01-13 22:47   ` Stefan Beller
2016-01-14 20:50     ` Jens Lehmann
2016-01-14 23:43       ` Stefan Beller
2016-01-15 17:37     ` Junio C Hamano
2016-01-15 22:58       ` Stefan Beller
2016-01-15 23:03         ` Junio C Hamano
2016-01-14 20:57   ` Johannes Sixt
2016-01-14 22:49     ` Stefan Beller
2016-01-13 22:03 ` Eric Sunshine
2016-01-13 23:37   ` Stefan Beller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5669202C.2090100@kdbg.org \
    --to=j6t@kdbg.org \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=jens.lehmann@web.de \
    --cc=sbeller@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).