dir: libify and export helper functions from clone.c
These functions can be useful to other parts of Git. Let's move them to dir.c, while renaming them to be make their functionality more explicit. Signed-off-by: Atharva Raykar <raykar.ath@gmail.com> Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Shourya Shukla <periperidip@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Atharva Raykar committed
Aug 10, 2021 at 17:16 UTC
ed86301f68fcbb17c5d1c7a3258e4705b3b1da9c
3 files changed
+127
-116
builtin/clone.c
+2
-116
@@ -217,120 +217,6 @@ static char *get_repo_path(const char *repo, int *is_bundle)
217
return canon;
218
}
219
220
-static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
221
-{
222
- const char *end = repo + strlen(repo), *start, *ptr;
223
- size_t len;
224
- char *dir;
225
-
226
- /*
227
- * Skip scheme.
228
- */
229
- start = strstr(repo, "://");
230
- if (start == NULL)
231
- start = repo;
232
- else
233
- start += 3;
234
-
235
- /*
236
- * Skip authentication data. The stripping does happen
237
- * greedily, such that we strip up to the last '@' inside
238
- * the host part.
239
- */
240
- for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) {
241
- if (*ptr == '@')
242
- start = ptr + 1;
243
- }
244
-
245
- /*
246
- * Strip trailing spaces, slashes and /.git
247
- */
248
- while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
249
- end--;
250
- if (end - start > 5 && is_dir_sep(end[-5]) &&
251
- !strncmp(end - 4, ".git", 4)) {
252
- end -= 5;
253
- while (start < end && is_dir_sep(end[-1]))
254
- end--;
255
- }
256
-
257
- /*
258
- * Strip trailing port number if we've got only a
259
- * hostname (that is, there is no dir separator but a
260
- * colon). This check is required such that we do not
261
- * strip URI's like '/foo/bar:2222.git', which should
262
- * result in a dir '2222' being guessed due to backwards
263
- * compatibility.
264
- */
265
- if (memchr(start, '/', end - start) == NULL
266
- && memchr(start, ':', end - start) != NULL) {
267
- ptr = end;
268
- while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':')
269
- ptr--;
270
- if (start < ptr && ptr[-1] == ':')
271
- end = ptr - 1;
272
- }
273
-
274
- /*
275
- * Find last component. To remain backwards compatible we
276
- * also regard colons as path separators, such that
277
- * cloning a repository 'foo:bar.git' would result in a
278
- * directory 'bar' being guessed.
279
- */
280
- ptr = end;
281
- while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':')
282
- ptr--;
283
- start = ptr;
284
-
285
- /*
286
- * Strip .{bundle,git}.
287
- */
288
- len = end - start;
289
- strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git");
290
-
291
- if (!len || (len == 1 && *start == '/'))
292
- die(_("No directory name could be guessed.\n"
293
- "Please specify a directory on the command line"));
294
-
295
- if (is_bare)
296
- dir = xstrfmt("%.*s.git", (int)len, start);
297
- else
298
- dir = xstrndup(start, len);
299
- /*
300
- * Replace sequences of 'control' characters and whitespace
301
- * with one ascii space, remove leading and trailing spaces.
302
- */
303
- if (*dir) {
304
- char *out = dir;
305
- int prev_space = 1 /* strip leading whitespace */;
306
- for (end = dir; *end; ++end) {
307
- char ch = *end;
308
- if ((unsigned char)ch < '\x20')
309
- ch = '\x20';
310
- if (isspace(ch)) {
311
- if (prev_space)
312
- continue;
313
- prev_space = 1;
314
- } else
315
- prev_space = 0;
316
- *out++ = ch;
317
- }
318
- *out = '\0';
319
- if (out > dir && prev_space)
320
- out[-1] = '\0';
321
- }
322
- return dir;
323
-}
324
-
325
-static void strip_trailing_slashes(char *dir)
326
-{
327
- char *end = dir + strlen(dir);
328
-
329
- while (dir < end - 1 && is_dir_sep(end[-1]))
330
- end--;
331
- *end = '\0';
332
-}
333
-
220
static int add_one_reference(struct string_list_item *item, void *cb_data)
221
{
222
struct strbuf err = STRBUF_INIT;
@@ -1041,8 +927,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
927
if (argc == 2)
928
dir = xstrdup(argv[1]);
929
else
1044
- dir = guess_dir_name(repo_name, is_bundle, option_bare);
1045
- strip_trailing_slashes(dir);
930
+ dir = git_url_basename(repo_name, is_bundle, option_bare);
931
+ strip_dir_trailing_slashes(dir);
932
933
dest_exists = path_exists(dir);
934
if (dest_exists && !is_empty_dir(dir))
dir.c
+114
@@ -2970,6 +2970,120 @@ int is_empty_dir(const char *path)
2970
return ret;
2971
}
2972
2973
+char *git_url_basename(const char *repo, int is_bundle, int is_bare)
2974
+{
2975
+ const char *end = repo + strlen(repo), *start, *ptr;
2976
+ size_t len;
2977
+ char *dir;
2978
+
2979
+ /*
2980
+ * Skip scheme.
2981
+ */
2982
+ start = strstr(repo, "://");
2983
+ if (start == NULL)
2984
+ start = repo;
2985
+ else
2986
+ start += 3;
2987
+
2988
+ /*
2989
+ * Skip authentication data. The stripping does happen
2990
+ * greedily, such that we strip up to the last '@' inside
2991
+ * the host part.
2992
+ */
2993
+ for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) {
2994
+ if (*ptr == '@')
2995
+ start = ptr + 1;
2996
+ }
2997
+
2998
+ /*
2999
+ * Strip trailing spaces, slashes and /.git
3000
+ */
3001
+ while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
3002
+ end--;
3003
+ if (end - start > 5 && is_dir_sep(end[-5]) &&
3004
+ !strncmp(end - 4, ".git", 4)) {
3005
+ end -= 5;
3006
+ while (start < end && is_dir_sep(end[-1]))
3007
+ end--;
3008
+ }
3009
+
3010
+ /*
3011
+ * Strip trailing port number if we've got only a
3012
+ * hostname (that is, there is no dir separator but a
3013
+ * colon). This check is required such that we do not
3014
+ * strip URI's like '/foo/bar:2222.git', which should
3015
+ * result in a dir '2222' being guessed due to backwards
3016
+ * compatibility.
3017
+ */
3018
+ if (memchr(start, '/', end - start) == NULL
3019
+ && memchr(start, ':', end - start) != NULL) {
3020
+ ptr = end;
3021
+ while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':')
3022
+ ptr--;
3023
+ if (start < ptr && ptr[-1] == ':')
3024
+ end = ptr - 1;
3025
+ }
3026
+
3027
+ /*
3028
+ * Find last component. To remain backwards compatible we
3029
+ * also regard colons as path separators, such that
3030
+ * cloning a repository 'foo:bar.git' would result in a
3031
+ * directory 'bar' being guessed.
3032
+ */
3033
+ ptr = end;
3034
+ while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':')
3035
+ ptr--;
3036
+ start = ptr;
3037
+
3038
+ /*
3039
+ * Strip .{bundle,git}.
3040
+ */
3041
+ len = end - start;
3042
+ strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git");
3043
+
3044
+ if (!len || (len == 1 && *start == '/'))
3045
+ die(_("No directory name could be guessed.\n"
3046
+ "Please specify a directory on the command line"));
3047
+
3048
+ if (is_bare)
3049
+ dir = xstrfmt("%.*s.git", (int)len, start);
3050
+ else
3051
+ dir = xstrndup(start, len);
3052
+ /*
3053
+ * Replace sequences of 'control' characters and whitespace
3054
+ * with one ascii space, remove leading and trailing spaces.
3055
+ */
3056
+ if (*dir) {
3057
+ char *out = dir;
3058
+ int prev_space = 1 /* strip leading whitespace */;
3059
+ for (end = dir; *end; ++end) {
3060
+ char ch = *end;
3061
+ if ((unsigned char)ch < '\x20')
3062
+ ch = '\x20';
3063
+ if (isspace(ch)) {
3064
+ if (prev_space)
3065
+ continue;
3066
+ prev_space = 1;
3067
+ } else
3068
+ prev_space = 0;
3069
+ *out++ = ch;
3070
+ }
3071
+ *out = '\0';
3072
+ if (out > dir && prev_space)
3073
+ out[-1] = '\0';
3074
+ }
3075
+ return dir;
3076
+}
3077
+
3078
+void strip_dir_trailing_slashes(char *dir)
3079
+{
3080
+ char *end = dir + strlen(dir);
3081
+
3082
+ while (dir < end - 1 && is_dir_sep(end[-1]))
3083
+ end--;
3084
+ *end = '\0';
3085
+}
3086
+
3087
static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
3088
{
3089
DIR *dir;
dir.h
+11
@@ -453,6 +453,17 @@ static inline int is_dot_or_dotdot(const char *name)
453
454
int is_empty_dir(const char *dir);
455
456
+/*
457
+ * Retrieve the "humanish" basename of the given Git URL.
458
+ *
459
+ * For example:
460
+ * /path/to/repo.git => "repo"
461
+ * host.xz:foo/.git => "foo"
462
+ * http://example.com/user/bar.baz => "bar.baz"
463
+ */
464
+char *git_url_basename(const char *repo, int is_bundle, int is_bare);
465
+void strip_dir_trailing_slashes(char *dir);
466
+
467
void setup_standard_excludes(struct dir_struct *dir);
468
469
char *get_sparse_checkout_filename(void);