remote: introduce git_remote_ready_cb Introduce a new callback that fires when the remote is ready to connect.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 5b67717..b75a991 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -514,6 +514,18 @@ typedef int GIT_CALLBACK(git_push_update_reference_cb)(const char *refname, cons
typedef int GIT_CALLBACK(git_url_resolve_cb)(git_buf *url_resolved, const char *url, int direction, void *payload);
/**
+ * Callback invoked immediately before we attempt to connect to the
+ * given url. Callers may change the URL before the connection by
+ * calling `git_remote_set_instance_url` in the callback.
+ *
+ * @param remote The remote to be connected
+ * @param direction GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH
+ * @param payload Payload provided by the caller
+ * @return 0 on success, or an error
+ */
+typedef int GIT_CALLBACK(git_remote_ready_cb)(git_remote *remote, int direction, void *payload);
+
+/**
* The callback settings structure
*
* Set the callbacks to be called by the remote when informing the user
@@ -598,6 +610,11 @@ struct git_remote_callbacks {
git_transport_cb transport;
/**
+ * Callback when the remote is ready to connect.
+ */
+ git_remote_ready_cb remote_ready;
+
+ /**
* This will be passed to each of the callbacks in this struct
* as the last parameter.
*/
diff --git a/src/remote.c b/src/remote.c
index 236f39a..8050e65 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -709,11 +709,19 @@ int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int
GIT_ASSERT_ARG(remote);
GIT_ASSERT_ARG(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
- if (direction == GIT_DIRECTION_FETCH) {
+ if (callbacks && callbacks->remote_ready) {
+ int status = callbacks->remote_ready(remote, direction, callbacks->payload);
+
+ if (status != 0 && status != GIT_PASSTHROUGH) {
+ git_error_set_after_callback_function(status, "git_remote_ready_cb");
+ return status;
+ }
+ }
+
+ if (direction == GIT_DIRECTION_FETCH)
url = remote->url;
- } else if (direction == GIT_DIRECTION_PUSH) {
+ else if (direction == GIT_DIRECTION_PUSH)
url = remote->pushurl ? remote->pushurl : remote->url;
- }
if (!url) {
git_error_set(GIT_ERROR_INVALID,
@@ -722,6 +730,7 @@ int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int
direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
return GIT_EINVALID;
}
+
return resolve_url(url_out, url, direction, callbacks);
}
diff --git a/tests/network/remote/remotes.c b/tests/network/remote/remotes.c
index a962d92..4a9f5ae 100644
--- a/tests/network/remote/remotes.c
+++ b/tests/network/remote/remotes.c
@@ -56,6 +56,48 @@ void test_network_remote_remotes__parsing(void)
git_buf_dispose(&url);
}
+static int remote_ready_callback(git_remote *remote, int direction, void *payload)
+{
+ if (direction == GIT_DIRECTION_PUSH) {
+ const char *url = git_remote_pushurl(remote);
+
+ cl_assert_equal_p(url, NULL);;
+ cl_assert_equal_s(payload, "payload");
+ return git_remote_set_instance_pushurl(remote, "push_url");
+ }
+
+ if (direction == GIT_DIRECTION_FETCH) {
+ const char *url = git_remote_url(remote);
+
+ cl_assert_equal_s(url, "git://github.com/libgit2/libgit2");
+ cl_assert_equal_s(payload, "payload");
+ return git_remote_set_instance_url(remote, "fetch_url");
+ }
+
+ return -1;
+}
+
+void test_network_remote_remotes__remote_ready(void)
+{
+ git_buf url = GIT_BUF_INIT;
+
+ git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
+ callbacks.remote_ready = remote_ready_callback;
+ callbacks.payload = "payload";
+
+ cl_assert_equal_s(git_remote_name(_remote), "test");
+ cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
+ cl_assert(git_remote_pushurl(_remote) == NULL);
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks));
+ cl_assert_equal_s(url.ptr, "fetch_url");
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks));
+ cl_assert_equal_s(url.ptr, "push_url");
+
+ git_buf_dispose(&url);
+}
+
static int urlresolve_callback(git_buf *url_resolved, const char *url, int direction, void *payload)
{
cl_assert(strcmp(url, "git://github.com/libgit2/libgit2") == 0);
diff --git a/tests/online/push_util.h b/tests/online/push_util.h
index d829bbc..5f669fe 100644
--- a/tests/online/push_util.h
+++ b/tests/online/push_util.h
@@ -12,7 +12,7 @@ extern const git_oid OID_ZERO;
* @param data pointer to a record_callbacks_data instance
*/
#define RECORD_CALLBACKS_INIT(data) \
- { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, data, NULL }
+ { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, NULL, data, NULL }
typedef struct {
char *name;