* [PATCH 0/2] Port `git submodule init` from shell to C
@ 2016-01-15 23:37 Stefan Beller
2016-01-15 23:37 ` [PATCH 1/2] submodule: Port resolve_relative_url " Stefan Beller
` (2 more replies)
0 siblings, 3 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-15 23:37 UTC (permalink / raw)
To: git; +Cc: gitster, j6t, sunshine, Jens.Lehmann, Stefan Beller
The first patch is a reroll of "[PATCH] submodule: Port resolve_relative_url
from shell to C" and the second patch is new.
This applies on top of origin/sb/submodule-parallel-update, as it makes use
of the recorded update strategy in the submodule configuration.
Thanks,
Stefan
Stefan Beller (2):
submodule: Port resolve_relative_url from shell to C
submodule: Port init from shell to C
builtin/submodule--helper.c | 330 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 118 +---------------
t/t0060-path-utils.sh | 42 ++++++
3 files changed, 370 insertions(+), 120 deletions(-)
--
2.7.0.rc0.37.gb4a0220.dirty
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 1/2] submodule: Port resolve_relative_url from shell to C
2016-01-15 23:37 [PATCH 0/2] Port `git submodule init` from shell to C Stefan Beller
@ 2016-01-15 23:37 ` Stefan Beller
2016-01-15 23:37 ` [PATCH 2/2] submodule: Port init " Stefan Beller
2016-01-19 23:17 ` [PATCH 0/2] Port `git submodule init` " Junio C Hamano
2 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-15 23:37 UTC (permalink / raw)
To: git; +Cc: gitster, j6t, sunshine, Jens.Lehmann, Stefan Beller
Later on we want to automatically call `git submodule init`
from other commands, such that the user doesn't have to initialize
the submodule themself. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
---
> ... and ends here can easily be rewritten to become a single strbuf_addf()
> without the xstrdup()s and without the early exit (at the cost of some
> additional ?: conditionals in the arguments).
I did not go that route, as I could not find a viable solution there.
It looks easy, but it is not, because we have a starts_with_dot_slash
check which is either applied to remoteurl alone or a combination of all of the inputs
(remoteurl=".", colonsep = "/", url + ./....)
builtin/submodule--helper.c | 215 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 42 +++++++++
3 files changed, 260 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 8002187..1484b36 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,217 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ int flag = 0;
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
+
+ if (!refname)
+ die("No such ref: HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = xstrdup(dest);
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+static char *last_dir_separator(char *str)
+{
+ char *p = str + strlen(str);
+ while (p-- > str)
+ if (is_dir_sep(*p))
+ return p;
+ return NULL;
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = last_dir_separator(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome correct
+ * http://a.com/b ../c http://a.com/c yes
+ * http://a.com/b ../../c http://c no (domain should be kept)
+ * http://a.com/b ../../../c http:/c no
+ * http://a.com/b ../../../../c http:c no
+ * http://a.com/b ../../../../../c .:c no
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ free(remoteurl);
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -502,7 +713,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 10c5af9..615ef9b 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" ||
@@ -1176,9 +1103,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 627ef85..8a1579c 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -286,4 +293,39 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
+test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
+test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.7.0.rc0.37.gb4a0220.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 2/2] submodule: Port init from shell to C
2016-01-15 23:37 [PATCH 0/2] Port `git submodule init` from shell to C Stefan Beller
2016-01-15 23:37 ` [PATCH 1/2] submodule: Port resolve_relative_url " Stefan Beller
@ 2016-01-15 23:37 ` Stefan Beller
2016-01-19 23:17 ` [PATCH 0/2] Port `git submodule init` " Junio C Hamano
2 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-15 23:37 UTC (permalink / raw)
To: git; +Cc: gitster, j6t, sunshine, Jens.Lehmann, Stefan Beller
By having the `init` functionality in C, we can reference it easier from
other parts in the code.
Signed-off-by: Stefan Beller <sbeller@google.com>
---
builtin/submodule--helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++--
git-submodule.sh | 39 +--------------
2 files changed, 111 insertions(+), 43 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1484b36..c7bd38a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -221,6 +221,115 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
+static int git_submodule_config(const char *var, const char *value, void *cb)
+{
+ return parse_submodule_config_option(var, value);
+}
+
+static void init_submodule(const char *path, const char *prefix)
+{
+ const struct submodule *sub;
+ struct strbuf sb = STRBUF_INIT;
+ char *url = NULL;
+ const char *upd = NULL;
+ const char *displaypath = relative_path(xgetcwd(), prefix, &sb);;
+
+ /* Only loads from .gitmodules, no overlay with .git/config */
+ gitmodules_config();
+
+ sub = submodule_from_path(null_sha1, path);
+
+ /*
+ * Copy url setting when it is not set yet.
+ * To look up the url in .git/config, we must not fall back to
+ * .gitmodules, so look it up directly.
+ */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.url", sub->name);
+ if (git_config_get_string(sb.buf, &url)) {
+ url = xstrdup(sub->url); // as overlayed by .gitmodules
+
+ if (!url)
+ die(_("No url found for submodule path '%s' in .gitmodules"),
+ displaypath);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *remoteurl;
+ char *remote = get_default_remote();
+ struct strbuf remotesb = STRBUF_INIT;
+ strbuf_addf(&remotesb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(remotesb.buf, &remoteurl))
+ /*
+ * The repository is its own
+ * authoritative upstream
+ */
+ remoteurl = xgetcwd();
+ url = relative_url(remoteurl, url, NULL);
+ strbuf_release(&remotesb);
+ }
+
+ if (git_config_set(sb.buf, url))
+ die(_("Failed to register url for submodule path '%s'"),
+ displaypath);
+
+ printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
+ sub->name, url, displaypath);
+ free(url);
+ }
+
+ /* Copy "update" setting when it is not set yet */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.update", sub->name);
+ if (git_config_get_string_const(sb.buf, &upd) && sub->update) {
+ upd = sub->update;
+ if (strcmp(sub->update, "checkout") &&
+ strcmp(sub->update, "rebase") &&
+ strcmp(sub->update, "merge") &&
+ strcmp(sub->update, "none")) {
+ fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
+ upd, sub->name);
+ upd = "none";
+ }
+ if (git_config_set(sb.buf, upd))
+ die(_("Failed to register update mode for submodule path '%s'"), displaypath);
+ }
+ strbuf_release(&sb);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+ int quiet = 0;
+ int i;
+
+ struct option module_init_options[] = {
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper init [<path>]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_init_options,
+ git_submodule_helper_usage, 0);
+
+ if (argc == 0)
+ die(_("Pass at least one submodule"));
+
+ for (i = 0; i < argc; i++)
+ init_submodule(argv[i], prefix);
+
+ return 0;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -466,11 +575,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
-static int git_submodule_config(const char *var, const char *value, void *cb)
-{
- return parse_submodule_config_option(var, value);
-}
-
struct submodule_update_clone {
/* states */
int count;
@@ -716,6 +820,7 @@ static struct cmd_struct commands[] = {
{"update-clone", update_clone},
{"resolve-relative-url", resolve_relative_url},
{"resolve-relative-url-test", resolve_relative_url_test},
+ {"init", module_init}
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 615ef9b..6fce0dc 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -398,45 +398,8 @@ cmd_init()
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
- name=$(git submodule--helper name "$sm_path") || exit
-
- displaypath=$(relative_path "$sm_path")
-
- # Copy url setting when it is not set yet
- if test -z "$(git config "submodule.$name.url")"
- then
- url=$(git config -f .gitmodules submodule."$name".url)
- test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
-
- # Possibly a url relative to parent
- case "$url" in
- ./*|../*)
- url=$(git submodule--helper resolve-relative-url "$url") || exit
- ;;
- esac
- git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
- fi
-
- # Copy "update" setting when it is not set yet
- if upd="$(git config -f .gitmodules submodule."$name".update)" &&
- test -n "$upd" &&
- test -z "$(git config submodule."$name".update)"
- then
- case "$upd" in
- checkout | rebase | merge | none)
- ;; # known modes of updating
- *)
- echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
- upd=none
- ;;
- esac
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
- fi
+ git submodule--helper init ${GIT_QUIET:+--quiet} "$sm_path" || exit
done
}
--
2.7.0.rc0.37.gb4a0220.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 0/2] Port `git submodule init` from shell to C
2016-01-15 23:37 [PATCH 0/2] Port `git submodule init` from shell to C Stefan Beller
2016-01-15 23:37 ` [PATCH 1/2] submodule: Port resolve_relative_url " Stefan Beller
2016-01-15 23:37 ` [PATCH 2/2] submodule: Port init " Stefan Beller
@ 2016-01-19 23:17 ` Junio C Hamano
2016-01-20 2:03 ` [PATCHv2 " Stefan Beller
2 siblings, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2016-01-19 23:17 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, j6t, sunshine, Jens.Lehmann
I've queued these with a bit of tweak in their log message.
Thanks.
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCHv2 0/2] Port `git submodule init` from shell to C
2016-01-19 23:17 ` [PATCH 0/2] Port `git submodule init` " Junio C Hamano
@ 2016-01-20 2:03 ` Stefan Beller
2016-01-20 2:03 ` [PATCHv2 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-01-20 2:03 ` [PATCHv2 2/2] submodule: port init " Stefan Beller
0 siblings, 2 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-20 2:03 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, j6t, sunshine, Jens.Lehmann
This replaces sb/submodule-init.
As I was crafting another series on top of this series I noticed a two bugs,
so I am resending it fixed.
* honor the quiet setting
* print to stderr instead of stdout. (In the next series we want to
call init_submodule from within update_clone whose stdout is piped into
git-submodule.sh, so stderr is the only way to talk to the user)
Thanks,
Stefan
The interdiff:
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c7bd38a..fecc9aa 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -226,7 +226,7 @@ static int git_submodule_config(const char *var, const char *value, void *cb)
return parse_submodule_config_option(var, value);
}
-static void init_submodule(const char *path, const char *prefix)
+static void init_submodule(const char *path, const char *prefix, int quiet)
{
const struct submodule *sub;
struct strbuf sb = STRBUF_INIT;
@@ -275,9 +275,9 @@ static void init_submodule(const char *path, const char *prefix)
if (git_config_set(sb.buf, url))
die(_("Failed to register url for submodule path '%s'"),
displaypath);
-
- printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
- sub->name, url, displaypath);
+ if (!quiet)
+ fprintf(stderr, _("Submodule '%s' (%s) registered for path '%s'\n"),
+ sub->name, url, displaypath);
free(url);
}
@@ -325,7 +325,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
die(_("Pass at least one submodule"));
for (i = 0; i < argc; i++)
- init_submodule(argv[i], prefix);
+ init_submodule(argv[i], prefix, quiet);
return 0;
}
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 330 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 118 +---------------
t/t0060-path-utils.sh | 42 ++++++
3 files changed, 370 insertions(+), 120 deletions(-)
--
2.7.0.rc0.44.g6033384.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCHv2 1/2] submodule: port resolve_relative_url from shell to C
2016-01-20 2:03 ` [PATCHv2 " Stefan Beller
@ 2016-01-20 2:03 ` Stefan Beller
2016-01-22 19:03 ` Johannes Sixt
2016-01-20 2:03 ` [PATCHv2 2/2] submodule: port init " Stefan Beller
1 sibling, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-01-20 2:03 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, j6t, sunshine, Jens.Lehmann
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 215 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 42 +++++++++
3 files changed, 260 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 8002187..1484b36 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,217 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ int flag = 0;
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
+
+ if (!refname)
+ die("No such ref: HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = xstrdup(dest);
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+static char *last_dir_separator(char *str)
+{
+ char *p = str + strlen(str);
+ while (p-- > str)
+ if (is_dir_sep(*p))
+ return p;
+ return NULL;
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = last_dir_separator(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome correct
+ * http://a.com/b ../c http://a.com/c yes
+ * http://a.com/b ../../c http://c no (domain should be kept)
+ * http://a.com/b ../../../c http:/c no
+ * http://a.com/b ../../../../c http:c no
+ * http://a.com/b ../../../../../c .:c no
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ free(remoteurl);
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -502,7 +713,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 10c5af9..615ef9b 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" ||
@@ -1176,9 +1103,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 627ef85..8a1579c 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -286,4 +293,39 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
+test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
+test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.7.0.rc0.44.g6033384.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCHv2 1/2] submodule: port resolve_relative_url from shell to C
2016-01-20 2:03 ` [PATCHv2 1/2] submodule: port resolve_relative_url " Stefan Beller
@ 2016-01-22 19:03 ` Johannes Sixt
2016-01-22 20:23 ` Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Johannes Sixt @ 2016-01-22 19:03 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, gitster, sunshine, Jens.Lehmann
Am 20.01.2016 um 03:03 schrieb Stefan Beller:
> +static char *last_dir_separator(char *str)
> +{
> + char *p = str + strlen(str);
> + while (p-- > str)
> + if (is_dir_sep(*p))
> + return p;
> + return NULL;
> +}
> +
I just noticed that we already have this function. Please squash in the
following.
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1484b36..92d7d32 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -51,21 +51,12 @@ static int starts_with_dot_dot_slash(const char *str)
return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
}
-static char *last_dir_separator(char *str)
-{
- char *p = str + strlen(str);
- while (p-- > str)
- if (is_dir_sep(*p))
- return p;
- return NULL;
-}
-
/*
* Returns 1 if it was the last chop before ':'.
*/
static int chop_last_dir(char **remoteurl, int is_relative)
{
- char *rfind = last_dir_separator(*remoteurl);
+ char *rfind = find_last_dir_sep(*remoteurl);
if (rfind) {
*rfind = '\0';
return 0;
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCHv2 1/2] submodule: port resolve_relative_url from shell to C
2016-01-22 19:03 ` Johannes Sixt
@ 2016-01-22 20:23 ` Stefan Beller
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-22 20:23 UTC (permalink / raw)
To: Johannes Sixt
Cc: git@vger.kernel.org, Junio C Hamano, Eric Sunshine, Jens Lehmann
On Fri, Jan 22, 2016 at 11:03 AM, Johannes Sixt <j6t@kdbg.org> wrote:
> Am 20.01.2016 um 03:03 schrieb Stefan Beller:
>> +static char *last_dir_separator(char *str)
>> +{
>> + char *p = str + strlen(str);
>> + while (p-- > str)
>> + if (is_dir_sep(*p))
>> + return p;
>> + return NULL;
>> +}
>> +
>
> I just noticed that we already have this function. Please squash in the
> following.
thanks for reviewing! squashed.
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 1484b36..92d7d32 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -51,21 +51,12 @@ static int starts_with_dot_dot_slash(const char *str)
> return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
> }
>
> -static char *last_dir_separator(char *str)
> -{
> - char *p = str + strlen(str);
> - while (p-- > str)
> - if (is_dir_sep(*p))
> - return p;
> - return NULL;
> -}
> -
> /*
> * Returns 1 if it was the last chop before ':'.
> */
> static int chop_last_dir(char **remoteurl, int is_relative)
> {
> - char *rfind = last_dir_separator(*remoteurl);
> + char *rfind = find_last_dir_sep(*remoteurl);
> if (rfind) {
> *rfind = '\0';
> return 0;
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCHv2 2/2] submodule: port init from shell to C
2016-01-20 2:03 ` [PATCHv2 " Stefan Beller
2016-01-20 2:03 ` [PATCHv2 1/2] submodule: port resolve_relative_url " Stefan Beller
@ 2016-01-20 2:03 ` Stefan Beller
2016-01-20 3:24 ` [PATCHv3 " Stefan Beller
1 sibling, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-01-20 2:03 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, j6t, sunshine, Jens.Lehmann
By having the `init` functionality in C, we can reference it easier
from other parts in the code.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++--
git-submodule.sh | 39 +--------------
2 files changed, 111 insertions(+), 43 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1484b36..fecc9aa 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -221,6 +221,115 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
+static int git_submodule_config(const char *var, const char *value, void *cb)
+{
+ return parse_submodule_config_option(var, value);
+}
+
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+ const struct submodule *sub;
+ struct strbuf sb = STRBUF_INIT;
+ char *url = NULL;
+ const char *upd = NULL;
+ const char *displaypath = relative_path(xgetcwd(), prefix, &sb);;
+
+ /* Only loads from .gitmodules, no overlay with .git/config */
+ gitmodules_config();
+
+ sub = submodule_from_path(null_sha1, path);
+
+ /*
+ * Copy url setting when it is not set yet.
+ * To look up the url in .git/config, we must not fall back to
+ * .gitmodules, so look it up directly.
+ */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.url", sub->name);
+ if (git_config_get_string(sb.buf, &url)) {
+ url = xstrdup(sub->url); // as overlayed by .gitmodules
+
+ if (!url)
+ die(_("No url found for submodule path '%s' in .gitmodules"),
+ displaypath);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *remoteurl;
+ char *remote = get_default_remote();
+ struct strbuf remotesb = STRBUF_INIT;
+ strbuf_addf(&remotesb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(remotesb.buf, &remoteurl))
+ /*
+ * The repository is its own
+ * authoritative upstream
+ */
+ remoteurl = xgetcwd();
+ url = relative_url(remoteurl, url, NULL);
+ strbuf_release(&remotesb);
+ }
+
+ if (git_config_set(sb.buf, url))
+ die(_("Failed to register url for submodule path '%s'"),
+ displaypath);
+ if (!quiet)
+ fprintf(stderr, _("Submodule '%s' (%s) registered for path '%s'\n"),
+ sub->name, url, displaypath);
+ free(url);
+ }
+
+ /* Copy "update" setting when it is not set yet */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.update", sub->name);
+ if (git_config_get_string_const(sb.buf, &upd) && sub->update) {
+ upd = sub->update;
+ if (strcmp(sub->update, "checkout") &&
+ strcmp(sub->update, "rebase") &&
+ strcmp(sub->update, "merge") &&
+ strcmp(sub->update, "none")) {
+ fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
+ upd, sub->name);
+ upd = "none";
+ }
+ if (git_config_set(sb.buf, upd))
+ die(_("Failed to register update mode for submodule path '%s'"), displaypath);
+ }
+ strbuf_release(&sb);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+ int quiet = 0;
+ int i;
+
+ struct option module_init_options[] = {
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper init [<path>]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_init_options,
+ git_submodule_helper_usage, 0);
+
+ if (argc == 0)
+ die(_("Pass at least one submodule"));
+
+ for (i = 0; i < argc; i++)
+ init_submodule(argv[i], prefix, quiet);
+
+ return 0;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -466,11 +575,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
-static int git_submodule_config(const char *var, const char *value, void *cb)
-{
- return parse_submodule_config_option(var, value);
-}
-
struct submodule_update_clone {
/* states */
int count;
@@ -716,6 +820,7 @@ static struct cmd_struct commands[] = {
{"update-clone", update_clone},
{"resolve-relative-url", resolve_relative_url},
{"resolve-relative-url-test", resolve_relative_url_test},
+ {"init", module_init}
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 615ef9b..6fce0dc 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -398,45 +398,8 @@ cmd_init()
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
- name=$(git submodule--helper name "$sm_path") || exit
-
- displaypath=$(relative_path "$sm_path")
-
- # Copy url setting when it is not set yet
- if test -z "$(git config "submodule.$name.url")"
- then
- url=$(git config -f .gitmodules submodule."$name".url)
- test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
-
- # Possibly a url relative to parent
- case "$url" in
- ./*|../*)
- url=$(git submodule--helper resolve-relative-url "$url") || exit
- ;;
- esac
- git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
- fi
-
- # Copy "update" setting when it is not set yet
- if upd="$(git config -f .gitmodules submodule."$name".update)" &&
- test -n "$upd" &&
- test -z "$(git config submodule."$name".update)"
- then
- case "$upd" in
- checkout | rebase | merge | none)
- ;; # known modes of updating
- *)
- echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
- upd=none
- ;;
- esac
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
- fi
+ git submodule--helper init ${GIT_QUIET:+--quiet} "$sm_path" || exit
done
}
--
2.7.0.rc0.44.g6033384.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCHv3 2/2] submodule: port init from shell to C
2016-01-20 2:03 ` [PATCHv2 2/2] submodule: port init " Stefan Beller
@ 2016-01-20 3:24 ` Stefan Beller
2016-01-20 21:01 ` Junio C Hamano
2016-01-21 23:18 ` [PATCHv4 " Stefan Beller
0 siblings, 2 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-20 3:24 UTC (permalink / raw)
To: git, gitster; +Cc: j6t, sunshine, Jens.Lehmann, Stefan Beller
By having the `init` functionality in C, we can reference it easier
from other parts in the code.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
I noticed a syntactical mistake in this patch, interdiff to v2:
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index bcfcbdf..def382e 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -247,7 +247,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.url", sub->name);
if (git_config_get_string(sb.buf, &url)) {
- url = xstrdup(sub->url); // as overlayed by .gitmodules
+ url = xstrdup(sub->url);
builtin/submodule--helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++--
git-submodule.sh | 39 +--------------
2 files changed, 111 insertions(+), 43 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1484b36..4684f16 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -221,6 +221,115 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
+static int git_submodule_config(const char *var, const char *value, void *cb)
+{
+ return parse_submodule_config_option(var, value);
+}
+
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+ const struct submodule *sub;
+ struct strbuf sb = STRBUF_INIT;
+ char *url = NULL;
+ const char *upd = NULL;
+ const char *displaypath = relative_path(xgetcwd(), prefix, &sb);;
+
+ /* Only loads from .gitmodules, no overlay with .git/config */
+ gitmodules_config();
+
+ sub = submodule_from_path(null_sha1, path);
+
+ /*
+ * Copy url setting when it is not set yet.
+ * To look up the url in .git/config, we must not fall back to
+ * .gitmodules, so look it up directly.
+ */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.url", sub->name);
+ if (git_config_get_string(sb.buf, &url)) {
+ url = xstrdup(sub->url);
+
+ if (!url)
+ die(_("No url found for submodule path '%s' in .gitmodules"),
+ displaypath);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *remoteurl;
+ char *remote = get_default_remote();
+ struct strbuf remotesb = STRBUF_INIT;
+ strbuf_addf(&remotesb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(remotesb.buf, &remoteurl))
+ /*
+ * The repository is its own
+ * authoritative upstream
+ */
+ remoteurl = xgetcwd();
+ url = relative_url(remoteurl, url, NULL);
+ strbuf_release(&remotesb);
+ }
+
+ if (git_config_set(sb.buf, url))
+ die(_("Failed to register url for submodule path '%s'"),
+ displaypath);
+ if (!quiet)
+ fprintf(stderr, _("Submodule '%s' (%s) registered for path '%s'\n"),
+ sub->name, url, displaypath);
+ free(url);
+ }
+
+ /* Copy "update" setting when it is not set yet */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.update", sub->name);
+ if (git_config_get_string_const(sb.buf, &upd) && sub->update) {
+ upd = sub->update;
+ if (strcmp(sub->update, "checkout") &&
+ strcmp(sub->update, "rebase") &&
+ strcmp(sub->update, "merge") &&
+ strcmp(sub->update, "none")) {
+ fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
+ upd, sub->name);
+ upd = "none";
+ }
+ if (git_config_set(sb.buf, upd))
+ die(_("Failed to register update mode for submodule path '%s'"), displaypath);
+ }
+ strbuf_release(&sb);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+ int quiet = 0;
+ int i;
+
+ struct option module_init_options[] = {
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper init [<path>]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_init_options,
+ git_submodule_helper_usage, 0);
+
+ if (argc == 0)
+ die(_("Pass at least one submodule"));
+
+ for (i = 0; i < argc; i++)
+ init_submodule(argv[i], prefix, quiet);
+
+ return 0;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -466,11 +575,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
-static int git_submodule_config(const char *var, const char *value, void *cb)
-{
- return parse_submodule_config_option(var, value);
-}
-
struct submodule_update_clone {
/* states */
int count;
@@ -716,6 +820,7 @@ static struct cmd_struct commands[] = {
{"update-clone", update_clone},
{"resolve-relative-url", resolve_relative_url},
{"resolve-relative-url-test", resolve_relative_url_test},
+ {"init", module_init}
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 615ef9b..6fce0dc 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -398,45 +398,8 @@ cmd_init()
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
- name=$(git submodule--helper name "$sm_path") || exit
-
- displaypath=$(relative_path "$sm_path")
-
- # Copy url setting when it is not set yet
- if test -z "$(git config "submodule.$name.url")"
- then
- url=$(git config -f .gitmodules submodule."$name".url)
- test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
-
- # Possibly a url relative to parent
- case "$url" in
- ./*|../*)
- url=$(git submodule--helper resolve-relative-url "$url") || exit
- ;;
- esac
- git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
- fi
-
- # Copy "update" setting when it is not set yet
- if upd="$(git config -f .gitmodules submodule."$name".update)" &&
- test -n "$upd" &&
- test -z "$(git config submodule."$name".update)"
- then
- case "$upd" in
- checkout | rebase | merge | none)
- ;; # known modes of updating
- *)
- echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
- upd=none
- ;;
- esac
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
- fi
+ git submodule--helper init ${GIT_QUIET:+--quiet} "$sm_path" || exit
done
}
--
2.7.0.rc0.41.g89994f2.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCHv3 2/2] submodule: port init from shell to C
2016-01-20 3:24 ` [PATCHv3 " Stefan Beller
@ 2016-01-20 21:01 ` Junio C Hamano
2016-01-20 22:33 ` Stefan Beller
2016-01-21 23:18 ` [PATCHv4 " Stefan Beller
1 sibling, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2016-01-20 21:01 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, j6t, sunshine, Jens.Lehmann
Stefan Beller <sbeller@google.com> writes:
> By having the `init` functionality in C, we can reference it easier
> from other parts in the code.
>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
How faithful a conversion is this aiming to be? For example, one
thing I noticed is that some messages that were originally given
with "say" and sent to the standard output, which is emitted to the
standard error with this rewrite. I didn't read both patches
carefully, so there may be other discrepancies I didn't spot.
I think you would want to do this in three steps:
- A faithful rewrite from shell to C;
- s/printf/fprintf(stderr, / for some messages; and finally
- Hiding of some messages under --quiet.
in the above order.
Thanks.
> builtin/submodule--helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++--
> git-submodule.sh | 39 +--------------
> 2 files changed, 111 insertions(+), 43 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 1484b36..4684f16 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -221,6 +221,115 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
> return 0;
> }
>
> +static int git_submodule_config(const char *var, const char *value, void *cb)
> +{
> + return parse_submodule_config_option(var, value);
> +}
> +
> +static void init_submodule(const char *path, const char *prefix, int quiet)
> +{
> + const struct submodule *sub;
> + struct strbuf sb = STRBUF_INIT;
> + char *url = NULL;
> + const char *upd = NULL;
> + const char *displaypath = relative_path(xgetcwd(), prefix, &sb);;
> +
> + /* Only loads from .gitmodules, no overlay with .git/config */
> + gitmodules_config();
> +
> + sub = submodule_from_path(null_sha1, path);
> +
> + /*
> + * Copy url setting when it is not set yet.
> + * To look up the url in .git/config, we must not fall back to
> + * .gitmodules, so look it up directly.
> + */
> + strbuf_reset(&sb);
> + strbuf_addf(&sb, "submodule.%s.url", sub->name);
> + if (git_config_get_string(sb.buf, &url)) {
> + url = xstrdup(sub->url);
> +
> + if (!url)
> + die(_("No url found for submodule path '%s' in .gitmodules"),
> + displaypath);
> +
> + /* Possibly a url relative to parent */
> + if (starts_with_dot_dot_slash(url) ||
> + starts_with_dot_slash(url)) {
> + char *remoteurl;
> + char *remote = get_default_remote();
> + struct strbuf remotesb = STRBUF_INIT;
> + strbuf_addf(&remotesb, "remote.%s.url", remote);
> + free(remote);
> +
> + if (git_config_get_string(remotesb.buf, &remoteurl))
> + /*
> + * The repository is its own
> + * authoritative upstream
> + */
> + remoteurl = xgetcwd();
> + url = relative_url(remoteurl, url, NULL);
> + strbuf_release(&remotesb);
> + }
> +
> + if (git_config_set(sb.buf, url))
> + die(_("Failed to register url for submodule path '%s'"),
> + displaypath);
> + if (!quiet)
> + fprintf(stderr, _("Submodule '%s' (%s) registered for path '%s'\n"),
> + sub->name, url, displaypath);
> + free(url);
> + }
> +
> + /* Copy "update" setting when it is not set yet */
> + strbuf_reset(&sb);
> + strbuf_addf(&sb, "submodule.%s.update", sub->name);
> + if (git_config_get_string_const(sb.buf, &upd) && sub->update) {
> + upd = sub->update;
> + if (strcmp(sub->update, "checkout") &&
> + strcmp(sub->update, "rebase") &&
> + strcmp(sub->update, "merge") &&
> + strcmp(sub->update, "none")) {
> + fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
> + upd, sub->name);
> + upd = "none";
> + }
> + if (git_config_set(sb.buf, upd))
> + die(_("Failed to register update mode for submodule path '%s'"), displaypath);
> + }
> + strbuf_release(&sb);
> +}
> +
> +static int module_init(int argc, const char **argv, const char *prefix)
> +{
> + int quiet = 0;
> + int i;
> +
> + struct option module_init_options[] = {
> + OPT_STRING(0, "prefix", &prefix,
> + N_("path"),
> + N_("alternative anchor for relative paths")),
> + OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
> + OPT_END()
> + };
> +
> + const char *const git_submodule_helper_usage[] = {
> + N_("git submodule--helper init [<path>]"),
> + NULL
> + };
> +
> + argc = parse_options(argc, argv, prefix, module_init_options,
> + git_submodule_helper_usage, 0);
> +
> + if (argc == 0)
> + die(_("Pass at least one submodule"));
> +
> + for (i = 0; i < argc; i++)
> + init_submodule(argv[i], prefix, quiet);
> +
> + return 0;
> +}
> +
> struct module_list {
> const struct cache_entry **entries;
> int alloc, nr;
> @@ -466,11 +575,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
> return 0;
> }
>
> -static int git_submodule_config(const char *var, const char *value, void *cb)
> -{
> - return parse_submodule_config_option(var, value);
> -}
> -
> struct submodule_update_clone {
> /* states */
> int count;
> @@ -716,6 +820,7 @@ static struct cmd_struct commands[] = {
> {"update-clone", update_clone},
> {"resolve-relative-url", resolve_relative_url},
> {"resolve-relative-url-test", resolve_relative_url_test},
> + {"init", module_init}
> };
>
> int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
> diff --git a/git-submodule.sh b/git-submodule.sh
> index 615ef9b..6fce0dc 100755
> --- a/git-submodule.sh
> +++ b/git-submodule.sh
> @@ -398,45 +398,8 @@ cmd_init()
> while read mode sha1 stage sm_path
> do
> die_if_unmatched "$mode"
> - name=$(git submodule--helper name "$sm_path") || exit
> -
> - displaypath=$(relative_path "$sm_path")
> -
> - # Copy url setting when it is not set yet
> - if test -z "$(git config "submodule.$name.url")"
> - then
> - url=$(git config -f .gitmodules submodule."$name".url)
> - test -z "$url" &&
> - die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
> -
> - # Possibly a url relative to parent
> - case "$url" in
> - ./*|../*)
> - url=$(git submodule--helper resolve-relative-url "$url") || exit
> - ;;
> - esac
> - git config submodule."$name".url "$url" ||
> - die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
>
> - say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
> - fi
> -
> - # Copy "update" setting when it is not set yet
> - if upd="$(git config -f .gitmodules submodule."$name".update)" &&
> - test -n "$upd" &&
> - test -z "$(git config submodule."$name".update)"
> - then
> - case "$upd" in
> - checkout | rebase | merge | none)
> - ;; # known modes of updating
> - *)
> - echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
> - upd=none
> - ;;
> - esac
> - git config submodule."$name".update "$upd" ||
> - die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
> - fi
> + git submodule--helper init ${GIT_QUIET:+--quiet} "$sm_path" || exit
> done
> }
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCHv3 2/2] submodule: port init from shell to C
2016-01-20 21:01 ` Junio C Hamano
@ 2016-01-20 22:33 ` Stefan Beller
2016-01-20 23:04 ` Junio C Hamano
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-01-20 22:33 UTC (permalink / raw)
To: Junio C Hamano
Cc: git@vger.kernel.org, Johannes Sixt, Eric Sunshine, Jens Lehmann
On Wed, Jan 20, 2016 at 1:01 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> By having the `init` functionality in C, we can reference it easier
>> from other parts in the code.
>>
>> Signed-off-by: Stefan Beller <sbeller@google.com>
>> Signed-off-by: Junio C Hamano <gitster@pobox.com>
>> ---
>
> How faithful a conversion is this aiming to be? For example, one
> thing I noticed is that some messages that were originally given
> with "say" and sent to the standard output, which is emitted to the
> standard error with this rewrite. I didn't read both patches
> carefully, so there may be other discrepancies I didn't spot.
>
> I think you would want to do this in three steps:
>
> - A faithful rewrite from shell to C;
>
> - s/printf/fprintf(stderr, / for some messages; and finally
>
> - Hiding of some messages under --quiet.
>
> in the above order.
"say" respects the setting of GIT_QUIET, which is usually set when
--quiet is passed, so I think I want:
- A faithful rewrite from shell to C including messages respecting
--quiet, such that the "say" behavior is kept.
- s/printf/fprintf(stderr, / for some messages
and then be done with it.
Thanks,
Stefan
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCHv3 2/2] submodule: port init from shell to C
2016-01-20 22:33 ` Stefan Beller
@ 2016-01-20 23:04 ` Junio C Hamano
0 siblings, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2016-01-20 23:04 UTC (permalink / raw)
To: Stefan Beller
Cc: git@vger.kernel.org, Johannes Sixt, Eric Sunshine, Jens Lehmann
Stefan Beller <sbeller@google.com> writes:
> "say" respects the setting of GIT_QUIET, which is usually set when
> --quiet is passed, so I think I want:
>
> - A faithful rewrite from shell to C including messages respecting
> --quiet, such that the "say" behavior is kept.
>
> - s/printf/fprintf(stderr, / for some messages
Yup, that is the correct order. Thanks.
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCHv4 2/2] submodule: port init from shell to C
2016-01-20 3:24 ` [PATCHv3 " Stefan Beller
2016-01-20 21:01 ` Junio C Hamano
@ 2016-01-21 23:18 ` Stefan Beller
2016-01-22 22:30 ` Junio C Hamano
1 sibling, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-01-21 23:18 UTC (permalink / raw)
To: git, gitster; +Cc: j6t, sunshine, Jens.Lehmann, Stefan Beller
By having the `init` functionality in C, we can reference it easier
from other parts in the code.
Signed-off-by: Stefan Beller <sbeller@google.com>
---
Hi Junio,
please replace the top-most patch of sb/submodule-init with this patch.
This will print to stdout instead of stderr, as it's the most
faithful shell -> translation. The s/printf/fprintf(stderr, / patch
will come with the series that needs the behavior, i.e. as one of the
first patches in the groups series (that is under heavy mental
construction currently).
Thanks,
Stefan
Interdiff to the top of sb/submodule-init (6a514f75c25, submodule: port
init from shell to C, Committed: 2016-01-20 12:55:30):
# diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
# index 4684f16..6323048 100644
# --- a/builtin/submodule--helper.c
# +++ b/builtin/submodule--helper.c
# @@ -232,7 +232,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
# struct strbuf sb = STRBUF_INIT;
# char *url = NULL;
# const char *upd = NULL;
# - const char *displaypath = relative_path(xgetcwd(), prefix, &sb);;
# + const char *displaypath = relative_path(xgetcwd(), prefix, &sb);
#
# /* Only loads from .gitmodules, no overlay with .git/config */
# gitmodules_config();
# @@ -276,7 +276,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
# die(_("Failed to register url for submodule path '%s'"),
# displaypath);
# if (!quiet)
# - fprintf(stderr, _("Submodule '%s' (%s) registered for path '%s'\n"),
# + printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
# sub->name, url, displaypath);
# free(url);
# }
builtin/submodule--helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++--
git-submodule.sh | 39 +--------------
2 files changed, 111 insertions(+), 43 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1484b36..6323048 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -221,6 +221,115 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
+static int git_submodule_config(const char *var, const char *value, void *cb)
+{
+ return parse_submodule_config_option(var, value);
+}
+
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+ const struct submodule *sub;
+ struct strbuf sb = STRBUF_INIT;
+ char *url = NULL;
+ const char *upd = NULL;
+ const char *displaypath = relative_path(xgetcwd(), prefix, &sb);
+
+ /* Only loads from .gitmodules, no overlay with .git/config */
+ gitmodules_config();
+
+ sub = submodule_from_path(null_sha1, path);
+
+ /*
+ * Copy url setting when it is not set yet.
+ * To look up the url in .git/config, we must not fall back to
+ * .gitmodules, so look it up directly.
+ */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.url", sub->name);
+ if (git_config_get_string(sb.buf, &url)) {
+ url = xstrdup(sub->url);
+
+ if (!url)
+ die(_("No url found for submodule path '%s' in .gitmodules"),
+ displaypath);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *remoteurl;
+ char *remote = get_default_remote();
+ struct strbuf remotesb = STRBUF_INIT;
+ strbuf_addf(&remotesb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(remotesb.buf, &remoteurl))
+ /*
+ * The repository is its own
+ * authoritative upstream
+ */
+ remoteurl = xgetcwd();
+ url = relative_url(remoteurl, url, NULL);
+ strbuf_release(&remotesb);
+ }
+
+ if (git_config_set(sb.buf, url))
+ die(_("Failed to register url for submodule path '%s'"),
+ displaypath);
+ if (!quiet)
+ printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
+ sub->name, url, displaypath);
+ free(url);
+ }
+
+ /* Copy "update" setting when it is not set yet */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.update", sub->name);
+ if (git_config_get_string_const(sb.buf, &upd) && sub->update) {
+ upd = sub->update;
+ if (strcmp(sub->update, "checkout") &&
+ strcmp(sub->update, "rebase") &&
+ strcmp(sub->update, "merge") &&
+ strcmp(sub->update, "none")) {
+ fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
+ upd, sub->name);
+ upd = "none";
+ }
+ if (git_config_set(sb.buf, upd))
+ die(_("Failed to register update mode for submodule path '%s'"), displaypath);
+ }
+ strbuf_release(&sb);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+ int quiet = 0;
+ int i;
+
+ struct option module_init_options[] = {
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper init [<path>]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_init_options,
+ git_submodule_helper_usage, 0);
+
+ if (argc == 0)
+ die(_("Pass at least one submodule"));
+
+ for (i = 0; i < argc; i++)
+ init_submodule(argv[i], prefix, quiet);
+
+ return 0;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -466,11 +575,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
-static int git_submodule_config(const char *var, const char *value, void *cb)
-{
- return parse_submodule_config_option(var, value);
-}
-
struct submodule_update_clone {
/* states */
int count;
@@ -716,6 +820,7 @@ static struct cmd_struct commands[] = {
{"update-clone", update_clone},
{"resolve-relative-url", resolve_relative_url},
{"resolve-relative-url-test", resolve_relative_url_test},
+ {"init", module_init}
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 615ef9b..6fce0dc 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -398,45 +398,8 @@ cmd_init()
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
- name=$(git submodule--helper name "$sm_path") || exit
-
- displaypath=$(relative_path "$sm_path")
-
- # Copy url setting when it is not set yet
- if test -z "$(git config "submodule.$name.url")"
- then
- url=$(git config -f .gitmodules submodule."$name".url)
- test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
-
- # Possibly a url relative to parent
- case "$url" in
- ./*|../*)
- url=$(git submodule--helper resolve-relative-url "$url") || exit
- ;;
- esac
- git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
- fi
-
- # Copy "update" setting when it is not set yet
- if upd="$(git config -f .gitmodules submodule."$name".update)" &&
- test -n "$upd" &&
- test -z "$(git config submodule."$name".update)"
- then
- case "$upd" in
- checkout | rebase | merge | none)
- ;; # known modes of updating
- *)
- echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
- upd=none
- ;;
- esac
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
- fi
+ git submodule--helper init ${GIT_QUIET:+--quiet} "$sm_path" || exit
done
}
--
2.7.0.rc0.41.g89994f2.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCHv4 2/2] submodule: port init from shell to C
2016-01-21 23:18 ` [PATCHv4 " Stefan Beller
@ 2016-01-22 22:30 ` Junio C Hamano
2016-01-22 22:32 ` Stefan Beller
` (3 more replies)
0 siblings, 4 replies; 37+ messages in thread
From: Junio C Hamano @ 2016-01-22 22:30 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, j6t, sunshine, Jens.Lehmann
Stefan Beller <sbeller@google.com> writes:
> By having the `init` functionality in C, we can reference it easier
> from other parts in the code.
>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---
>
> Hi Junio,
>
> please replace the top-most patch of sb/submodule-init with this patch.
Will do, but it seems that you'd have to be replacing 1/2 as well,
so perhaps send both when that happens?
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCHv4 2/2] submodule: port init from shell to C
2016-01-22 22:30 ` Junio C Hamano
@ 2016-01-22 22:32 ` Stefan Beller
2016-01-22 23:32 ` [PATCHv3 0/2] Port `git submodule init` " Stefan Beller
` (2 subsequent siblings)
3 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-22 22:32 UTC (permalink / raw)
To: Junio C Hamano
Cc: git@vger.kernel.org, Johannes Sixt, Eric Sunshine, Jens Lehmann
On Fri, Jan 22, 2016 at 2:30 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> By having the `init` functionality in C, we can reference it easier
>> from other parts in the code.
>>
>> Signed-off-by: Stefan Beller <sbeller@google.com>
>> ---
>>
>> Hi Junio,
>>
>> please replace the top-most patch of sb/submodule-init with this patch.
>
> Will do, but it seems that you'd have to be replacing 1/2 as well,
> so perhaps send both when that happens?
I'll resend the series later tonight indeed, so no need to pickup that patch.
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCHv3 0/2] Port `git submodule init` from shell to C
2016-01-22 22:30 ` Junio C Hamano
2016-01-22 22:32 ` Stefan Beller
@ 2016-01-22 23:32 ` Stefan Beller
2016-01-25 22:46 ` Junio C Hamano
2016-01-22 23:32 ` [PATCHv3 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-01-22 23:32 ` [PATCHv3 2/2] submodule: port init " Stefan Beller
3 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-01-22 23:32 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, j6t, sunshine, Jens.Lehmann
This applies on top of sb/submodule-parallel-update, replacing
sb/submodule-init.
Fixes:
* a more faithful conversion by staying on stdout (We switch to stderr later
in another series)
* use the existing find_last_dir_sep instead of reinventing the wheel.
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 321 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 118 +---------------
t/t0060-path-utils.sh | 42 ++++++
3 files changed, 361 insertions(+), 120 deletions(-)
Interdiff to origin/sb/submodule-init (committed 2016-01-20 12:55:30)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 4684f16..c9b0c05 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -51,21 +51,12 @@ static int starts_with_dot_dot_slash(const char *str)
return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
}
-static char *last_dir_separator(char *str)
-{
- char *p = str + strlen(str);
- while (p-- > str)
- if (is_dir_sep(*p))
- return p;
- return NULL;
-}
-
/*
* Returns 1 if it was the last chop before ':'.
*/
static int chop_last_dir(char **remoteurl, int is_relative)
{
- char *rfind = last_dir_separator(*remoteurl);
+ char *rfind = find_last_dir_sep(*remoteurl);
if (rfind) {
*rfind = '\0';
return 0;
@@ -232,7 +223,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
struct strbuf sb = STRBUF_INIT;
char *url = NULL;
const char *upd = NULL;
- const char *displaypath = relative_path(xgetcwd(), prefix, &sb);;
+ const char *displaypath = relative_path(xgetcwd(), prefix, &sb);
/* Only loads from .gitmodules, no overlay with .git/config */
gitmodules_config();
@@ -276,7 +267,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
die(_("Failed to register url for submodule path '%s'"),
displaypath);
if (!quiet)
- fprintf(stderr, _("Submodule '%s' (%s) registered for path '%s'\n"),
+ printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
sub->name, url, displaypath);
free(url);
}
--
2.7.0.rc0.45.g0dba895.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCHv3 0/2] Port `git submodule init` from shell to C
2016-01-22 23:32 ` [PATCHv3 0/2] Port `git submodule init` " Stefan Beller
@ 2016-01-25 22:46 ` Junio C Hamano
2016-01-28 2:30 ` [PATCHv4 " Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2016-01-25 22:46 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, j6t, sunshine, Jens.Lehmann
Stefan Beller <sbeller@google.com> writes:
> This applies on top of sb/submodule-parallel-update, replacing
> sb/submodule-init.
>
> Fixes:
>
> * a more faithful conversion by staying on stdout (We switch to stderr later
> in another series)
> * use the existing find_last_dir_sep instead of reinventing the wheel.
>
> Stefan Beller (2):
> submodule: port resolve_relative_url from shell to C
> submodule: port init from shell to C
Thanks, will replace.
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCHv4 0/2] Port `git submodule init` from shell to C
2016-01-25 22:46 ` Junio C Hamano
@ 2016-01-28 2:30 ` Stefan Beller
2016-01-28 2:30 ` [PATCHv4 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-01-28 2:30 ` [PATCHv4 2/2] submodule: port init " Stefan Beller
0 siblings, 2 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-28 2:30 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, Jens.Lehmann, sunshine, j6t
Hi,
I looked at this patch series again and fixed all memory leaks as found by
coverity scan.
This applies on top of sb/submodule-parallel-update
Thanks,
Stefan
Interdiff to v3:
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c9b0c05..dd8b2a5 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -35,7 +35,7 @@ static char *get_default_remote(void)
if (git_config_get_string(sb.buf, &dest))
ret = xstrdup("origin");
else
- ret = xstrdup(dest);
+ ret = dest;
strbuf_release(&sb);
return ret;
@@ -188,6 +188,7 @@ static int resolve_relative_url(int argc, const char **argv, const char *prefix)
res = relative_url(remoteurl, url, up_path);
puts(res);
free(res);
+ free(remoteurl);
return 0;
}
@@ -209,6 +210,7 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
res = relative_url(remoteurl, url, up_path);
puts(res);
free(res);
+ free(remoteurl);
return 0;
}
@@ -222,8 +224,9 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
const struct submodule *sub;
struct strbuf sb = STRBUF_INIT;
char *url = NULL;
- const char *upd = NULL;
- const char *displaypath = relative_path(xgetcwd(), prefix, &sb);
+ char *upd = NULL;
+ char *cwd = xgetcwd();
+ const char *displaypath = relative_path(cwd, prefix, &sb);
/* Only loads from .gitmodules, no overlay with .git/config */
gitmodules_config();
@@ -261,6 +264,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
remoteurl = xgetcwd();
url = relative_url(remoteurl, url, NULL);
strbuf_release(&remotesb);
+ free(remoteurl);
}
if (git_config_set(sb.buf, url))
@@ -269,26 +273,27 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
if (!quiet)
printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
sub->name, url, displaypath);
- free(url);
}
/* Copy "update" setting when it is not set yet */
strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.update", sub->name);
- if (git_config_get_string_const(sb.buf, &upd) && sub->update) {
- upd = sub->update;
+ if (git_config_get_string(sb.buf, &upd) && sub->update) {
+ upd = xstrdup(sub->update);
if (strcmp(sub->update, "checkout") &&
strcmp(sub->update, "rebase") &&
strcmp(sub->update, "merge") &&
strcmp(sub->update, "none")) {
fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
upd, sub->name);
- upd = "none";
+ upd = xstrdup("none");
}
if (git_config_set(sb.buf, upd))
die(_("Failed to register update mode for submodule path '%s'"), displaypath);
}
strbuf_release(&sb);
+ free(cwd);
+ free(upd);
+ free(url);
}
static int module_init(int argc, const char **argv, const char *prefix)
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 326 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 118 +---------------
t/t0060-path-utils.sh | 42 ++++++
3 files changed, 366 insertions(+), 120 deletions(-)
--
2.7.0.rc0.42.ge5f5e2d
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCHv4 1/2] submodule: port resolve_relative_url from shell to C
2016-01-28 2:30 ` [PATCHv4 " Stefan Beller
@ 2016-01-28 2:30 ` Stefan Beller
2016-01-28 22:03 ` Junio C Hamano
2016-01-28 2:30 ` [PATCHv4 2/2] submodule: port init " Stefan Beller
1 sibling, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-01-28 2:30 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, Jens.Lehmann, sunshine, j6t
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 208 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 42 +++++++++
3 files changed, 253 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 8002187..13583d9 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,210 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ int flag = 0;
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
+
+ if (!refname)
+ die("No such ref: HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = dest;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = find_last_dir_sep(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome correct
+ * http://a.com/b ../c http://a.com/c yes
+ * http://a.com/b ../../c http://c no (domain should be kept)
+ * http://a.com/b ../../../c http:/c no
+ * http://a.com/b ../../../../c http:c no
+ * http://a.com/b ../../../../../c .:c no
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ free(remoteurl);
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -502,7 +706,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 10c5af9..615ef9b 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" ||
@@ -1176,9 +1103,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 627ef85..8a1579c 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -286,4 +293,39 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
+test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
+test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.7.0.rc0.42.ge5f5e2d
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCHv4 1/2] submodule: port resolve_relative_url from shell to C
2016-01-28 2:30 ` [PATCHv4 1/2] submodule: port resolve_relative_url " Stefan Beller
@ 2016-01-28 22:03 ` Junio C Hamano
2016-01-28 22:11 ` Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Junio C Hamano @ 2016-01-28 22:03 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, Jens.Lehmann, sunshine, j6t
Stefan Beller <sbeller@google.com> writes:
> +static char *relative_url(const char *remote_url,
> + const char *url,
> + const char *up_path)
> +{
> + int is_relative = 0;
> + int colonsep = 0;
> + char *out;
> + char *remoteurl = xstrdup(remote_url);
> + struct strbuf sb = STRBUF_INIT;
> + size_t len = strlen(remoteurl);
> +
> + if (is_dir_sep(remoteurl[len]))
> + remoteurl[len] = '\0';
> +
> + if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
> + is_relative = 0;
> + else {
> + is_relative = 1;
> + /*
> + * Prepend a './' to ensure all relative
> + * remoteurls start with './' or '../'
> + */
> + if (!starts_with_dot_slash(remoteurl) &&
> + !starts_with_dot_dot_slash(remoteurl)) {
> + strbuf_reset(&sb);
> + strbuf_addf(&sb, "./%s", remoteurl);
> + free(remoteurl);
> + remoteurl = strbuf_detach(&sb, NULL);
> + }
> + }
> + /*
> + * When the url starts with '../', remove that and the
> + * last directory in remoteurl.
> + */
> + while (url) {
> + if (starts_with_dot_dot_slash(url)) {
> + url += 3;
> + colonsep |= chop_last_dir(&remoteurl, is_relative);
> + } else if (starts_with_dot_slash(url))
> + url += 2;
> + else
> + break;
> + }
> + strbuf_reset(&sb);
> + strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
> +
> + if (starts_with_dot_slash(sb.buf))
> + out = xstrdup(sb.buf + 2);
> + else
> + out = xstrdup(sb.buf);
> + strbuf_reset(&sb);
> +
> + free(remoteurl);
This is a rather strange place to put this free(), as you are done
with it a bit earlier, but it's OK. I briefly wondered if the code
becomes easier to follow with fewer free(remoteurl) if this local
variable is made into a strbuf, but I didn't seriously think it
through.
Otherwise looking good.
Thanks.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCHv4 1/2] submodule: port resolve_relative_url from shell to C
2016-01-28 22:03 ` Junio C Hamano
@ 2016-01-28 22:11 ` Stefan Beller
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-28 22:11 UTC (permalink / raw)
To: Junio C Hamano
Cc: git@vger.kernel.org, Jens Lehmann, Eric Sunshine, Johannes Sixt
On Thu, Jan 28, 2016 at 2:03 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> +static char *relative_url(const char *remote_url,
>> + const char *url,
>> + const char *up_path)
>> +{
>> + int is_relative = 0;
>> + int colonsep = 0;
>> + char *out;
>> + char *remoteurl = xstrdup(remote_url);
>> + struct strbuf sb = STRBUF_INIT;
>> + size_t len = strlen(remoteurl);
>> +
>> + if (is_dir_sep(remoteurl[len]))
>> + remoteurl[len] = '\0';
>> +
>> + if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
>> + is_relative = 0;
>> + else {
>> + is_relative = 1;
>> + /*
>> + * Prepend a './' to ensure all relative
>> + * remoteurls start with './' or '../'
>> + */
>> + if (!starts_with_dot_slash(remoteurl) &&
>> + !starts_with_dot_dot_slash(remoteurl)) {
>> + strbuf_reset(&sb);
>> + strbuf_addf(&sb, "./%s", remoteurl);
>> + free(remoteurl);
>> + remoteurl = strbuf_detach(&sb, NULL);
>> + }
>> + }
>> + /*
>> + * When the url starts with '../', remove that and the
>> + * last directory in remoteurl.
>> + */
>> + while (url) {
>> + if (starts_with_dot_dot_slash(url)) {
>> + url += 3;
>> + colonsep |= chop_last_dir(&remoteurl, is_relative);
>> + } else if (starts_with_dot_slash(url))
>> + url += 2;
>> + else
>> + break;
>> + }
>> + strbuf_reset(&sb);
>> + strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
>> +
>> + if (starts_with_dot_slash(sb.buf))
>> + out = xstrdup(sb.buf + 2);
>> + else
>> + out = xstrdup(sb.buf);
>> + strbuf_reset(&sb);
>> +
>> + free(remoteurl);
>
> This is a rather strange place to put this free(), as you are done
> with it a bit earlier, but it's OK. I briefly wondered if the code
> becomes easier to follow with fewer free(remoteurl) if this local
> variable is made into a strbuf, but I didn't seriously think it
> through.
Right. As I did not touch that particular free with the resend, I wondered
how it came there, too. And I think I had it at the end of the function and
then realized the return just after the current position would leak it, so
I moved it minimally up. If I'll resend again, I'll move it up to where
it was last used.
>
> Otherwise looking good.
>
> Thanks.
Thanks,
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCHv4 2/2] submodule: port init from shell to C
2016-01-28 2:30 ` [PATCHv4 " Stefan Beller
2016-01-28 2:30 ` [PATCHv4 1/2] submodule: port resolve_relative_url " Stefan Beller
@ 2016-01-28 2:30 ` Stefan Beller
2016-02-27 8:30 ` Duy Nguyen
1 sibling, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-01-28 2:30 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, Jens.Lehmann, sunshine, j6t
By having the `init` functionality in C, we can reference it easier
from other parts in the code.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 119 ++++++++++++++++++++++++++++++++++++++++++--
git-submodule.sh | 39 +--------------
2 files changed, 115 insertions(+), 43 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 13583d9..689c354 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -214,6 +214,119 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
+static int git_submodule_config(const char *var, const char *value, void *cb)
+{
+ return parse_submodule_config_option(var, value);
+}
+
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+ const struct submodule *sub;
+ struct strbuf sb = STRBUF_INIT;
+ char *url = NULL;
+ char *upd = NULL;
+ char *cwd = xgetcwd();
+ const char *displaypath = relative_path(cwd, prefix, &sb);
+
+ /* Only loads from .gitmodules, no overlay with .git/config */
+ gitmodules_config();
+
+ sub = submodule_from_path(null_sha1, path);
+
+ /*
+ * Copy url setting when it is not set yet.
+ * To look up the url in .git/config, we must not fall back to
+ * .gitmodules, so look it up directly.
+ */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.url", sub->name);
+ if (git_config_get_string(sb.buf, &url)) {
+ url = xstrdup(sub->url);
+
+ if (!url)
+ die(_("No url found for submodule path '%s' in .gitmodules"),
+ displaypath);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *remoteurl;
+ char *remote = get_default_remote();
+ struct strbuf remotesb = STRBUF_INIT;
+ strbuf_addf(&remotesb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(remotesb.buf, &remoteurl))
+ /*
+ * The repository is its own
+ * authoritative upstream
+ */
+ remoteurl = xgetcwd();
+ url = relative_url(remoteurl, url, NULL);
+ strbuf_release(&remotesb);
+ free(remoteurl);
+ }
+
+ if (git_config_set(sb.buf, url))
+ die(_("Failed to register url for submodule path '%s'"),
+ displaypath);
+ if (!quiet)
+ printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
+ sub->name, url, displaypath);
+ }
+
+ /* Copy "update" setting when it is not set yet */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.update", sub->name);
+ if (git_config_get_string(sb.buf, &upd) && sub->update) {
+ upd = xstrdup(sub->update);
+ if (strcmp(sub->update, "checkout") &&
+ strcmp(sub->update, "rebase") &&
+ strcmp(sub->update, "merge") &&
+ strcmp(sub->update, "none")) {
+ fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
+ upd, sub->name);
+ upd = xstrdup("none");
+ }
+ if (git_config_set(sb.buf, upd))
+ die(_("Failed to register update mode for submodule path '%s'"), displaypath);
+ }
+ strbuf_release(&sb);
+ free(cwd);
+ free(upd);
+ free(url);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+ int quiet = 0;
+ int i;
+
+ struct option module_init_options[] = {
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper init [<path>]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_init_options,
+ git_submodule_helper_usage, 0);
+
+ if (argc == 0)
+ die(_("Pass at least one submodule"));
+
+ for (i = 0; i < argc; i++)
+ init_submodule(argv[i], prefix, quiet);
+
+ return 0;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -459,11 +572,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
-static int git_submodule_config(const char *var, const char *value, void *cb)
-{
- return parse_submodule_config_option(var, value);
-}
-
struct submodule_update_clone {
/* states */
int count;
@@ -709,6 +817,7 @@ static struct cmd_struct commands[] = {
{"update-clone", update_clone},
{"resolve-relative-url", resolve_relative_url},
{"resolve-relative-url-test", resolve_relative_url_test},
+ {"init", module_init}
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 615ef9b..6fce0dc 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -398,45 +398,8 @@ cmd_init()
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
- name=$(git submodule--helper name "$sm_path") || exit
-
- displaypath=$(relative_path "$sm_path")
-
- # Copy url setting when it is not set yet
- if test -z "$(git config "submodule.$name.url")"
- then
- url=$(git config -f .gitmodules submodule."$name".url)
- test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
-
- # Possibly a url relative to parent
- case "$url" in
- ./*|../*)
- url=$(git submodule--helper resolve-relative-url "$url") || exit
- ;;
- esac
- git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
- fi
-
- # Copy "update" setting when it is not set yet
- if upd="$(git config -f .gitmodules submodule."$name".update)" &&
- test -n "$upd" &&
- test -z "$(git config submodule."$name".update)"
- then
- case "$upd" in
- checkout | rebase | merge | none)
- ;; # known modes of updating
- *)
- echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
- upd=none
- ;;
- esac
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
- fi
+ git submodule--helper init ${GIT_QUIET:+--quiet} "$sm_path" || exit
done
}
--
2.7.0.rc0.42.ge5f5e2d
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCHv4 2/2] submodule: port init from shell to C
2016-01-28 2:30 ` [PATCHv4 2/2] submodule: port init " Stefan Beller
@ 2016-02-27 8:30 ` Duy Nguyen
0 siblings, 0 replies; 37+ messages in thread
From: Duy Nguyen @ 2016-02-27 8:30 UTC (permalink / raw)
To: Stefan Beller
Cc: Git Mailing List, Junio C Hamano, Jens Lehmann, Eric Sunshine,
Johannes Sixt
On Thu, Jan 28, 2016 at 9:30 AM, Stefan Beller <sbeller@google.com> wrote:
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 13583d9..689c354 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> +static int module_init(int argc, const char **argv, const char *prefix)
> +{
> + int quiet = 0;
> + int i;
> +
> + struct option module_init_options[] = {
> + OPT_STRING(0, "prefix", &prefix,
> + N_("path"),
> + N_("alternative anchor for relative paths")),
> + OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
I think we need N_() around this "Suppress..." string. By the way,
typo in "initializing"
--
Duy
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCHv3 1/2] submodule: port resolve_relative_url from shell to C
2016-01-22 22:30 ` Junio C Hamano
2016-01-22 22:32 ` Stefan Beller
2016-01-22 23:32 ` [PATCHv3 0/2] Port `git submodule init` " Stefan Beller
@ 2016-01-22 23:32 ` Stefan Beller
2016-01-22 23:32 ` [PATCHv3 2/2] submodule: port init " Stefan Beller
3 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-22 23:32 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, j6t, sunshine, Jens.Lehmann
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 206 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 42 +++++++++
3 files changed, 251 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 8002187..92d7d32 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,208 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ int flag = 0;
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
+
+ if (!refname)
+ die("No such ref: HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = xstrdup(dest);
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = find_last_dir_sep(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome correct
+ * http://a.com/b ../c http://a.com/c yes
+ * http://a.com/b ../../c http://c no (domain should be kept)
+ * http://a.com/b ../../../c http:/c no
+ * http://a.com/b ../../../../c http:c no
+ * http://a.com/b ../../../../../c .:c no
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ free(remoteurl);
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -502,7 +704,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 10c5af9..615ef9b 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" ||
@@ -1176,9 +1103,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 627ef85..8a1579c 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -286,4 +293,39 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
+test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
+test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.7.0.rc0.45.g0dba895.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCHv3 2/2] submodule: port init from shell to C
2016-01-22 22:30 ` Junio C Hamano
` (2 preceding siblings ...)
2016-01-22 23:32 ` [PATCHv3 1/2] submodule: port resolve_relative_url " Stefan Beller
@ 2016-01-22 23:32 ` Stefan Beller
3 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-01-22 23:32 UTC (permalink / raw)
To: git, gitster; +Cc: Stefan Beller, j6t, sunshine, Jens.Lehmann
By having the `init` functionality in C, we can reference it easier
from other parts in the code.
Signed-off-by: Stefan Beller <sbeller@google.com>
---
builtin/submodule--helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++--
git-submodule.sh | 39 +--------------
2 files changed, 111 insertions(+), 43 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 92d7d32..c9b0c05 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -212,6 +212,115 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
+static int git_submodule_config(const char *var, const char *value, void *cb)
+{
+ return parse_submodule_config_option(var, value);
+}
+
+static void init_submodule(const char *path, const char *prefix, int quiet)
+{
+ const struct submodule *sub;
+ struct strbuf sb = STRBUF_INIT;
+ char *url = NULL;
+ const char *upd = NULL;
+ const char *displaypath = relative_path(xgetcwd(), prefix, &sb);
+
+ /* Only loads from .gitmodules, no overlay with .git/config */
+ gitmodules_config();
+
+ sub = submodule_from_path(null_sha1, path);
+
+ /*
+ * Copy url setting when it is not set yet.
+ * To look up the url in .git/config, we must not fall back to
+ * .gitmodules, so look it up directly.
+ */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.url", sub->name);
+ if (git_config_get_string(sb.buf, &url)) {
+ url = xstrdup(sub->url);
+
+ if (!url)
+ die(_("No url found for submodule path '%s' in .gitmodules"),
+ displaypath);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *remoteurl;
+ char *remote = get_default_remote();
+ struct strbuf remotesb = STRBUF_INIT;
+ strbuf_addf(&remotesb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(remotesb.buf, &remoteurl))
+ /*
+ * The repository is its own
+ * authoritative upstream
+ */
+ remoteurl = xgetcwd();
+ url = relative_url(remoteurl, url, NULL);
+ strbuf_release(&remotesb);
+ }
+
+ if (git_config_set(sb.buf, url))
+ die(_("Failed to register url for submodule path '%s'"),
+ displaypath);
+ if (!quiet)
+ printf(_("Submodule '%s' (%s) registered for path '%s'\n"),
+ sub->name, url, displaypath);
+ free(url);
+ }
+
+ /* Copy "update" setting when it is not set yet */
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "submodule.%s.update", sub->name);
+ if (git_config_get_string_const(sb.buf, &upd) && sub->update) {
+ upd = sub->update;
+ if (strcmp(sub->update, "checkout") &&
+ strcmp(sub->update, "rebase") &&
+ strcmp(sub->update, "merge") &&
+ strcmp(sub->update, "none")) {
+ fprintf(stderr, _("warning: unknown update mode '%s' suggested for submodule '%s'\n"),
+ upd, sub->name);
+ upd = "none";
+ }
+ if (git_config_set(sb.buf, upd))
+ die(_("Failed to register update mode for submodule path '%s'"), displaypath);
+ }
+ strbuf_release(&sb);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix)
+{
+ int quiet = 0;
+ int i;
+
+ struct option module_init_options[] = {
+ OPT_STRING(0, "prefix", &prefix,
+ N_("path"),
+ N_("alternative anchor for relative paths")),
+ OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper init [<path>]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_init_options,
+ git_submodule_helper_usage, 0);
+
+ if (argc == 0)
+ die(_("Pass at least one submodule"));
+
+ for (i = 0; i < argc; i++)
+ init_submodule(argv[i], prefix, quiet);
+
+ return 0;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
@@ -457,11 +566,6 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
-static int git_submodule_config(const char *var, const char *value, void *cb)
-{
- return parse_submodule_config_option(var, value);
-}
-
struct submodule_update_clone {
/* states */
int count;
@@ -707,6 +811,7 @@ static struct cmd_struct commands[] = {
{"update-clone", update_clone},
{"resolve-relative-url", resolve_relative_url},
{"resolve-relative-url-test", resolve_relative_url_test},
+ {"init", module_init}
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 615ef9b..6fce0dc 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -398,45 +398,8 @@ cmd_init()
while read mode sha1 stage sm_path
do
die_if_unmatched "$mode"
- name=$(git submodule--helper name "$sm_path") || exit
-
- displaypath=$(relative_path "$sm_path")
-
- # Copy url setting when it is not set yet
- if test -z "$(git config "submodule.$name.url")"
- then
- url=$(git config -f .gitmodules submodule."$name".url)
- test -z "$url" &&
- die "$(eval_gettext "No url found for submodule path '\$displaypath' in .gitmodules")"
-
- # Possibly a url relative to parent
- case "$url" in
- ./*|../*)
- url=$(git submodule--helper resolve-relative-url "$url") || exit
- ;;
- esac
- git config submodule."$name".url "$url" ||
- die "$(eval_gettext "Failed to register url for submodule path '\$displaypath'")"
- say "$(eval_gettext "Submodule '\$name' (\$url) registered for path '\$displaypath'")"
- fi
-
- # Copy "update" setting when it is not set yet
- if upd="$(git config -f .gitmodules submodule."$name".update)" &&
- test -n "$upd" &&
- test -z "$(git config submodule."$name".update)"
- then
- case "$upd" in
- checkout | rebase | merge | none)
- ;; # known modes of updating
- *)
- echo >&2 "warning: unknown update mode '$upd' suggested for submodule '$name'"
- upd=none
- ;;
- esac
- git config submodule."$name".update "$upd" ||
- die "$(eval_gettext "Failed to register update mode for submodule path '\$displaypath'")"
- fi
+ git submodule--helper init ${GIT_QUIET:+--quiet} "$sm_path" || exit
done
}
--
2.7.0.rc0.45.g0dba895.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 0/2] Port `git submodule init` from shell to C
@ 2016-02-12 23:39 Stefan Beller
2016-02-12 23:39 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-02-12 23:39 UTC (permalink / raw)
To: git, gitster, jrnieder, Jens.Lehmann; +Cc: Stefan Beller
This applies on top of the just sent series which is going to replace
sb/submodule-parallel-update, replacing sb/submodule-init.
* Using enums for the submodule update strategy now.
Thanks,
Stefan
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 315 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 118 +----------------
submodule.c | 21 +++
submodule.h | 1 +
t/t0060-path-utils.sh | 42 ++++++
5 files changed, 382 insertions(+), 115 deletions(-)
--
2.7.1.292.g18a4ced.dirty
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-02-12 23:39 [PATCH 0/2] Port `git submodule init` " Stefan Beller
@ 2016-02-12 23:39 ` Stefan Beller
2016-02-18 20:23 ` Junio C Hamano
` (2 more replies)
0 siblings, 3 replies; 37+ messages in thread
From: Stefan Beller @ 2016-02-12 23:39 UTC (permalink / raw)
To: git, gitster, jrnieder, Jens.Lehmann; +Cc: Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 208 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 42 +++++++++
3 files changed, 253 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 65bdc14..d1e9118 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,210 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ int flag = 0;
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
+
+ if (!refname)
+ die("No such ref: HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = dest;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = find_last_dir_sep(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome correct
+ * http://a.com/b ../c http://a.com/c yes
+ * http://a.com/b ../../c http://c no (domain should be kept)
+ * http://a.com/b ../../../c http:/c no
+ * http://a.com/b ../../../../c http:c no
+ * http://a.com/b ../../../../../c .:c no
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ free(remoteurl);
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -502,7 +706,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 10c5af9..615ef9b 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" ||
@@ -1176,9 +1103,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index f0152a7..0d2176b 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -289,4 +296,39 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
+test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
+test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
+test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
+test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.7.1.292.g18a4ced.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-02-12 23:39 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
@ 2016-02-18 20:23 ` Junio C Hamano
2016-02-27 8:28 ` Duy Nguyen
2016-03-02 17:21 ` Johannes Sixt
2 siblings, 0 replies; 37+ messages in thread
From: Junio C Hamano @ 2016-02-18 20:23 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, jrnieder, Jens.Lehmann
Stefan Beller <sbeller@google.com> writes:
> +static int starts_with_dot_slash(const char *str)
> +{
> + return str[0] == '.' && is_dir_sep(str[1]);
> +}
> +
> +static int starts_with_dot_dot_slash(const char *str)
> +{
> + return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
> +}
> +
> +/*
> + * Returns 1 if it was the last chop before ':'.
> + */
> +static int chop_last_dir(char **remoteurl, int is_relative)
> +{
> + char *rfind = find_last_dir_sep(*remoteurl);
> + if (rfind) {
> + *rfind = '\0';
> + return 0;
> + }
> +
> + rfind = strrchr(*remoteurl, ':');
> + if (rfind) {
> + *rfind = '\0';
> + return 1;
> + }
> +
> + if (is_relative || !strcmp(".", *remoteurl))
> + die(_("cannot strip one component off url '%s'"),
> + *remoteurl);
> +
> + free(*remoteurl);
> + *remoteurl = xstrdup(".");
> + return 0;
> +}
> +
> +/*
> + * The `url` argument is the URL that navigates to the submodule origin
> + * repo. When relative, this URL is relative to the superproject origin
> + * URL repo. The `up_path` argument, if specified, is the relative
> + * path that navigates from the submodule working tree to the superproject
> + * working tree. Returns the origin URL of the submodule.
> + *
> + * Return either 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.
> + *
> + * NEEDSWORK: This works incorrectly on the domain and protocol part.
> + * remote_url url outcome correct
> + * http://a.com/b ../c http://a.com/c yes
> + * http://a.com/b ../../c http://c no (domain should be kept)
> + * http://a.com/b ../../../c http:/c no
> + * http://a.com/b ../../../../c http:c no
> + * http://a.com/b ../../../../../c .:c no
> + */
Not just "no" but we should say what the expected outcome is. I
think all of them should error out?
Given how chop_last_dir() works, I think this function is broken
when a local part has a colon in its path component, too. I do not
think the scripted version did any better on such a URL; just
another thing that NEEDSWORK comment should list as a thing to be
fixed in the future.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-02-12 23:39 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-02-18 20:23 ` Junio C Hamano
@ 2016-02-27 8:28 ` Duy Nguyen
2016-03-02 17:21 ` Johannes Sixt
2 siblings, 0 replies; 37+ messages in thread
From: Duy Nguyen @ 2016-02-27 8:28 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, gitster, jrnieder, Jens.Lehmann
On Fri, Feb 12, 2016 at 03:39:15PM -0800, Stefan Beller wrote:
> Later on we want to automatically call `git submodule init` from
> other commands, such that the users don't have to initialize the
> submodule themselves. As these other commands are written in C
> already, we'd need the init functionality in C, too. The
> `resolve_relative_url` function is a large part of that init
> functionality, so start by porting this function to C.
>
> To create the tests in t0060, the function `resolve_relative_url`
> was temporarily enhanced to write all inputs and output to disk
> when running the test suite. The added tests in this patch are
> a small selection thereof.
>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
> builtin/submodule--helper.c | 208 +++++++++++++++++++++++++++++++++++++++++++-
i18n fixes. Can you squash this patch in when it's re-rolled?
-- 8< --
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f4a0fd7..a6e54fa 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -22,7 +22,7 @@ static char *get_default_remote(void)
const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
if (!refname)
- die("No such ref: HEAD");
+ die(_("No such ref: %s"), "HEAD");
/* detached HEAD */
if (!strcmp(refname, "HEAD"))
-- 8< --
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-02-12 23:39 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-02-18 20:23 ` Junio C Hamano
2016-02-27 8:28 ` Duy Nguyen
@ 2016-03-02 17:21 ` Johannes Sixt
2016-03-02 17:34 ` Stefan Beller
2 siblings, 1 reply; 37+ messages in thread
From: Johannes Sixt @ 2016-03-02 17:21 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, gitster, jrnieder, Jens.Lehmann
Am 13.02.2016 um 00:39 schrieb Stefan Beller:
> @@ -289,4 +296,39 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
> test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
> test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
>
> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
> +test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
> +test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
> +test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
> +test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
> +test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
> +test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
> +test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
> +test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
> +test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
> +test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
The tests with absolute paths all fail on Windows. The reason is that
git.exe sees mangled paths and 'git submodule--helper
resolve-relative-url-test' produces mangled paths (that begins with a
drive letter), whereas the test script expects POSIX paths. The pattern
I currently use to fix this is
test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"
(In our test scripts, $PWD is a POSIX style path and $(pwd) is a
Windows style path).
With this change, the penultimate case above still fails because the
'home2/..' gets lost somewhere in the actual output, which I still have
to debug.
The two cases beginning with '/u//' cannot be tested on Windows.
Are they important? Are the doubled slashes intentional?
> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
> +test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
> +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
> +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
> +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
> +
> test_done
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-03-02 17:21 ` Johannes Sixt
@ 2016-03-02 17:34 ` Stefan Beller
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-03-02 17:34 UTC (permalink / raw)
To: Johannes Sixt
Cc: git@vger.kernel.org, Junio C Hamano, Jonathan Nieder,
Jens Lehmann
On Wed, Mar 2, 2016 at 9:21 AM, Johannes Sixt <j6t@kdbg.org> wrote:
> Am 13.02.2016 um 00:39 schrieb Stefan Beller:
>> @@ -289,4 +296,39 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
>> test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
>> test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
>>
>> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
>> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
>> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
>> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
>> +test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
>> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
>> +test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
>> +test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
>> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
>> +test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
>> +test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
>> +test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
>> +test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
>> +test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
>> +test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
>> +test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
>> +test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
>
> The tests with absolute paths all fail on Windows. The reason is that
> git.exe sees mangled paths and 'git submodule--helper
> resolve-relative-url-test' produces mangled paths (that begins with a
> drive letter), whereas the test script expects POSIX paths. The pattern
> I currently use to fix this is
>
> test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"
>
> (In our test scripts, $PWD is a POSIX style path and $(pwd) is a
> Windows style path).
>
> With this change, the penultimate case above still fails because the
> 'home2/..' gets lost somewhere in the actual output, which I still have
> to debug.
>
> The two cases beginning with '/u//' cannot be tested on Windows.
> Are they important? Are the doubled slashes intentional?
The way I got the test cases is by inserting a debug printf into the
shell script
and then running the test suite (as that ought to work correct and
cover everything).
And the double slash is intentional, somewhere in the test suite we have a case
where that occurs. It may be a calling error?
Thanks for looking into this on the Windows side :)
Thanks,
Stefan
>
>> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
>> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
>> +test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
>> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
>> +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
>> +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
>> +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
>> +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
>> +
>> test_done
>>
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 0/2] Port `git submodule init` from shell to C
@ 2016-03-15 0:15 Stefan Beller
2016-03-15 0:15 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-03-15 0:15 UTC (permalink / raw)
To: git; +Cc: gitster, jrnieder, j6t, pclouds, Stefan Beller
This applies on top of origin/sb/submodule-parallel-update.
By having the `init` functionality in C, we can reference it easier
from other parts in the code.
Thanks for the reviews a long time ago!
Junio,
I fixed the NEEDSWORK comment for relative_url
and thought about the memory allocation
Duy,
I fixed the i18n issues introduced.
Johannes,
I took $PWD instead of absolute paths. According to your last message, this
may still break on Windows for
test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
There are however no further tests starting with /.
Thanks,
Stefan
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 317 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 118 +----------------
submodule.c | 21 +++
submodule.h | 1 +
t/t0060-path-utils.sh | 43 ++++++
5 files changed, 385 insertions(+), 115 deletions(-)
Diff to origin/sb/submodule-init:
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 213af2e..d942463 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -22,7 +22,7 @@ static char *get_default_remote(void)
const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
if (!refname)
- die("No such ref: HEAD");
+ die(_("No such ref: %s"), "HEAD");
/* detached HEAD */
if (!strcmp(refname, "HEAD"))
@@ -94,12 +94,14 @@ static int chop_last_dir(char **remoteurl, int is_relative)
* the superproject working tree otherwise.
*
* NEEDSWORK: This works incorrectly on the domain and protocol part.
- * remote_url url outcome correct
- * http://a.com/b ../c http://a.com/c yes
- * http://a.com/b ../../c http://c no (domain should be kept)
- * http://a.com/b ../../../c http:/c no
- * http://a.com/b ../../../../c http:c no
- * http://a.com/b ../../../../../c .:c no
+ * remote_url url outcome expectation
+ * http://a.com/b ../c http://a.com/c as is
+ * http://a.com/b ../../c http://c error out
+ * http://a.com/b ../../../c http:/c error out
+ * http://a.com/b ../../../../c http:c error out
+ * http://a.com/b ../../../../../c .:c error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
*/
static char *relative_url(const char *remote_url,
const char *url,
@@ -146,6 +148,7 @@ static char *relative_url(const char *remote_url,
}
strbuf_reset(&sb);
strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+ free(remoteurl);
if (starts_with_dot_slash(sb.buf))
out = xstrdup(sb.buf + 2);
@@ -153,7 +156,6 @@ static char *relative_url(const char *remote_url,
out = xstrdup(sb.buf);
strbuf_reset(&sb);
- free(remoteurl);
if (!up_path || !is_relative)
return out;
@@ -299,7 +301,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
OPT_STRING(0, "prefix", &prefix,
N_("path"),
N_("alternative anchor for relative paths")),
- OPT__QUIET(&quiet, "Suppress output for initialzing a submodule"),
+ OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
OPT_END()
};
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 8a1579c..579c1fa 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -293,35 +293,36 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
-test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
-test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
-test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
-test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
-test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
-test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
-test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/subsuper_update_r" "../subsubsuper_update_r" "/u//trash directory.t7406-submodule-update/subsubsuper_update_r"
-test_submodule_relative_url "(null)" "/u//trash directory.t7406-submodule-update/super_update_r2" "../subsuper_update_r" "/u//trash directory.t7406-submodule-update/subsuper_update_r"
-test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm/." "../." "/u/trash directory.t3600-rm/."
-test_submodule_relative_url "(null)" "/u/trash directory.t3600-rm" "./." "/u/trash directory.t3600-rm/."
-test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
-test_submodule_relative_url "../" "/u/trash directory.t7400-submodule-basic/addtest" "../repo" "/u/trash directory.t7400-submodule-basic/repo"
-test_submodule_relative_url "(null)" "/u/trash directory.t7400-submodule-basic" "./å äö" "/u/trash directory.t7400-submodule-basic/å äö"
-test_submodule_relative_url "(null)" "/u/trash directory.t7403-submodule-sync/." "../submodule" "/u/trash directory.t7403-submodule-sync/submodule"
-test_submodule_relative_url "(null)" "/u/trash directory.t7407-submodule-foreach/submodule" "../submodule" "/u/trash directory.t7407-submodule-foreach/submodule"
-test_submodule_relative_url "(null)" "/u/trash directory.t7409-submodule-detached-worktree/home2/../remote" "../bundle1" "/u/trash directory.t7409-submodule-detached-worktree/home2/../bundle1"
-test_submodule_relative_url "(null)" "/u/trash directory.t7613-merge-submodule/submodule_update_repo" "./." "/u/trash directory.t7613-merge-submodule/submodule_update_repo/."
+test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
+test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
+test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
-test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
-test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
--
2.7.0.rc0.46.g8f16ed4.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-03-15 0:15 [PATCH 0/2] Port `git submodule init` " Stefan Beller
@ 2016-03-15 0:15 ` Stefan Beller
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-03-15 0:15 UTC (permalink / raw)
To: git; +Cc: gitster, jrnieder, j6t, pclouds, Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 210 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 43 +++++++++
3 files changed, 256 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a484945..bc7cf87 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,212 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ int flag = 0;
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
+
+ if (!refname)
+ die(_("No such ref: %s"), "HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = dest;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = find_last_dir_sep(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome expectation
+ * http://a.com/b ../c http://a.com/c as is
+ * http://a.com/b ../../c http://c error out
+ * http://a.com/b ../../../c http:/c error out
+ * http://a.com/b ../../../../c http:c error out
+ * http://a.com/b ../../../../../c .:c error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+ free(remoteurl);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -515,7 +721,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 86018ee..b3290f8 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" ||
@@ -1178,9 +1105,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 627ef85..579c1fa 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -286,4 +293,40 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
+test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
+test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.7.0.rc0.46.g8f16ed4.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 0/2] Port `git submodule init` from shell to C
@ 2016-04-13 0:18 Stefan Beller
2016-04-13 0:18 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-04-13 0:18 UTC (permalink / raw)
To: git; +Cc: gitster, pclouds, j6t, Stefan Beller
This is a resend of origin/sb/submodule-init (and it still applies on
top of submodule-parallel-update)
I squashed a change which Michael Haggerty proposed in one of the
large cleanup series preparing for the new refs backend. (18/21)
As that is the only fix in that series touching submodules,
picking it up here would untangle sb/submodule-init from that series.
Thanks,
Stefan
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index d942463..3078790 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -17,9 +17,8 @@ static char *get_default_remote(void)
{
char *dest = NULL, *ret;
unsigned char sha1[20];
- int flag = 0;
struct strbuf sb = STRBUF_INIT;
- const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
if (!refname)
die(_("No such ref: %s"), "HEAD");
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 316 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 118 +----------------
submodule.c | 21 +++
submodule.h | 1 +
t/t0060-path-utils.sh | 43 ++++++
5 files changed, 384 insertions(+), 115 deletions(-)
--
2.5.0.264.gc776916.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-04-13 0:18 [PATCH 0/2] Port `git submodule init` " Stefan Beller
@ 2016-04-13 0:18 ` Stefan Beller
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-04-13 0:18 UTC (permalink / raw)
To: git; +Cc: gitster, pclouds, j6t, Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 209 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 43 +++++++++
3 files changed, 255 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a484945..2ab3662 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,211 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+
+ if (!refname)
+ die(_("No such ref: %s"), "HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = dest;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = find_last_dir_sep(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome expectation
+ * http://a.com/b ../c http://a.com/c as is
+ * http://a.com/b ../../c http://c error out
+ * http://a.com/b ../../../c http:/c error out
+ * http://a.com/b ../../../../c http:c error out
+ * http://a.com/b ../../../../../c .:c error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+ free(remoteurl);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -515,7 +720,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 86018ee..b3290f8 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" ||
@@ -1178,9 +1105,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 627ef85..579c1fa 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -286,4 +293,40 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
+test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
+test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.5.0.264.gc776916.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 0/2] Port `submodule init` to C
@ 2016-04-14 18:18 Stefan Beller
2016-04-14 18:18 ` [PATCH 1/2] submodule: port resolve_relative_url from shell " Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-04-14 18:18 UTC (permalink / raw)
To: git; +Cc: gitster, pclouds, j6t, Stefan Beller
This is another round for sb/submodule-init.
Changes since last round:
* Also iterate over the submodules in the C helper. With that missing piece
`git submodule init` is completely handled in C now except for the usage
string and the command->subcommand selection. (i.e. when calling
`git submodule init`, we still go through git.c -> git-submodule.sh
-> submodule--helper.c, but we do not go back into the shell after parsing
`init` and calling module_init for it.
* This applies on another base commit, such that we make use of the tests
written in origin/sb/submodule-path-misc-bugs. (I am not sure if I have too
many series in flight stomping on each other here)
* This time I actually fix what Ramsay was hinting at:
strbuf_detach(&sb, NULL) instead of strbuf_detach(&sb, 0);
Where do these patches apply?
=============================
I ran the following commands for a new starting point of this series:
git checkout --detach origin/sb/submodule-parallel-update
git merge origin/sb/submodule-helper-clone-regression-fix
git merge origin/sb/submodule-path-misc-bugs
The second merge produces 2 conflicts, which can be resolved like this:
(I am unsure about the second comment in strbuf.h though)
diff --cc builtin/fetch.c
index 5aa1c2d,e4639d8..0000000
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@@ -37,7 -37,8 +37,8 @@@ static int prune = -1; /* unspecified *
static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int tags = TAGS_DEFAULT, unshallow, update_shallow;
-static int max_children = 1;
+static int max_children = -1;
+ static enum transport_family family;
static const char *depth;
static const char *upload_pack;
static struct strbuf default_rla = STRBUF_INIT;
diff --cc strbuf.h
index d4f2aa1,f72fd14..0000000
--- a/strbuf.h
+++ b/strbuf.h
@@@ -387,15 -387,10 +387,16 @@@ extern ssize_t strbuf_read_file(struct
extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
/**
+ * Write the whole content of the strbuf to the stream not stopping at
+ * NUL bytes.
+ */
+extern ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
+
+/**
- * Read a line from a FILE *, overwriting the existing contents
- * of the strbuf. The second argument specifies the line
- * terminator character, typically `'\n'`.
+ * Read a line from a FILE *, overwriting the existing contents of
+ * the strbuf. The strbuf_getline*() family of functions share
+ * this signature, but have different line termination conventions.
+ *
* Reading stops after the terminator or at EOF. The terminator
* is removed from the buffer before returning. Returns 0 unless
* there was nothing left before EOF, in which case it returns `EOF`.
As sb/submodule-parallel-update and sb/submodule-helper-clone-regression-fix
both touch builtin/submodule--helper.c, so we need those.
We need origin/sb/submodule-path-misc-bugs as it tests `submodule add`
output.
Thanks,
Stefan
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 322 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 127 +----------------
submodule.c | 21 +++
submodule.h | 1 +
t/t0060-path-utils.sh | 43 ++++++
5 files changed, 392 insertions(+), 122 deletions(-)
--
2.8.0.26.g0341e85
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-04-14 18:18 [PATCH 0/2] Port `submodule init` " Stefan Beller
@ 2016-04-14 18:18 ` Stefan Beller
2016-04-14 19:35 ` Johannes Sixt
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-04-14 18:18 UTC (permalink / raw)
To: git; +Cc: gitster, pclouds, j6t, Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 209 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 43 +++++++++
3 files changed, 255 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 864dd18..46946b0 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,211 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+
+ if (!refname)
+ die(_("No such ref: %s"), "HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = dest;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = find_last_dir_sep(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome expectation
+ * http://a.com/b ../c http://a.com/c as is
+ * http://a.com/b ../../c http://c error out
+ * http://a.com/b ../../../c http:/c error out
+ * http://a.com/b ../../../../c http:c error out
+ * http://a.com/b ../../../../../c .:c error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+ free(remoteurl);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -504,7 +709,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 07290d0..2423d7c 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" ||
@@ -1202,9 +1129,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 8532a02..2e62548 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -298,4 +305,40 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
+test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
+test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
+test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
+test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.8.0.26.g0341e85
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-04-14 18:18 ` [PATCH 1/2] submodule: port resolve_relative_url from shell " Stefan Beller
@ 2016-04-14 19:35 ` Johannes Sixt
2016-04-14 19:37 ` Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Johannes Sixt @ 2016-04-14 19:35 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, gitster, pclouds
Am 14.04.2016 um 20:18 schrieb Stefan Beller:
> @@ -298,4 +305,40 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
> test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
> test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
>
> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
> +test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
> +test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
> +test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
> +test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
> +
> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
> +test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
> +test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
> +test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
> +test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
> +test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
> +test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
> +test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
> +test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
> +test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
> +test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
> +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
> +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
> +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
> +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
> +
> test_done
>
I am very sorry that I am chiming in again so late. I forgot to mention
that this requires a fixup on Windows as below. I won't mind to submit
the fixup as a follow-on patch, but you could also squash it in if yet
another round is required.
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 579c1fa..1d19fbb 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -293,13 +293,16 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+# In the tests below, the distinction between $PWD and $(pwd) is important:
+# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).
+
test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
-test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$(pwd)/repo"
test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
@@ -310,16 +313,16 @@ test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
-test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
-test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
-test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
-test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
-test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
-test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
-test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
-test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
-test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
-test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
+test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$(pwd)/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$(pwd)/subsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/." "../." "$(pwd)/."
+test_submodule_relative_url "(null)" "$PWD" "./." "$(pwd)/."
+test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"
+test_submodule_relative_url "(null)" "$PWD" "./å äö" "$(pwd)/å äö"
+test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$(pwd)/submodule"
+test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$(pwd)/submodule"
+test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$(pwd)/home2/../bundle1"
+test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$(pwd)/submodule_update_repo/."
test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
--
2.7.0.118.g90056ae
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-04-14 19:35 ` Johannes Sixt
@ 2016-04-14 19:37 ` Stefan Beller
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-04-14 19:37 UTC (permalink / raw)
To: Johannes Sixt; +Cc: git@vger.kernel.org, Junio C Hamano, Duy Nguyen
On Thu, Apr 14, 2016 at 12:35 PM, Johannes Sixt <j6t@kdbg.org> wrote:
> Am 14.04.2016 um 20:18 schrieb Stefan Beller:
>> @@ -298,4 +305,40 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
>> test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
>> test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
>>
>> +test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
>> +test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
>> +test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
>> +test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
>> +test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
>> +test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
>> +
>> +test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
>> +test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
>> +test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
>> +test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
>> +test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
>> +test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
>> +test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
>> +test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
>> +test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
>> +test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
>> +test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
>> +test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
>> +test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
>> +test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
>> +test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
>> +test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
>> +test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
>> +test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
>> +test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
>> +test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
>> +test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
>> +test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
>> +test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
>> +test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
>> +
>> test_done
>>
>
> I am very sorry that I am chiming in again so late. I forgot to mention
> that this requires a fixup on Windows as below. I won't mind to submit
> the fixup as a follow-on patch, but you could also squash it in if yet
> another round is required.
Thanks a lot for testing a patch on Windows!
I'll pick this up in a resend.
>
> diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
> index 579c1fa..1d19fbb 100755
> --- a/t/t0060-path-utils.sh
> +++ b/t/t0060-path-utils.sh
> @@ -293,13 +293,16 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
> test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
> test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
>
> +# In the tests below, the distinction between $PWD and $(pwd) is important:
> +# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).
> +
> test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
> test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
> test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
> test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
> test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
> test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
> -test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
> +test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$(pwd)/repo"
> test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
> test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
>
> @@ -310,16 +313,16 @@ test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
> test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
> test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
> test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
> -test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
> -test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
> -test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
> -test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
> -test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
> -test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
> -test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
> -test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
> -test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
> -test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
> +test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$(pwd)/subsubsuper_update_r"
> +test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$(pwd)/subsuper_update_r"
> +test_submodule_relative_url "(null)" "$PWD/." "../." "$(pwd)/."
> +test_submodule_relative_url "(null)" "$PWD" "./." "$(pwd)/."
> +test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"
> +test_submodule_relative_url "(null)" "$PWD" "./å äö" "$(pwd)/å äö"
> +test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$(pwd)/submodule"
> +test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$(pwd)/submodule"
> +test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$(pwd)/home2/../bundle1"
> +test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$(pwd)/submodule_update_repo/."
> test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
> test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
> test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
> --
> 2.7.0.118.g90056ae
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 0/2] Another reroll of sb/submodule-init
@ 2016-04-16 0:50 Stefan Beller
2016-04-16 0:50 ` [PATCH 1/2] submodule: port resolve_relative_url from shell to C Stefan Beller
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Beller @ 2016-04-16 0:50 UTC (permalink / raw)
To: git; +Cc: gitster, pclouds, j6t, Stefan Beller
* squashed the fixes from Johannes Sixt to unbreak Windows tests.
(I had encoding issues; so I manually integrated the changes)
* fixed memleaks
* the base to apply did not change (ee30f17805f51d37 Merge branch
'sb/submodule-path-misc-bugs' into sb/submodule-init)
Thanks,
Stefan
diff to current origin/sb/submodule-init:
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index ad3cba6..b6d4f27 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -309,8 +309,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
{
const struct submodule *sub;
struct strbuf sb = STRBUF_INIT;
- const char *upd = NULL;
- char *url = NULL, *displaypath;
+ char *upd = NULL, *url = NULL, *displaypath;
/* Only loads from .gitmodules, no overlay with .git/config */
gitmodules_config();
@@ -340,7 +339,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
/* Possibly a url relative to parent */
if (starts_with_dot_dot_slash(url) ||
starts_with_dot_slash(url)) {
- char *remoteurl;
+ char *remoteurl, *relurl;
char *remote = get_default_remote();
struct strbuf remotesb = STRBUF_INIT;
strbuf_addf(&remotesb, "remote.%s.url", remote);
@@ -352,9 +351,11 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
* authoritative upstream
*/
remoteurl = xgetcwd();
- url = relative_url(remoteurl, url, NULL);
+ relurl = relative_url(remoteurl, url, NULL);
strbuf_release(&remotesb);
free(remoteurl);
+ free(url);
+ url = relurl;
}
if (git_config_set_gently(sb.buf, url))
@@ -368,14 +369,14 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
/* Copy "update" setting when it is not set yet */
strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.update", sub->name);
- if (git_config_get_string_const(sb.buf, &upd) &&
+ if (git_config_get_string(sb.buf, &upd) &&
sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
fprintf(stderr, _("warning: command update mode suggested for submodule '%s'\n"),
sub->name);
- upd = "none";
+ upd = xstrdup("none");
} else
- upd = submodule_strategy_to_string(&sub->update_strategy);
+ upd = xstrdup(submodule_strategy_to_string(&sub->update_strategy));
if (git_config_set_gently(sb.buf, upd))
die(_("Failed to register update mode for submodule path '%s'"), displaypath);
@@ -383,6 +384,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
strbuf_release(&sb);
free(displaypath);
free(url);
+ free(upd);
}
static int module_init(int argc, const char **argv, const char *prefix)
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 2e62548..bf2deee 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -305,13 +305,16 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+# In the tests below, the distinction between $PWD and $(pwd) is important:
+# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).
+
test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
-test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$PWD/repo"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$(pwd)/repo"
test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
@@ -322,16 +325,16 @@ test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
-test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$PWD/subsubsuper_update_r"
-test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$PWD/subsuper_update_r"
-test_submodule_relative_url "(null)" "$PWD/." "../." "$PWD/."
-test_submodule_relative_url "(null)" "$PWD" "./." "$PWD/."
-test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$PWD/repo"
-test_submodule_relative_url "(null)" "$PWD" "./å äö" "$PWD/å äö"
-test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$PWD/submodule"
-test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$PWD/submodule"
-test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$PWD/home2/../bundle1"
-test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$PWD/submodule_update_repo/."
+test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$(pwd)/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$(pwd)/subsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/." "../." "$(pwd)/."
+test_submodule_relative_url "(null)" "$PWD" "./." "$(pwd)/."
+test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"
+test_submodule_relative_url "(null)" "$PWD" "./å äö" "$(pwd)/å äö"
+test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$(pwd)/submodule"
+test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$(pwd)/submodule"
+test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$(pwd)/home2/../bundle1"
+test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$(pwd)/submodule_update_repo/."
test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
Stefan Beller (2):
submodule: port resolve_relative_url from shell to C
submodule: port init from shell to C
builtin/submodule--helper.c | 324 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 127 +----------------
submodule.c | 21 +++
submodule.h | 1 +
t/t0060-path-utils.sh | 46 +++++++
5 files changed, 397 insertions(+), 122 deletions(-)
--
2.8.0.26.gba39a1b.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 1/2] submodule: port resolve_relative_url from shell to C
2016-04-16 0:50 [PATCH 0/2] Another reroll of sb/submodule-init Stefan Beller
@ 2016-04-16 0:50 ` Stefan Beller
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Beller @ 2016-04-16 0:50 UTC (permalink / raw)
To: git; +Cc: gitster, pclouds, j6t, Stefan Beller
Later on we want to automatically call `git submodule init` from
other commands, such that the users don't have to initialize the
submodule themselves. As these other commands are written in C
already, we'd need the init functionality in C, too. The
`resolve_relative_url` function is a large part of that init
functionality, so start by porting this function to C.
To create the tests in t0060, the function `resolve_relative_url`
was temporarily enhanced to write all inputs and output to disk
when running the test suite. The added tests in this patch are
a small selection thereof.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/submodule--helper.c | 209 +++++++++++++++++++++++++++++++++++++++++++-
git-submodule.sh | 81 +----------------
t/t0060-path-utils.sh | 46 ++++++++++
3 files changed, 258 insertions(+), 78 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 864dd18..46946b0 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -9,6 +9,211 @@
#include "submodule-config.h"
#include "string-list.h"
#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "connect.h"
+
+static char *get_default_remote(void)
+{
+ char *dest = NULL, *ret;
+ unsigned char sha1[20];
+ struct strbuf sb = STRBUF_INIT;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+
+ if (!refname)
+ die(_("No such ref: %s"), "HEAD");
+
+ /* detached HEAD */
+ if (!strcmp(refname, "HEAD"))
+ return xstrdup("origin");
+
+ if (!skip_prefix(refname, "refs/heads/", &refname))
+ die(_("Expecting a full ref name, got %s"), refname);
+
+ strbuf_addf(&sb, "branch.%s.remote", refname);
+ if (git_config_get_string(sb.buf, &dest))
+ ret = xstrdup("origin");
+ else
+ ret = dest;
+
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int starts_with_dot_slash(const char *str)
+{
+ return str[0] == '.' && is_dir_sep(str[1]);
+}
+
+static int starts_with_dot_dot_slash(const char *str)
+{
+ return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
+}
+
+/*
+ * Returns 1 if it was the last chop before ':'.
+ */
+static int chop_last_dir(char **remoteurl, int is_relative)
+{
+ char *rfind = find_last_dir_sep(*remoteurl);
+ if (rfind) {
+ *rfind = '\0';
+ return 0;
+ }
+
+ rfind = strrchr(*remoteurl, ':');
+ if (rfind) {
+ *rfind = '\0';
+ return 1;
+ }
+
+ if (is_relative || !strcmp(".", *remoteurl))
+ die(_("cannot strip one component off url '%s'"),
+ *remoteurl);
+
+ free(*remoteurl);
+ *remoteurl = xstrdup(".");
+ return 0;
+}
+
+/*
+ * The `url` argument is the URL that navigates to the submodule origin
+ * repo. When relative, this URL is relative to the superproject origin
+ * URL repo. The `up_path` argument, if specified, is the relative
+ * path that navigates from the submodule working tree to the superproject
+ * working tree. Returns the origin URL of the submodule.
+ *
+ * Return either 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.
+ *
+ * NEEDSWORK: This works incorrectly on the domain and protocol part.
+ * remote_url url outcome expectation
+ * http://a.com/b ../c http://a.com/c as is
+ * http://a.com/b ../../c http://c error out
+ * http://a.com/b ../../../c http:/c error out
+ * http://a.com/b ../../../../c http:c error out
+ * http://a.com/b ../../../../../c .:c error out
+ * NEEDSWORK: Given how chop_last_dir() works, this function is broken
+ * when a local part has a colon in its path component, too.
+ */
+static char *relative_url(const char *remote_url,
+ const char *url,
+ const char *up_path)
+{
+ int is_relative = 0;
+ int colonsep = 0;
+ char *out;
+ char *remoteurl = xstrdup(remote_url);
+ struct strbuf sb = STRBUF_INIT;
+ size_t len = strlen(remoteurl);
+
+ if (is_dir_sep(remoteurl[len]))
+ remoteurl[len] = '\0';
+
+ if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
+ is_relative = 0;
+ else {
+ is_relative = 1;
+ /*
+ * Prepend a './' to ensure all relative
+ * remoteurls start with './' or '../'
+ */
+ if (!starts_with_dot_slash(remoteurl) &&
+ !starts_with_dot_dot_slash(remoteurl)) {
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "./%s", remoteurl);
+ free(remoteurl);
+ remoteurl = strbuf_detach(&sb, NULL);
+ }
+ }
+ /*
+ * When the url starts with '../', remove that and the
+ * last directory in remoteurl.
+ */
+ while (url) {
+ if (starts_with_dot_dot_slash(url)) {
+ url += 3;
+ colonsep |= chop_last_dir(&remoteurl, is_relative);
+ } else if (starts_with_dot_slash(url))
+ url += 2;
+ else
+ break;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
+ free(remoteurl);
+
+ if (starts_with_dot_slash(sb.buf))
+ out = xstrdup(sb.buf + 2);
+ else
+ out = xstrdup(sb.buf);
+ strbuf_reset(&sb);
+
+ if (!up_path || !is_relative)
+ return out;
+
+ strbuf_addf(&sb, "%s%s", up_path, out);
+ free(out);
+ return strbuf_detach(&sb, NULL);
+}
+
+static int resolve_relative_url(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl = NULL;
+ char *remote = get_default_remote();
+ const char *up_path = NULL;
+ char *res;
+ const char *url;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (argc != 2 && argc != 3)
+ die("resolve-relative-url only accepts one or two arguments");
+
+ url = argv[1];
+ strbuf_addf(&sb, "remote.%s.url", remote);
+ free(remote);
+
+ if (git_config_get_string(sb.buf, &remoteurl))
+ /* the repository is its own authoritative upstream */
+ remoteurl = xgetcwd();
+
+ if (argc == 3)
+ up_path = argv[2];
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
+
+static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
+{
+ char *remoteurl, *res;
+ const char *up_path, *url;
+
+ if (argc != 4)
+ die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");
+
+ up_path = argv[1];
+ remoteurl = xstrdup(argv[2]);
+ url = argv[3];
+
+ if (!strcmp(up_path, "(null)"))
+ up_path = NULL;
+
+ res = relative_url(remoteurl, url, up_path);
+ puts(res);
+ free(res);
+ free(remoteurl);
+ return 0;
+}
struct module_list {
const struct cache_entry **entries;
@@ -504,7 +709,9 @@ static struct cmd_struct commands[] = {
{"list", module_list},
{"name", module_name},
{"clone", module_clone},
- {"update-clone", update_clone}
+ {"update-clone", update_clone},
+ {"resolve-relative-url", resolve_relative_url},
+ {"resolve-relative-url-test", resolve_relative_url_test},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/git-submodule.sh b/git-submodule.sh
index 07290d0..2423d7c 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" ||
@@ -1202,9 +1129,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"
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 8532a02..bf2deee 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -19,6 +19,13 @@ relative_path() {
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
+test_submodule_relative_url() {
+ test_expect_success "test_submodule_relative_url: $1 $2 $3 => $4" "
+ actual=\$(git submodule--helper resolve-relative-url-test '$1' '$2' '$3') &&
+ test \"\$actual\" = '$4'
+ "
+}
+
test_git_path() {
test_expect_success "git-path $1 $2 => $3" "
$1 git rev-parse --git-path $2 >actual &&
@@ -298,4 +305,43 @@ test_git_path GIT_COMMON_DIR=bar config bar/config
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
+# In the tests below, the distinction between $PWD and $(pwd) is important:
+# on Windows, $PWD is POSIX style (/c/foo), $(pwd) has drive letter (c:/foo).
+
+test_submodule_relative_url "../" "../foo" "../submodule" "../../submodule"
+test_submodule_relative_url "../" "../foo/bar" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "../foo/submodule" "../submodule" "../../foo/submodule"
+test_submodule_relative_url "../" "./foo" "../submodule" "../submodule"
+test_submodule_relative_url "../" "./foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../../../" "../foo/bar" "../sub/a/b/c" "../../../../foo/sub/a/b/c"
+test_submodule_relative_url "../" "$PWD/addtest" "../repo" "$(pwd)/repo"
+test_submodule_relative_url "../" "foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "../" "foo" "../submodule" "../submodule"
+
+test_submodule_relative_url "(null)" "../foo/bar" "../sub/a/b/c" "../foo/sub/a/b/c"
+test_submodule_relative_url "(null)" "../foo/bar" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo/submodule" "../submodule" "../foo/submodule"
+test_submodule_relative_url "(null)" "../foo" "../submodule" "../submodule"
+test_submodule_relative_url "(null)" "./foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "./foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "//somewhere else/repo" "../subrepo" "//somewhere else/subrepo"
+test_submodule_relative_url "(null)" "$PWD/subsuper_update_r" "../subsubsuper_update_r" "$(pwd)/subsubsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/super_update_r2" "../subsuper_update_r" "$(pwd)/subsuper_update_r"
+test_submodule_relative_url "(null)" "$PWD/." "../." "$(pwd)/."
+test_submodule_relative_url "(null)" "$PWD" "./." "$(pwd)/."
+test_submodule_relative_url "(null)" "$PWD/addtest" "../repo" "$(pwd)/repo"
+test_submodule_relative_url "(null)" "$PWD" "./å äö" "$(pwd)/å äö"
+test_submodule_relative_url "(null)" "$PWD/." "../submodule" "$(pwd)/submodule"
+test_submodule_relative_url "(null)" "$PWD/submodule" "../submodule" "$(pwd)/submodule"
+test_submodule_relative_url "(null)" "$PWD/home2/../remote" "../bundle1" "$(pwd)/home2/../bundle1"
+test_submodule_relative_url "(null)" "$PWD/submodule_update_repo" "./." "$(pwd)/submodule_update_repo/."
+test_submodule_relative_url "(null)" "file:///tmp/repo" "../subrepo" "file:///tmp/subrepo"
+test_submodule_relative_url "(null)" "foo/bar" "../submodule" "foo/submodule"
+test_submodule_relative_url "(null)" "foo" "../submodule" "submodule"
+test_submodule_relative_url "(null)" "helper:://hostname/repo" "../subrepo" "helper:://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname/repo" "../subrepo" "ssh://hostname/subrepo"
+test_submodule_relative_url "(null)" "ssh://hostname:22/repo" "../subrepo" "ssh://hostname:22/subrepo"
+test_submodule_relative_url "(null)" "user@host:path/to/repo" "../subrepo" "user@host:path/to/subrepo"
+test_submodule_relative_url "(null)" "user@host:repo" "../subrepo" "user@host:subrepo"
+
test_done
--
2.8.0.26.gba39a1b.dirty
^ permalink raw reply related [flat|nested] 37+ messages in thread
end of thread, other threads:[~2016-04-16 0:50 UTC | newest]
Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-15 23:37 [PATCH 0/2] Port `git submodule init` from shell to C Stefan Beller
2016-01-15 23:37 ` [PATCH 1/2] submodule: Port resolve_relative_url " Stefan Beller
2016-01-15 23:37 ` [PATCH 2/2] submodule: Port init " Stefan Beller
2016-01-19 23:17 ` [PATCH 0/2] Port `git submodule init` " Junio C Hamano
2016-01-20 2:03 ` [PATCHv2 " Stefan Beller
2016-01-20 2:03 ` [PATCHv2 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-01-22 19:03 ` Johannes Sixt
2016-01-22 20:23 ` Stefan Beller
2016-01-20 2:03 ` [PATCHv2 2/2] submodule: port init " Stefan Beller
2016-01-20 3:24 ` [PATCHv3 " Stefan Beller
2016-01-20 21:01 ` Junio C Hamano
2016-01-20 22:33 ` Stefan Beller
2016-01-20 23:04 ` Junio C Hamano
2016-01-21 23:18 ` [PATCHv4 " Stefan Beller
2016-01-22 22:30 ` Junio C Hamano
2016-01-22 22:32 ` Stefan Beller
2016-01-22 23:32 ` [PATCHv3 0/2] Port `git submodule init` " Stefan Beller
2016-01-25 22:46 ` Junio C Hamano
2016-01-28 2:30 ` [PATCHv4 " Stefan Beller
2016-01-28 2:30 ` [PATCHv4 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-01-28 22:03 ` Junio C Hamano
2016-01-28 22:11 ` Stefan Beller
2016-01-28 2:30 ` [PATCHv4 2/2] submodule: port init " Stefan Beller
2016-02-27 8:30 ` Duy Nguyen
2016-01-22 23:32 ` [PATCHv3 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-01-22 23:32 ` [PATCHv3 2/2] submodule: port init " Stefan Beller
-- strict thread matches above, loose matches on Subject: below --
2016-02-12 23:39 [PATCH 0/2] Port `git submodule init` " Stefan Beller
2016-02-12 23:39 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-02-18 20:23 ` Junio C Hamano
2016-02-27 8:28 ` Duy Nguyen
2016-03-02 17:21 ` Johannes Sixt
2016-03-02 17:34 ` Stefan Beller
2016-03-15 0:15 [PATCH 0/2] Port `git submodule init` " Stefan Beller
2016-03-15 0:15 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-04-13 0:18 [PATCH 0/2] Port `git submodule init` " Stefan Beller
2016-04-13 0:18 ` [PATCH 1/2] submodule: port resolve_relative_url " Stefan Beller
2016-04-14 18:18 [PATCH 0/2] Port `submodule init` " Stefan Beller
2016-04-14 18:18 ` [PATCH 1/2] submodule: port resolve_relative_url from shell " Stefan Beller
2016-04-14 19:35 ` Johannes Sixt
2016-04-14 19:37 ` Stefan Beller
2016-04-16 0:50 [PATCH 0/2] Another reroll of sb/submodule-init Stefan Beller
2016-04-16 0:50 ` [PATCH 1/2] submodule: port resolve_relative_url from shell to C Stefan Beller
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 NNTP newsgroup(s).