From 58448910a0591c38959bd26de23cbe97e243b0af Mon Sep 17 00:00:00 2001 From: Ryan Wilcox Date: Wed, 29 Feb 2012 17:37:18 -0500 Subject: [PATCH 1/4] implement support for username@host:path URLs in transport_find_fn() --- src/transport.c | 28 +++++++++++++++++++++++++--- tests-clar/network/remotes.c | 10 ++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/transport.c b/src/transport.c index 672eb6e8a..523a9fce2 100644 --- a/src/transport.c +++ b/src/transport.c @@ -10,6 +10,8 @@ #include "git2/net.h" #include "transport.h" +#include + static struct { char *prefix; git_transport_cb fn; @@ -28,15 +30,35 @@ static struct { static git_transport_cb transport_find_fn(const char *url) { size_t i = 0; + regex_t preg; + int error; + git_transport_cb output = NULL; - /* 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; } - return NULL; + + // next, see if it matches un-schemed SSH paths used by Git + // if it does not match, it must be a local transport method + // use the slightly old fashioned :alnum: instead of \w or :word:, because + // both are Perl extensions to the Regular Expression language (and not available here) + error = regcomp(&preg, "^[[:alnum:]_]+@[[:alnum:]_]+\\.[[:alnum:]_]+:.+\\.git$", REG_EXTENDED); + if (error < 0) + goto cleanup; + + int rc = regexec(&preg, url, 0, NULL, 0); + if ( rc == REG_NOMATCH ) + output = NULL; // a match was not found - it's probably a file system path + else + output = &git_transport_git; // a match was found! + +cleanup: + regfree(&preg); + + return output; } /************** diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c index 36b945f9a..4cf473d70 100644 --- a/tests-clar/network/remotes.c +++ b/tests-clar/network/remotes.c @@ -30,6 +30,16 @@ 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(void) +{ + cl_assert( !git_remote_valid_url("/home/git/repos/libgit2.git") ); +} + void test_network_remotes__refspec_parsing(void) { cl_assert(!strcmp(git_refspec_src(_refspec), "refs/heads/*")); From 253d6df5fd899ca9273b73a919ec5f19f0ff2df4 Mon Sep 17 00:00:00 2001 From: Ryan Wilcox Date: Thu, 1 Mar 2012 08:30:38 -0500 Subject: [PATCH 2/4] fix up previous SSH path parsing commit based on @carlosmn feedback --- src/transport.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/src/transport.c b/src/transport.c index 523a9fce2..e6ba0758b 100644 --- a/src/transport.c +++ b/src/transport.c @@ -9,7 +9,7 @@ #include "git2/remote.h" #include "git2/net.h" #include "transport.h" - +#include "path.h" #include static struct { @@ -30,9 +30,6 @@ static struct { static git_transport_cb transport_find_fn(const char *url) { size_t i = 0; - regex_t preg; - int error; - git_transport_cb output = NULL; // First, check to see if it's an obvious URL, which a URL scheme for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) { @@ -40,25 +37,15 @@ static git_transport_cb transport_find_fn(const char *url) 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; - // next, see if it matches un-schemed SSH paths used by Git - // if it does not match, it must be a local transport method - // use the slightly old fashioned :alnum: instead of \w or :word:, because - // both are Perl extensions to the Regular Expression language (and not available here) - error = regcomp(&preg, "^[[:alnum:]_]+@[[:alnum:]_]+\\.[[:alnum:]_]+:.+\\.git$", REG_EXTENDED); - if (error < 0) - goto cleanup; + /* 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 */ - int rc = regexec(&preg, url, 0, NULL, 0); - if ( rc == REG_NOMATCH ) - output = NULL; // a match was not found - it's probably a file system path - else - output = &git_transport_git; // a match was found! - -cleanup: - regfree(&preg); - - return output; + return NULL; } /************** @@ -79,12 +66,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, "No supported transport mechanism found for URL or path. Either libgit2 has not implemented this transport protocol, or it can not find the specified path."); error = fn(&transport); if (error < GIT_SUCCESS) From 7a5449662972769b6b09540463d8b6378664393a Mon Sep 17 00:00:00 2001 From: Ryan Wilcox Date: Thu, 1 Mar 2012 08:31:50 -0500 Subject: [PATCH 3/4] introduced new function: git_remote_supported_url() <-- returns true if this version of libgit2 supports the correct transport mechanism for a URL or path --- src/transport.c | 6 ++++++ src/transport.h | 12 ++++++++++++ tests-clar/network/remotes.c | 13 ++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/transport.c b/src/transport.c index e6ba0758b..cd1fd88b5 100644 --- a/src/transport.c +++ b/src/transport.c @@ -88,3 +88,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..812099e7f 100644 --- a/src/transport.h +++ b/src/transport.h @@ -102,8 +102,20 @@ 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); +/** + Returns true if the passed URL is supported by this version of libgit2. + (or, more technically, the transport method inferred by libgit is supported + by this version of libgit2). +*/ +int git_remote_supported_url(const char* url); + typedef struct git_transport git_transport; typedef int (*git_transport_cb)(git_transport **transport); diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c index 4cf473d70..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; @@ -35,11 +36,21 @@ 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(void) +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/*")); From 4f8efc97c1ee06bc113443f028ba7821a7af7920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 5 Mar 2012 19:32:21 +0100 Subject: [PATCH 4/4] Make git_remote_supported_url() public and shorten error string --- include/git2/remote.h | 8 ++++++++ src/transport.c | 3 +-- src/transport.h | 7 ------- 3 files changed, 9 insertions(+), 9 deletions(-) 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 cd1fd88b5..4c486e200 100644 --- a/src/transport.c +++ b/src/transport.c @@ -10,7 +10,6 @@ #include "git2/net.h" #include "transport.h" #include "path.h" -#include static struct { char *prefix; @@ -67,7 +66,7 @@ int git_transport_new(git_transport **out, const char *url) fn = transport_find_fn(url); if (fn == NULL) - return git__throw(GIT_EINVALIDARGS, "No supported transport mechanism found for URL or path. Either libgit2 has not implemented this transport protocol, or it can not find the specified path."); + return git__throw(GIT_EINVALIDARGS, "Unsupported URL or non-existent path"); error = fn(&transport); if (error < GIT_SUCCESS) diff --git a/src/transport.h b/src/transport.h index 812099e7f..63dd7dab6 100644 --- a/src/transport.h +++ b/src/transport.h @@ -109,13 +109,6 @@ int git_transport_dummy(struct git_transport **transport); */ int git_transport_valid_url(const char *url); -/** - Returns true if the passed URL is supported by this version of libgit2. - (or, more technically, the transport method inferred by libgit is supported - by this version of libgit2). -*/ -int git_remote_supported_url(const char* url); - typedef struct git_transport git_transport; typedef int (*git_transport_cb)(git_transport **transport);