remote: move relative_url()
This method was initially written in 63e95beb0
(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 <avarab@gmail.com>
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
c1d024b843
commit
1d04e719e7
@ -72,135 +72,6 @@ static char *get_default_remote(void)
|
|||||||
return repo_get_default_remote(the_repository);
|
return repo_get_default_remote(the_repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int starts_with_dot_slash(const char *const path)
|
|
||||||
{
|
|
||||||
return starts_with_dot_slash_native(path);;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int starts_with_dot_dot_slash(const char *const path)
|
|
||||||
{
|
|
||||||
return starts_with_dot_dot_slash_native(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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://a.com/c same as previous line, but
|
|
||||||
* ignore trailing slash in url
|
|
||||||
* 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-1]))
|
|
||||||
remoteurl[len-1] = '\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 (ends_with(url, "/"))
|
|
||||||
strbuf_setlen(&sb, sb.len - 1);
|
|
||||||
free(remoteurl);
|
|
||||||
|
|
||||||
if (starts_with_dot_slash(sb.buf))
|
|
||||||
out = xstrdup(sb.buf + 2);
|
|
||||||
else
|
|
||||||
out = xstrdup(sb.buf);
|
|
||||||
|
|
||||||
if (!up_path || !is_relative) {
|
|
||||||
strbuf_release(&sb);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
strbuf_reset(&sb);
|
|
||||||
strbuf_addf(&sb, "%s%s", up_path, out);
|
|
||||||
free(out);
|
|
||||||
return strbuf_detach(&sb, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
|
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
|
||||||
{
|
{
|
||||||
char *remoteurl, *resolved_url;
|
char *remoteurl, *resolved_url;
|
||||||
@ -592,6 +463,18 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int starts_with_dot_slash(const char *const path)
|
||||||
|
{
|
||||||
|
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
|
||||||
|
PATH_MATCH_XPLATFORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int starts_with_dot_dot_slash(const char *const path)
|
||||||
|
{
|
||||||
|
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
|
||||||
|
PATH_MATCH_XPLATFORM);
|
||||||
|
}
|
||||||
|
|
||||||
struct init_cb {
|
struct init_cb {
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
const char *superprefix;
|
const char *superprefix;
|
||||||
|
91
remote.c
91
remote.c
@ -14,6 +14,7 @@
|
|||||||
#include "strvec.h"
|
#include "strvec.h"
|
||||||
#include "commit-reach.h"
|
#include "commit-reach.h"
|
||||||
#include "advice.h"
|
#include "advice.h"
|
||||||
|
#include "connect.h"
|
||||||
|
|
||||||
enum map_direction { FROM_SRC, FROM_DST };
|
enum map_direction { FROM_SRC, FROM_DST };
|
||||||
|
|
||||||
@ -2727,3 +2728,93 @@ void remote_state_clear(struct remote_state *remote_state)
|
|||||||
hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
|
hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
|
||||||
hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
|
hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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-1]))
|
||||||
|
remoteurl[len-1] = '\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_native(remoteurl) &&
|
||||||
|
!starts_with_dot_dot_slash_native(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_native(url)) {
|
||||||
|
url += 3;
|
||||||
|
colonsep |= chop_last_dir(&remoteurl, is_relative);
|
||||||
|
} else if (starts_with_dot_slash_native(url))
|
||||||
|
url += 2;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strbuf_reset(&sb);
|
||||||
|
strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
|
||||||
|
if (ends_with(url, "/"))
|
||||||
|
strbuf_setlen(&sb, sb.len - 1);
|
||||||
|
free(remoteurl);
|
||||||
|
|
||||||
|
if (starts_with_dot_slash_native(sb.buf))
|
||||||
|
out = xstrdup(sb.buf + 2);
|
||||||
|
else
|
||||||
|
out = xstrdup(sb.buf);
|
||||||
|
|
||||||
|
if (!up_path || !is_relative) {
|
||||||
|
strbuf_release(&sb);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_reset(&sb);
|
||||||
|
strbuf_addf(&sb, "%s%s", up_path, out);
|
||||||
|
free(out);
|
||||||
|
return strbuf_detach(&sb, NULL);
|
||||||
|
}
|
||||||
|
31
remote.h
31
remote.h
@ -409,4 +409,35 @@ int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
|
|||||||
int is_empty_cas(const struct push_cas_option *);
|
int is_empty_cas(const struct push_cas_option *);
|
||||||
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
|
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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://a.com/c same as previous line, but
|
||||||
|
* ignore trailing slash in url
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
char *relative_url(const char *remote_url, const char *url,
|
||||||
|
const char *up_path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user