Unverified Commit 7eb7edd4 by Edward Thomson Committed by GitHub

Merge pull request #6278 from lhchavez/git_transport_smart_remote_connect_options

transport: introduce `git_transport_smart_remote_connect_options`
parents d333dbea cc4c37ca
......@@ -8,6 +8,8 @@
#ifndef INCLUDE_sys_git_remote_h
#define INCLUDE_sys_git_remote_h
#include "git2/remote.h"
/**
* @file git2/sys/remote.h
* @brief Low-level remote functionality for custom transports
......@@ -26,6 +28,19 @@ typedef enum {
GIT_REMOTE_CAPABILITY_REACHABLE_OID = (1 << 1),
} git_remote_capability_t;
/**
* Disposes libgit2-initialized fields from a git_remote_connect_options.
* This should only be used for git_remote_connect_options returned by
* git_transport_remote_connect_options.
*
* Note that this does not free the `git_remote_connect_options` itself, just
* the memory pointed to by it.
*
* @param opts The `git_remote_connect_options` struct to dispose.
*/
GIT_EXTERN(void) git_remote_connect_options_dispose(
git_remote_connect_options *opts);
/** @} */
GIT_END_DECL
#endif
......@@ -9,11 +9,11 @@
#define INCLUDE_sys_git_transport_h
#include "git2/net.h"
#include "git2/proxy.h"
#include "git2/remote.h"
#include "git2/strarray.h"
#include "git2/transport.h"
#include "git2/types.h"
#include "git2/strarray.h"
#include "git2/proxy.h"
/**
* @file git2/sys/transport.h
......@@ -261,6 +261,19 @@ GIT_EXTERN(int) git_transport_smart_certificate_check(git_transport *transport,
*/
GIT_EXTERN(int) git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods);
/**
* Get a copy of the remote connect options
*
* All data is copied and must be freed by the caller by calling
* `git_remote_connect_options_dispose`.
*
* @param out options struct to fill
* @param transport the transport to extract the data from.
*/
GIT_EXTERN(int) git_transport_remote_connect_options(
git_remote_connect_options *out,
git_transport *transport);
/*
*** End of base transport interface ***
*** Begin interface for subtransports for the smart transport ***
......
......@@ -11,6 +11,7 @@
#include "git2/remote.h"
#include "git2/transport.h"
#include "git2/sys/remote.h"
#include "git2/sys/transport.h"
#include "refspec.h"
......@@ -53,7 +54,6 @@ int git_remote_connect_options_normalize(
git_remote_connect_options *dst,
git_repository *repo,
const git_remote_connect_options *src);
void git_remote_connect_options_dispose(git_remote_connect_options *opts);
int git_remote_capabilities(unsigned int *out, git_remote *remote);
......
......@@ -425,6 +425,18 @@ int git_transport_smart_credentials(git_credential **out, git_transport *transpo
return connect_opts->callbacks.credentials(out, t->url, user, methods, connect_opts->callbacks.payload);
}
int git_transport_remote_connect_options(
git_remote_connect_options *out,
git_transport *transport)
{
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(transport);
return git_remote_connect_options_dup(out, &t->connect_opts);
}
int git_transport_smart(git_transport **out, git_remote *owner, void *param)
{
transport_smart *t;
......
#include "clar_libgit2.h"
#include "git2/sys/remote.h"
#include "git2/sys/transport.h"
static const char *proxy_url = "https://proxy";
static git_transport _transport = GIT_TRANSPORT_INIT;
static int dummy_transport(git_transport **transport, git_remote *owner, void *param)
......@@ -77,3 +79,146 @@ void test_transport_register__custom_transport_ssh(void)
#endif
}
}
static int custom_subtransport_stream__read(
git_smart_subtransport_stream *stream,
char *buffer,
size_t buf_size,
size_t *bytes_read)
{
GIT_UNUSED(stream);
GIT_UNUSED(buffer);
GIT_UNUSED(buf_size);
*bytes_read = 0;
git_error_set_str(42, "unimplemented");
return GIT_EUSER;
}
static int custom_subtransport_stream__write(
git_smart_subtransport_stream *stream,
const char *buffer,
size_t len)
{
GIT_UNUSED(stream);
GIT_UNUSED(buffer);
GIT_UNUSED(len);
git_error_set_str(42, "unimplemented");
return GIT_EUSER;
}
static void custom_subtransport_stream__free(
git_smart_subtransport_stream *stream)
{
git__free(stream);
}
struct custom_subtransport {
git_smart_subtransport subtransport;
git_transport *owner;
int *called;
};
static int custom_subtransport__action(
git_smart_subtransport_stream **out,
git_smart_subtransport *transport,
const char *url,
git_smart_service_t action)
{
struct custom_subtransport *t = (struct custom_subtransport *)transport;
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
int ret;
GIT_UNUSED(url);
GIT_UNUSED(action);
ret = git_transport_remote_connect_options(&opts, t->owner);
/* increase the counter once if this function was called at all and once more if the URL matches. */
(*t->called)++;
if (strcmp(proxy_url, opts.proxy_opts.url) == 0)
(*t->called)++;
git_remote_connect_options_dispose(&opts);
*out = git__calloc(1, sizeof(git_smart_subtransport_stream));
(*out)->subtransport = transport;
(*out)->read = custom_subtransport_stream__read;
(*out)->write = custom_subtransport_stream__write;
(*out)->free = custom_subtransport_stream__free;
return ret;
}
static int custom_subtransport__close(git_smart_subtransport *transport)
{
GIT_UNUSED(transport);
return 0;
}
static void custom_subtransport__free(git_smart_subtransport *transport)
{
GIT_UNUSED(transport);
git__free(transport);
}
static int custom_transport_callback(git_smart_subtransport **out, git_transport *owner, void *param)
{
struct custom_subtransport *subtransport = git__calloc(1, sizeof(struct custom_subtransport));
subtransport->called = (int *)param;
subtransport->owner = owner;
subtransport->subtransport.action = custom_subtransport__action;
subtransport->subtransport.close = custom_subtransport__close;
subtransport->subtransport.free = custom_subtransport__free;
*out = &subtransport->subtransport;
return 0;
}
static int custom_transport(git_transport **out, git_remote *owner, void *param)
{
struct git_smart_subtransport_definition definition;
definition.callback = custom_transport_callback;
definition.rpc = false;
definition.param = param;
return git_transport_smart(out, owner, &definition);
}
void test_transport_register__custom_transport_callbacks(void)
{
git_transport *transport;
int called = 0;
const char *url = "custom://somepath";
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
git_repository *repo;
git_remote *remote;
cl_git_pass(git_repository_init(&repo, "./transport", 0));
cl_git_pass(git_remote_create(&remote, repo, "test",
cl_fixture("testrepo.git")));
cl_git_pass(git_transport_register("custom", custom_transport, &called));
cl_git_pass(git_transport_new(&transport, remote, url));
opts.follow_redirects = GIT_REMOTE_REDIRECT_NONE;
opts.proxy_opts.url = proxy_url;
/* This is expected to fail, since the subtransport_stream is not implemented */
transport->connect(transport, url, GIT_SERVICE_UPLOADPACK_LS, &opts);
/* the counter is increased twice if everything goes as planned */
cl_assert_equal_i(2, called);
cl_git_pass(transport->close(transport));
transport->free(transport);
cl_git_pass(git_transport_unregister("custom"));
git_remote_free(remote);
git_repository_free(repo);
cl_fixture_cleanup("testrepo.git");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment