From 8378695671cec5d45464cea65aa5199ecf242212 Mon Sep 17 00:00:00 2001 From: Philip Kelley Date: Fri, 4 Jan 2013 14:39:05 -0500 Subject: [PATCH] Add git_transport_register, git_transport_unregister --- include/git2/transport.h | 34 +++++++++++++++++++++ src/transport.c | 66 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/include/git2/transport.h b/include/git2/transport.h index e61b10423..9901b15de 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -253,6 +253,40 @@ GIT_EXTERN(int) git_transport_new(git_transport **out, git_remote *owner, const /* Signature of a function which creates a transport */ typedef int (*git_transport_cb)(git_transport **out, git_remote *owner, void *param); +/** + * Add a custom transport definition, to be used in addition to the built-in + * set of transports that come with libgit2. + * + * The caller is responsible for synchronizing calls to git_transport_register + * and git_transport_unregister with other calls to the library that + * instantiate transports. + * + * @param prefix The scheme (ending in "://") to match, i.e. "git://" + * @param priority The priority of this transport relative to others with + * the same prefix. Built-in transports have a priority of 1. + * @param cb The callback used to create an instance of the transport + * @param param A fixed parameter to pass to cb at creation time + * @return 0 or an error code + */ +GIT_EXTERN(int) git_transport_register( + const char *prefix, + unsigned priority, + git_transport_cb cb, + void *param); + +/** + * + * Unregister a custom transport definition which was previously registered + * with git_transport_register. + * + * @param prefix From the previous call to git_transport_register + * @param priority From the previous call to git_transport_register + * @return 0 or an error code + */ +GIT_EXTERN(int) git_transport_unregister( + const char *prefix, + unsigned priority); + /* Transports which come with libgit2 (match git_transport_cb). The expected * value for "param" is listed in-line below. */ diff --git a/src/transport.c b/src/transport.c index 354789db1..ff926b1be 100644 --- a/src/transport.c +++ b/src/transport.c @@ -42,6 +42,8 @@ static transport_definition transports[] = { {NULL, 0, 0} }; +static git_vector additional_transports = GIT_VECTOR_INIT; + #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1 static int transport_find_fn(const char *url, git_transport_cb *callback, void **param) @@ -61,6 +63,14 @@ static int transport_find_fn(const char *url, git_transport_cb *callback, void * definition = definition_iter; } + git_vector_foreach(&additional_transports, i, definition_iter) { + if (strncasecmp(url, definition_iter->prefix, strlen(definition_iter->prefix))) + continue; + + if (definition_iter->priority > priority) + definition = definition_iter; + } + #ifdef GIT_WIN32 /* On Windows, it might not be possible to discern between absolute local * and ssh paths - first check if this is a valid local path that points @@ -135,6 +145,62 @@ int git_transport_new(git_transport **out, git_remote *owner, const char *url) return 0; } +int git_transport_register( + const char *prefix, + unsigned priority, + git_transport_cb cb, + void *param) +{ + transport_definition *d; + + d = git__calloc(sizeof(transport_definition), 1); + GITERR_CHECK_ALLOC(d); + + d->prefix = git__strdup(prefix); + + if (!d->prefix) + goto on_error; + + d->priority = priority; + d->fn = cb; + d->param = param; + + if (git_vector_insert(&additional_transports, d) < 0) + goto on_error; + + return 0; + +on_error: + git__free(d->prefix); + git__free(d); + return -1; +} + +int git_transport_unregister( + const char *prefix, + unsigned priority) +{ + transport_definition *d; + unsigned i; + + git_vector_foreach(&additional_transports, i, d) { + if (d->priority == priority && !strcasecmp(d->prefix, prefix)) { + if (git_vector_remove(&additional_transports, i) < 0) + return -1; + + git__free(d->prefix); + git__free(d); + + if (!additional_transports.length) + git_vector_free(&additional_transports); + + return 0; + } + } + + return GIT_ENOTFOUND; +} + /* from remote.h */ int git_remote_valid_url(const char *url) {