diff --git a/include/git2/remote.h b/include/git2/remote.h index e6537ec52..1830c7218 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -197,6 +197,14 @@ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote); */ GIT_EXTERN(int) git_remote_valid_url(const char *url); +/** + * Return whether the passed URL is supported by this version of the library. + * + * @param url the url to check + * @return 1 if the url is supported, 0 otherwise +*/ +GIT_EXTERN(int) git_remote_supported_url(const char* url); + /** * Get a list of the configured remotes for a repo * diff --git a/src/transport.c b/src/transport.c index 785ddc35d..4910f2433 100644 --- a/src/transport.c +++ b/src/transport.c @@ -9,6 +9,7 @@ #include "git2/remote.h" #include "git2/net.h" #include "transport.h" +#include "path.h" static struct { char *prefix; @@ -29,13 +30,20 @@ static git_transport_cb transport_find_fn(const char *url) { size_t i = 0; - /* TODO: Parse "example.com:project.git" as an SSH URL */ - + // First, check to see if it's an obvious URL, which a URL scheme for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) { if (!strncasecmp(url, transports[i].prefix, strlen(transports[i].prefix))) return transports[i].fn; } + /* still here? Check to see if the path points to a file on the local file system */ + if ((git_path_exists(url) == GIT_SUCCESS) && git_path_isdir(url)) + return &git_transport_local; + + /* It could be a SSH remote path. Check to see if there's a : */ + if (strrchr(url, ':')) + return &git_transport_dummy; /* SSH is an unsupported transport mechanism in this version of libgit2 */ + return NULL; } @@ -57,12 +65,8 @@ int git_transport_new(git_transport **out, const char *url) fn = transport_find_fn(url); - /* - * If we haven't found the transport, we assume we mean a - * local file. - */ if (fn == NULL) - fn = &git_transport_local; + return git__throw(GIT_EINVALIDARGS, "Unsupported URL or non-existent path"); error = fn(&transport); if (error < GIT_SUCCESS) @@ -83,3 +87,9 @@ int git_remote_valid_url(const char *url) return transport_find_fn(url) != NULL; } +int git_remote_supported_url(const char* url) +{ + git_transport_cb transport_fn = transport_find_fn(url); + + return ((transport_fn != NULL) && (transport_fn != &git_transport_dummy)); +} diff --git a/src/transport.h b/src/transport.h index 4c123571d..63dd7dab6 100644 --- a/src/transport.h +++ b/src/transport.h @@ -102,6 +102,11 @@ int git_transport_local(struct git_transport **transport); int git_transport_git(struct git_transport **transport); int git_transport_http(struct git_transport **transport); int git_transport_dummy(struct git_transport **transport); + +/** + Returns true if the passed URL is valid (a URL with a Git supported scheme, + or pointing to an existing path) +*/ int git_transport_valid_url(const char *url); typedef struct git_transport git_transport; diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c index 36b945f9a..add99c18b 100644 --- a/tests-clar/network/remotes.c +++ b/tests-clar/network/remotes.c @@ -1,6 +1,7 @@ #include "clar_libgit2.h" #include "buffer.h" #include "refspec.h" +#include "transport.h" static git_remote *_remote; static git_repository *_repo; @@ -30,6 +31,26 @@ void test_network_remotes__parsing(void) cl_assert(!strcmp(git_remote_url(_remote), "git://github.com/libgit2/libgit2")); } +void test_network_remotes__parsing_ssh_remote(void) +{ + cl_assert( git_remote_valid_url("git@github.com:libgit2/libgit2.git") ); +} + +void test_network_remotes__parsing_local_path_fails_if_path_not_found(void) +{ + cl_assert( !git_remote_valid_url("/home/git/repos/libgit2.git") ); +} + +void test_network_remotes__supported_transport_methods_are_supported(void) +{ + cl_assert( git_remote_supported_url("git://github.com/libgit2/libgit2") ); +} + +void test_network_remotes__unsupported_transport_methods_are_unsupported(void) +{ + cl_assert( !git_remote_supported_url("git@github.com:libgit2/libgit2.git") ); +} + void test_network_remotes__refspec_parsing(void) { cl_assert(!strcmp(git_refspec_src(_refspec), "refs/heads/*"));