diff options
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 91 |
1 files changed, 91 insertions, 0 deletions
@@ -14,6 +14,7 @@ #include "strvec.h" #include "commit-reach.h" #include "advice.h" +#include "connect.h" 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->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); +} |