connect.c: refactor url parsing
Make the function is_local() in transport.c public, rename it into url_is_local_not_ssh() and use it in both transport.c and connect.c Use a protocol "local" for URLs for the local file system. One note about using file:// under Windows: The (absolute) path on Unix like system typically starts with "/". When the host is empty, it can be omitted, so that a shell scriptlet url=file://$pwd will give a URL like "file:///home/user/repo". Windows does not have the same concept of a root directory located in "/". When parsing the URL allow "file://C:/user/repo" (even if RFC1738 indicates that "file:///C:/user/repo" should be used). Signed-off-by: Torsten Bögershausen <tboegi@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
83b0587527
commit
c59ab2e52a
57
connect.c
57
connect.c
@ -232,14 +232,24 @@ int server_supports(const char *feature)
|
||||
|
||||
enum protocol {
|
||||
PROTO_LOCAL = 1,
|
||||
PROTO_FILE,
|
||||
PROTO_SSH,
|
||||
PROTO_GIT
|
||||
};
|
||||
|
||||
int url_is_local_not_ssh(const char *url)
|
||||
{
|
||||
const char *colon = strchr(url, ':');
|
||||
const char *slash = strchr(url, '/');
|
||||
return !colon || (slash && slash < colon) ||
|
||||
has_dos_drive_prefix(url);
|
||||
}
|
||||
|
||||
static const char *prot_name(enum protocol protocol)
|
||||
{
|
||||
switch (protocol) {
|
||||
case PROTO_LOCAL:
|
||||
case PROTO_FILE:
|
||||
return "file";
|
||||
case PROTO_SSH:
|
||||
return "ssh";
|
||||
@ -261,7 +271,7 @@ static enum protocol get_protocol(const char *name)
|
||||
if (!strcmp(name, "ssh+git"))
|
||||
return PROTO_SSH;
|
||||
if (!strcmp(name, "file"))
|
||||
return PROTO_LOCAL;
|
||||
return PROTO_FILE;
|
||||
die("I don't handle protocol '%s'", name);
|
||||
}
|
||||
|
||||
@ -564,9 +574,8 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
|
||||
char *url;
|
||||
char *host, *path;
|
||||
char *end;
|
||||
int separator;
|
||||
int separator = '/';
|
||||
enum protocol protocol = PROTO_LOCAL;
|
||||
int free_path = 0;
|
||||
|
||||
if (is_url(url_orig))
|
||||
url = url_decode(url_orig);
|
||||
@ -578,10 +587,12 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
|
||||
*host = '\0';
|
||||
protocol = get_protocol(url);
|
||||
host += 3;
|
||||
separator = '/';
|
||||
} else {
|
||||
host = url;
|
||||
separator = ':';
|
||||
if (!url_is_local_not_ssh(url)) {
|
||||
protocol = PROTO_SSH;
|
||||
separator = ':';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -597,17 +608,12 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
|
||||
} else
|
||||
end = host;
|
||||
|
||||
path = strchr(end, separator);
|
||||
if (path && !has_dos_drive_prefix(end)) {
|
||||
if (separator == ':') {
|
||||
if (host != url || path < strchrnul(host, '/')) {
|
||||
protocol = PROTO_SSH;
|
||||
*path++ = '\0';
|
||||
} else /* '/' in the host part, assume local path */
|
||||
path = end;
|
||||
}
|
||||
} else
|
||||
if (protocol == PROTO_LOCAL)
|
||||
path = end;
|
||||
else if (protocol == PROTO_FILE && has_dos_drive_prefix(end))
|
||||
path = end; /* "file://$(pwd)" may be "file://C:/projects/repo" */
|
||||
else
|
||||
path = strchr(end, separator);
|
||||
|
||||
if (!path || !*path)
|
||||
die("No path specified. See 'man git-pull' for valid url syntax");
|
||||
@ -616,23 +622,20 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
|
||||
* null-terminate hostname and point path to ~ for URL's like this:
|
||||
* ssh://host.xz/~user/repo
|
||||
*/
|
||||
if (protocol != PROTO_LOCAL) {
|
||||
char *ptr = path;
|
||||
|
||||
end = path; /* Need to \0 terminate host here */
|
||||
if (separator == ':')
|
||||
path++; /* path starts after ':' */
|
||||
if (protocol == PROTO_GIT || protocol == PROTO_SSH) {
|
||||
if (path[1] == '~')
|
||||
path++;
|
||||
else {
|
||||
path = xstrdup(ptr);
|
||||
free_path = 1;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
path = xstrdup(path);
|
||||
*end = '\0';
|
||||
|
||||
*ret_host = xstrdup(host);
|
||||
if (free_path)
|
||||
*ret_path = path;
|
||||
else
|
||||
*ret_path = xstrdup(path);
|
||||
*ret_path = path;
|
||||
free(url);
|
||||
return protocol;
|
||||
}
|
||||
|
@ -9,5 +9,6 @@ extern int git_connection_is_socket(struct child_process *conn);
|
||||
extern int server_supports(const char *feature);
|
||||
extern int parse_feature_request(const char *features, const char *feature);
|
||||
extern const char *server_feature_value(const char *feature, int *len_ret);
|
||||
extern int url_is_local_not_ssh(const char *url);
|
||||
|
||||
#endif
|
||||
|
@ -612,4 +612,11 @@ do
|
||||
done
|
||||
done
|
||||
|
||||
test_expect_success MINGW 'fetch-pack --diag-url file://c:/repo' '
|
||||
check_prot_path file://c:/repo file c:/repo
|
||||
'
|
||||
test_expect_success MINGW 'fetch-pack --diag-url c:repo' '
|
||||
check_prot_path c:repo file c:repo
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -362,6 +362,14 @@ do
|
||||
test_clone_url [::1]:$repo ::1 $repo
|
||||
'
|
||||
done
|
||||
#home directory
|
||||
test_expect_success "clone host:/~repo" '
|
||||
test_clone_url host:/~repo host "~repo"
|
||||
'
|
||||
|
||||
test_expect_success "clone [::1]:/~repo" '
|
||||
test_clone_url [::1]:/~repo ::1 "~repo"
|
||||
'
|
||||
|
||||
# Corner cases
|
||||
for url in foo/bar:baz [foo]bar/baz:qux [foo/bar]:baz
|
||||
|
12
transport.c
12
transport.c
@ -885,14 +885,6 @@ void transport_take_over(struct transport *transport,
|
||||
transport->cannot_reuse = 1;
|
||||
}
|
||||
|
||||
static int is_local(const char *url)
|
||||
{
|
||||
const char *colon = strchr(url, ':');
|
||||
const char *slash = strchr(url, '/');
|
||||
return !colon || (slash && slash < colon) ||
|
||||
has_dos_drive_prefix(url);
|
||||
}
|
||||
|
||||
static int is_file(const char *url)
|
||||
{
|
||||
struct stat buf;
|
||||
@ -941,7 +933,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
||||
ret->fetch = fetch_objs_via_rsync;
|
||||
ret->push = rsync_transport_push;
|
||||
ret->smart_options = NULL;
|
||||
} else if (is_local(url) && is_file(url) && is_bundle(url, 1)) {
|
||||
} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
|
||||
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
|
||||
ret->data = data;
|
||||
ret->get_refs_list = get_refs_from_bundle;
|
||||
@ -1297,7 +1289,7 @@ char *transport_anonymize_url(const char *url)
|
||||
size_t anon_len, prefix_len = 0;
|
||||
|
||||
anon_part = strchr(url, '@');
|
||||
if (is_local(url) || !anon_part)
|
||||
if (url_is_local_not_ssh(url) || !anon_part)
|
||||
goto literal_copy;
|
||||
|
||||
anon_len = strlen(++anon_part);
|
||||
|
Loading…
Reference in New Issue
Block a user