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>
Derrick Stolee committed
May 16, 2022 at 20:11 UTC
1d04e719e7bda885991cd4566a5bb6f6565fa106
3 files changed
+134
-129
builtin/submodule--helper.c
+12
-129
@@ -72,135 +72,6 @@ static char *get_default_remote(void)
72
return repo_get_default_remote(the_repository);
73
}
74
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
-
75
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
76
{
77
char *remoteurl, *resolved_url;
@@ -592,6 +463,18 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
463
return 0;
464
}
465
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
+
478
struct init_cb {
479
const char *prefix;
480
const char *superprefix;
remote.c
+91
@@ -14,6 +14,7 @@
14
#include "strvec.h"
15
#include "commit-reach.h"
16
#include "advice.h"
17
+#include "connect.h"
18
19
enum map_direction { FROM_SRC, FROM_DST };
20
@@ -2727,3 +2728,93 @@ void remote_state_clear(struct remote_state *remote_state)
2728
hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
2729
hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
2730
}
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
+31
@@ -409,4 +409,35 @@ int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
409
int is_empty_cas(const struct push_cas_option *);
410
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
411
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
+
443
#endif