]> git.ipfire.org Git - thirdparty/git.git/blobdiff - remote.c
Merge branch 'ds/bundle-uri'
[thirdparty/git.git] / remote.c
index 930fdc9c2f606ab60cc9b9209230f7d9ce5f5556..e98148ac227310247aa6de0fd1f251b4b028f381 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -14,6 +14,7 @@
 #include "strvec.h"
 #include "commit-reach.h"
 #include "advice.h"
+#include "connect.h"
 
 enum map_direction { FROM_SRC, FROM_DST };
 
@@ -2729,3 +2730,101 @@ 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;
+       struct strbuf sb = STRBUF_INIT;
+       size_t len;
+
+       if (!url_is_local_not_ssh(url) || is_absolute_path(url))
+               return xstrdup(url);
+
+       len = strlen(remote_url);
+       if (!len)
+               BUG("invalid empty remote_url");
+
+       remoteurl = xstrdup(remote_url);
+       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);
+}