Skip to content

Commit ed86301

Browse files
tfidfwastakengitster
authored andcommitted
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 <[email protected]> Mentored-by: Christian Couder <[email protected]> Mentored-by: Shourya Shukla <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0c61041 commit ed86301

File tree

3 files changed

+127
-116
lines changed

3 files changed

+127
-116
lines changed

builtin/clone.c

Lines changed: 2 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -217,120 +217,6 @@ static char *get_repo_path(const char *repo, int *is_bundle)
217217
return canon;
218218
}
219219

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-
334220
static int add_one_reference(struct string_list_item *item, void *cb_data)
335221
{
336222
struct strbuf err = STRBUF_INIT;
@@ -1041,8 +927,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1041927
if (argc == 2)
1042928
dir = xstrdup(argv[1]);
1043929
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);
1046932

1047933
dest_exists = path_exists(dir);
1048934
if (dest_exists && !is_empty_dir(dir))

dir.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2970,6 +2970,120 @@ int is_empty_dir(const char *path)
29702970
return ret;
29712971
}
29722972

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+
29733087
static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
29743088
{
29753089
DIR *dir;

dir.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,17 @@ static inline int is_dot_or_dotdot(const char *name)
453453

454454
int is_empty_dir(const char *dir);
455455

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+
456467
void setup_standard_excludes(struct dir_struct *dir);
457468

458469
char *get_sparse_checkout_filename(void);

0 commit comments

Comments
 (0)