Skip to content

Commit 1d04e71

Browse files
derrickstoleegitster
authored andcommitted
remote: move relative_url()
This method was initially written in 63e95be (submodule: port resolve_relative_url from shell to C, 2016-05-15). As we will need similar functionality in the bundle URI feature, extract this to be available in remote.h. The code is almost exactly the same, except for the following trivial differences: * Fix whitespace and wrapping issues with the prototype and argument lists. * Let's call starts_with_dot_{,dot_}slash_native() instead of the functionally identical "starts_with_dot_{,dot_}slash()" wrappers "builtin/submodule--helper.c". Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c1d024b commit 1d04e71

File tree

3 files changed

+134
-129
lines changed

3 files changed

+134
-129
lines changed

builtin/submodule--helper.c

Lines changed: 12 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -72,135 +72,6 @@ static char *get_default_remote(void)
7272
return repo_get_default_remote(the_repository);
7373
}
7474

75-
/*
76-
* Returns 1 if it was the last chop before ':'.
77-
*/
78-
static int chop_last_dir(char **remoteurl, int is_relative)
79-
{
80-
char *rfind = find_last_dir_sep(*remoteurl);
81-
if (rfind) {
82-
*rfind = '\0';
83-
return 0;
84-
}
85-
86-
rfind = strrchr(*remoteurl, ':');
87-
if (rfind) {
88-
*rfind = '\0';
89-
return 1;
90-
}
91-
92-
if (is_relative || !strcmp(".", *remoteurl))
93-
die(_("cannot strip one component off url '%s'"),
94-
*remoteurl);
95-
96-
free(*remoteurl);
97-
*remoteurl = xstrdup(".");
98-
return 0;
99-
}
100-
101-
static int starts_with_dot_slash(const char *const path)
102-
{
103-
return starts_with_dot_slash_native(path);;
104-
}
105-
106-
static int starts_with_dot_dot_slash(const char *const path)
107-
{
108-
return starts_with_dot_dot_slash_native(path);
109-
}
110-
111-
/*
112-
* The `url` argument is the URL that navigates to the submodule origin
113-
* repo. When relative, this URL is relative to the superproject origin
114-
* URL repo. The `up_path` argument, if specified, is the relative
115-
* path that navigates from the submodule working tree to the superproject
116-
* working tree. Returns the origin URL of the submodule.
117-
*
118-
* Return either an absolute URL or filesystem path (if the superproject
119-
* origin URL is an absolute URL or filesystem path, respectively) or a
120-
* relative file system path (if the superproject origin URL is a relative
121-
* file system path).
122-
*
123-
* When the output is a relative file system path, the path is either
124-
* relative to the submodule working tree, if up_path is specified, or to
125-
* the superproject working tree otherwise.
126-
*
127-
* NEEDSWORK: This works incorrectly on the domain and protocol part.
128-
* remote_url url outcome expectation
129-
* http://a.com/b ../c http://a.com/c as is
130-
* http://a.com/b/ ../c http://a.com/c same as previous line, but
131-
* ignore trailing slash in url
132-
* http://a.com/b ../../c http://c error out
133-
* http://a.com/b ../../../c http:/c error out
134-
* http://a.com/b ../../../../c http:c error out
135-
* http://a.com/b ../../../../../c .:c error out
136-
* NEEDSWORK: Given how chop_last_dir() works, this function is broken
137-
* when a local part has a colon in its path component, too.
138-
*/
139-
static char *relative_url(const char *remote_url,
140-
const char *url,
141-
const char *up_path)
142-
{
143-
int is_relative = 0;
144-
int colonsep = 0;
145-
char *out;
146-
char *remoteurl = xstrdup(remote_url);
147-
struct strbuf sb = STRBUF_INIT;
148-
size_t len = strlen(remoteurl);
149-
150-
if (is_dir_sep(remoteurl[len-1]))
151-
remoteurl[len-1] = '\0';
152-
153-
if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
154-
is_relative = 0;
155-
else {
156-
is_relative = 1;
157-
/*
158-
* Prepend a './' to ensure all relative
159-
* remoteurls start with './' or '../'
160-
*/
161-
if (!starts_with_dot_slash(remoteurl) &&
162-
!starts_with_dot_dot_slash(remoteurl)) {
163-
strbuf_reset(&sb);
164-
strbuf_addf(&sb, "./%s", remoteurl);
165-
free(remoteurl);
166-
remoteurl = strbuf_detach(&sb, NULL);
167-
}
168-
}
169-
/*
170-
* When the url starts with '../', remove that and the
171-
* last directory in remoteurl.
172-
*/
173-
while (url) {
174-
if (starts_with_dot_dot_slash(url)) {
175-
url += 3;
176-
colonsep |= chop_last_dir(&remoteurl, is_relative);
177-
} else if (starts_with_dot_slash(url))
178-
url += 2;
179-
else
180-
break;
181-
}
182-
strbuf_reset(&sb);
183-
strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
184-
if (ends_with(url, "/"))
185-
strbuf_setlen(&sb, sb.len - 1);
186-
free(remoteurl);
187-
188-
if (starts_with_dot_slash(sb.buf))
189-
out = xstrdup(sb.buf + 2);
190-
else
191-
out = xstrdup(sb.buf);
192-
193-
if (!up_path || !is_relative) {
194-
strbuf_release(&sb);
195-
return out;
196-
}
197-
198-
strbuf_reset(&sb);
199-
strbuf_addf(&sb, "%s%s", up_path, out);
200-
free(out);
201-
return strbuf_detach(&sb, NULL);
202-
}
203-
20475
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
20576
{
20677
char *remoteurl, *resolved_url;
@@ -592,6 +463,18 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
592463
return 0;
593464
}
594465

466+
static int starts_with_dot_slash(const char *const path)
467+
{
468+
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
469+
PATH_MATCH_XPLATFORM);
470+
}
471+
472+
static int starts_with_dot_dot_slash(const char *const path)
473+
{
474+
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
475+
PATH_MATCH_XPLATFORM);
476+
}
477+
595478
struct init_cb {
596479
const char *prefix;
597480
const char *superprefix;

remote.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "strvec.h"
1515
#include "commit-reach.h"
1616
#include "advice.h"
17+
#include "connect.h"
1718

1819
enum map_direction { FROM_SRC, FROM_DST };
1920

@@ -2727,3 +2728,93 @@ void remote_state_clear(struct remote_state *remote_state)
27272728
hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
27282729
hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
27292730
}
2731+
2732+
/*
2733+
* Returns 1 if it was the last chop before ':'.
2734+
*/
2735+
static int chop_last_dir(char **remoteurl, int is_relative)
2736+
{
2737+
char *rfind = find_last_dir_sep(*remoteurl);
2738+
if (rfind) {
2739+
*rfind = '\0';
2740+
return 0;
2741+
}
2742+
2743+
rfind = strrchr(*remoteurl, ':');
2744+
if (rfind) {
2745+
*rfind = '\0';
2746+
return 1;
2747+
}
2748+
2749+
if (is_relative || !strcmp(".", *remoteurl))
2750+
die(_("cannot strip one component off url '%s'"),
2751+
*remoteurl);
2752+
2753+
free(*remoteurl);
2754+
*remoteurl = xstrdup(".");
2755+
return 0;
2756+
}
2757+
2758+
char *relative_url(const char *remote_url, const char *url,
2759+
const char *up_path)
2760+
{
2761+
int is_relative = 0;
2762+
int colonsep = 0;
2763+
char *out;
2764+
char *remoteurl = xstrdup(remote_url);
2765+
struct strbuf sb = STRBUF_INIT;
2766+
size_t len = strlen(remoteurl);
2767+
2768+
if (is_dir_sep(remoteurl[len-1]))
2769+
remoteurl[len-1] = '\0';
2770+
2771+
if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
2772+
is_relative = 0;
2773+
else {
2774+
is_relative = 1;
2775+
/*
2776+
* Prepend a './' to ensure all relative
2777+
* remoteurls start with './' or '../'
2778+
*/
2779+
if (!starts_with_dot_slash_native(remoteurl) &&
2780+
!starts_with_dot_dot_slash_native(remoteurl)) {
2781+
strbuf_reset(&sb);
2782+
strbuf_addf(&sb, "./%s", remoteurl);
2783+
free(remoteurl);
2784+
remoteurl = strbuf_detach(&sb, NULL);
2785+
}
2786+
}
2787+
/*
2788+
* When the url starts with '../', remove that and the
2789+
* last directory in remoteurl.
2790+
*/
2791+
while (url) {
2792+
if (starts_with_dot_dot_slash_native(url)) {
2793+
url += 3;
2794+
colonsep |= chop_last_dir(&remoteurl, is_relative);
2795+
} else if (starts_with_dot_slash_native(url))
2796+
url += 2;
2797+
else
2798+
break;
2799+
}
2800+
strbuf_reset(&sb);
2801+
strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
2802+
if (ends_with(url, "/"))
2803+
strbuf_setlen(&sb, sb.len - 1);
2804+
free(remoteurl);
2805+
2806+
if (starts_with_dot_slash_native(sb.buf))
2807+
out = xstrdup(sb.buf + 2);
2808+
else
2809+
out = xstrdup(sb.buf);
2810+
2811+
if (!up_path || !is_relative) {
2812+
strbuf_release(&sb);
2813+
return out;
2814+
}
2815+
2816+
strbuf_reset(&sb);
2817+
strbuf_addf(&sb, "%s%s", up_path, out);
2818+
free(out);
2819+
return strbuf_detach(&sb, NULL);
2820+
}

remote.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,35 @@ int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
409409
int is_empty_cas(const struct push_cas_option *);
410410
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
411411

412+
/*
413+
* The `url` argument is the URL that navigates to the submodule origin
414+
* repo. When relative, this URL is relative to the superproject origin
415+
* URL repo. The `up_path` argument, if specified, is the relative
416+
* path that navigates from the submodule working tree to the superproject
417+
* working tree. Returns the origin URL of the submodule.
418+
*
419+
* Return either an absolute URL or filesystem path (if the superproject
420+
* origin URL is an absolute URL or filesystem path, respectively) or a
421+
* relative file system path (if the superproject origin URL is a relative
422+
* file system path).
423+
*
424+
* When the output is a relative file system path, the path is either
425+
* relative to the submodule working tree, if up_path is specified, or to
426+
* the superproject working tree otherwise.
427+
*
428+
* NEEDSWORK: This works incorrectly on the domain and protocol part.
429+
* remote_url url outcome expectation
430+
* http://a.com/b ../c http://a.com/c as is
431+
* http://a.com/b/ ../c http://a.com/c same as previous line, but
432+
* ignore trailing slash in url
433+
* http://a.com/b ../../c http://c error out
434+
* http://a.com/b ../../../c http:/c error out
435+
* http://a.com/b ../../../../c http:c error out
436+
* http://a.com/b ../../../../../c .:c error out
437+
* NEEDSWORK: Given how chop_last_dir() works, this function is broken
438+
* when a local part has a colon in its path component, too.
439+
*/
440+
char *relative_url(const char *remote_url, const char *url,
441+
const char *up_path);
442+
412443
#endif

0 commit comments

Comments
 (0)