Pass unknown protocols to external protocol handlers
Change URL handling to allow external protocol handlers to implement new protocols without the '::' syntax if helper name does not conflict with any built-in protocol. foo:// now invokes git-remote-foo with foo:// as the URL. Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
28ed5b3524
commit
25d5cc488a
@ -63,6 +63,16 @@ static void write_constant(int fd, const char *str)
|
|||||||
die_errno("Full write to remote helper failed");
|
die_errno("Full write to remote helper failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *remove_ext_force(const char *url)
|
||||||
|
{
|
||||||
|
if (url) {
|
||||||
|
const char *colon = strchr(url, ':');
|
||||||
|
if (colon && colon[1] == ':')
|
||||||
|
return colon + 2;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
static struct child_process *get_helper(struct transport *transport)
|
static struct child_process *get_helper(struct transport *transport)
|
||||||
{
|
{
|
||||||
struct helper_data *data = transport->data;
|
struct helper_data *data = transport->data;
|
||||||
@ -83,7 +93,7 @@ static struct child_process *get_helper(struct transport *transport)
|
|||||||
strbuf_addf(&buf, "remote-%s", data->name);
|
strbuf_addf(&buf, "remote-%s", data->name);
|
||||||
helper->argv[0] = strbuf_detach(&buf, NULL);
|
helper->argv[0] = strbuf_detach(&buf, NULL);
|
||||||
helper->argv[1] = transport->remote->name;
|
helper->argv[1] = transport->remote->name;
|
||||||
helper->argv[2] = transport->url;
|
helper->argv[2] = remove_ext_force(transport->url);
|
||||||
helper->git_cmd = 1;
|
helper->git_cmd = 1;
|
||||||
if (start_command(helper))
|
if (start_command(helper))
|
||||||
die("Unable to run helper: git %s", helper->argv[0]);
|
die("Unable to run helper: git %s", helper->argv[0]);
|
||||||
|
76
transport.c
76
transport.c
@ -780,6 +780,44 @@ static int is_file(const char *url)
|
|||||||
return S_ISREG(buf.st_mode);
|
return S_ISREG(buf.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_url(const char *url)
|
||||||
|
{
|
||||||
|
const char *url2, *first_slash;
|
||||||
|
|
||||||
|
if (!url)
|
||||||
|
return 0;
|
||||||
|
url2 = url;
|
||||||
|
first_slash = strchr(url, '/');
|
||||||
|
|
||||||
|
/* Input with no slash at all or slash first can't be URL. */
|
||||||
|
if (!first_slash || first_slash == url)
|
||||||
|
return 0;
|
||||||
|
/* Character before must be : and next must be /. */
|
||||||
|
if (first_slash[-1] != ':' || first_slash[1] != '/')
|
||||||
|
return 0;
|
||||||
|
/* There must be something before the :// */
|
||||||
|
if (first_slash == url + 1)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* Check all characters up to first slash - 1. Only alphanum
|
||||||
|
* is allowed.
|
||||||
|
*/
|
||||||
|
url2 = url;
|
||||||
|
while (url2 < first_slash - 1) {
|
||||||
|
if (!isalnum((unsigned char)*url2))
|
||||||
|
return 0;
|
||||||
|
url2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Valid enough. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int external_specification_len(const char *url)
|
||||||
|
{
|
||||||
|
return strchr(url, ':') - url;
|
||||||
|
}
|
||||||
|
|
||||||
struct transport *transport_get(struct remote *remote, const char *url)
|
struct transport *transport_get(struct remote *remote, const char *url)
|
||||||
{
|
{
|
||||||
struct transport *ret = xcalloc(1, sizeof(*ret));
|
struct transport *ret = xcalloc(1, sizeof(*ret));
|
||||||
@ -805,30 +843,23 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
|||||||
|
|
||||||
if (remote && remote->foreign_vcs) {
|
if (remote && remote->foreign_vcs) {
|
||||||
transport_helper_init(ret, remote->foreign_vcs);
|
transport_helper_init(ret, remote->foreign_vcs);
|
||||||
return ret;
|
} else if (!prefixcmp(url, "rsync:")) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!prefixcmp(url, "rsync:")) {
|
|
||||||
ret->get_refs_list = get_refs_via_rsync;
|
ret->get_refs_list = get_refs_via_rsync;
|
||||||
ret->fetch = fetch_objs_via_rsync;
|
ret->fetch = fetch_objs_via_rsync;
|
||||||
ret->push = rsync_transport_push;
|
ret->push = rsync_transport_push;
|
||||||
|
|
||||||
} else if (!prefixcmp(url, "http://")
|
|
||||||
|| !prefixcmp(url, "https://")
|
|
||||||
|| !prefixcmp(url, "ftp://")) {
|
|
||||||
transport_helper_init(ret, "curl");
|
|
||||||
#ifdef NO_CURL
|
|
||||||
error("git was compiled without libcurl support.");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else if (is_local(url) && is_file(url)) {
|
} else if (is_local(url) && is_file(url)) {
|
||||||
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
|
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
|
||||||
ret->data = data;
|
ret->data = data;
|
||||||
ret->get_refs_list = get_refs_from_bundle;
|
ret->get_refs_list = get_refs_from_bundle;
|
||||||
ret->fetch = fetch_refs_from_bundle;
|
ret->fetch = fetch_refs_from_bundle;
|
||||||
ret->disconnect = close_bundle;
|
ret->disconnect = close_bundle;
|
||||||
|
} else if (!is_url(url)
|
||||||
} else {
|
|| !prefixcmp(url, "file://")
|
||||||
|
|| !prefixcmp(url, "git://")
|
||||||
|
|| !prefixcmp(url, "ssh://")
|
||||||
|
|| !prefixcmp(url, "git+ssh://")
|
||||||
|
|| !prefixcmp(url, "ssh+git://")) {
|
||||||
|
/* These are builtin smart transports. */
|
||||||
struct git_transport_data *data = xcalloc(1, sizeof(*data));
|
struct git_transport_data *data = xcalloc(1, sizeof(*data));
|
||||||
ret->data = data;
|
ret->data = data;
|
||||||
ret->set_option = set_git_option;
|
ret->set_option = set_git_option;
|
||||||
@ -845,6 +876,21 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
|||||||
data->receivepack = "git-receive-pack";
|
data->receivepack = "git-receive-pack";
|
||||||
if (remote->receivepack)
|
if (remote->receivepack)
|
||||||
data->receivepack = remote->receivepack;
|
data->receivepack = remote->receivepack;
|
||||||
|
} else if (!prefixcmp(url, "http://")
|
||||||
|
|| !prefixcmp(url, "https://")
|
||||||
|
|| !prefixcmp(url, "ftp://")) {
|
||||||
|
/* These three are just plain special. */
|
||||||
|
transport_helper_init(ret, "curl");
|
||||||
|
#ifdef NO_CURL
|
||||||
|
error("git was compiled without libcurl support.");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
/* Unknown protocol in URL. Pass to external handler. */
|
||||||
|
int len = external_specification_len(url);
|
||||||
|
char *handler = xmalloc(len + 1);
|
||||||
|
handler[len] = 0;
|
||||||
|
strncpy(handler, url, len);
|
||||||
|
transport_helper_init(ret, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user