Skip to content

Commit 16a2e66

Browse files
authored
Merge pull request libgit2#6012 from libgit2/ethomson/custom_url
remote: introduce remote_ready_cb, deprecate resolve_url callback
2 parents 9f84003 + 7442c00 commit 16a2e66

File tree

4 files changed

+207
-9
lines changed

4 files changed

+207
-9
lines changed

include/git2/remote.h

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,18 +212,20 @@ GIT_EXTERN(const char *) git_remote_name(const git_remote *remote);
212212
* Get the remote's url
213213
*
214214
* If url.*.insteadOf has been configured for this URL, it will
215-
* return the modified URL.
215+
* return the modified URL. If `git_remote_set_instance_pushurl`
216+
* has been called for this remote, then that URL will be returned.
216217
*
217218
* @param remote the remote
218219
* @return a pointer to the url
219220
*/
220221
GIT_EXTERN(const char *) git_remote_url(const git_remote *remote);
221222

222223
/**
223-
* Get the remote's url for pushing
224+
* Get the remote's url for pushing.
224225
*
225226
* If url.*.pushInsteadOf has been configured for this URL, it
226-
* will return the modified URL.
227+
* will return the modified URL. If `git_remote_set_instance_pushurl`
228+
* has been called for this remote, then that URL will be returned.
227229
*
228230
* @param remote the remote
229231
* @return a pointer to the url or NULL if no special url for pushing is set
@@ -257,6 +259,26 @@ GIT_EXTERN(int) git_remote_set_url(git_repository *repo, const char *remote, con
257259
*/
258260
GIT_EXTERN(int) git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url);
259261

262+
/**
263+
* Set the url for this particular url instance. The URL in the
264+
* configuration will be ignored, and will not be changed.
265+
*
266+
* @param remote the remote's name
267+
* @param url the url to set
268+
* @return 0 or an error value
269+
*/
270+
GIT_EXTERN(int) git_remote_set_instance_url(git_remote *remote, const char *url);
271+
272+
/**
273+
* Set the push url for this particular url instance. The URL in the
274+
* configuration will be ignored, and will not be changed.
275+
*
276+
* @param remote the remote's name
277+
* @param url the url to set
278+
* @return 0 or an error value
279+
*/
280+
GIT_EXTERN(int) git_remote_set_instance_pushurl(git_remote *remote, const char *url);
281+
260282
/**
261283
* Add a fetch refspec to the remote's configuration
262284
*
@@ -477,6 +499,7 @@ typedef int GIT_CALLBACK(git_push_negotiation)(const git_push_update **updates,
477499
*/
478500
typedef int GIT_CALLBACK(git_push_update_reference_cb)(const char *refname, const char *status, void *data);
479501

502+
#ifndef GIT_DEPRECATE_HARD
480503
/**
481504
* Callback to resolve URLs before connecting to remote
482505
*
@@ -488,8 +511,22 @@ typedef int GIT_CALLBACK(git_push_update_reference_cb)(const char *refname, cons
488511
* @param direction GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH
489512
* @param payload Payload provided by the caller
490513
* @return 0 on success, GIT_PASSTHROUGH or an error
514+
* @deprecated Use `git_remote_set_instance_url`
491515
*/
492516
typedef int GIT_CALLBACK(git_url_resolve_cb)(git_buf *url_resolved, const char *url, int direction, void *payload);
517+
#endif
518+
519+
/**
520+
* Callback invoked immediately before we attempt to connect to the
521+
* given url. Callers may change the URL before the connection by
522+
* calling `git_remote_set_instance_url` in the callback.
523+
*
524+
* @param remote The remote to be connected
525+
* @param direction GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH
526+
* @param payload Payload provided by the caller
527+
* @return 0 on success, or an error
528+
*/
529+
typedef int GIT_CALLBACK(git_remote_ready_cb)(git_remote *remote, int direction, void *payload);
493530

494531
/**
495532
* The callback settings structure
@@ -575,17 +612,29 @@ struct git_remote_callbacks {
575612
*/
576613
git_transport_cb transport;
577614

615+
/**
616+
* Callback when the remote is ready to connect.
617+
*/
618+
git_remote_ready_cb remote_ready;
619+
578620
/**
579621
* This will be passed to each of the callbacks in this struct
580622
* as the last parameter.
581623
*/
582624
void *payload;
583625

626+
#ifdef GIT_DEPRECATE_HARD
627+
void *reserved;
628+
#else
584629
/**
585630
* Resolve URL before connecting to remote.
586631
* The returned URL will be used to connect to the remote instead.
632+
*
633+
* This callback is deprecated; users should use
634+
* git_remote_ready_cb and configure the instance URL instead.
587635
*/
588636
git_url_resolve_cb resolve_url;
637+
#endif
589638
};
590639

591640
#define GIT_REMOTE_CALLBACKS_VERSION 1

src/remote.c

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,22 @@ const char *git_remote_url(const git_remote *remote)
600600
return remote->url;
601601
}
602602

603+
int git_remote_set_instance_url(git_remote *remote, const char *url)
604+
{
605+
char *tmp;
606+
607+
GIT_ASSERT_ARG(remote);
608+
GIT_ASSERT_ARG(url);
609+
610+
if ((tmp = git__strdup(url)) == NULL)
611+
return -1;
612+
613+
git__free(remote->url);
614+
remote->url = tmp;
615+
616+
return 0;
617+
}
618+
603619
static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
604620
{
605621
git_config *cfg;
@@ -645,13 +661,37 @@ const char *git_remote_pushurl(const git_remote *remote)
645661
return remote->pushurl;
646662
}
647663

664+
int git_remote_set_instance_pushurl(git_remote *remote, const char *url)
665+
{
666+
char *tmp;
667+
668+
GIT_ASSERT_ARG(remote);
669+
GIT_ASSERT_ARG(url);
670+
671+
if ((tmp = git__strdup(url)) == NULL)
672+
return -1;
673+
674+
git__free(remote->pushurl);
675+
remote->pushurl = tmp;
676+
677+
return 0;
678+
}
679+
648680
int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
649681
{
650682
return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
651683
}
652684

653-
static int resolve_url(git_buf *resolved_url, const char *url, int direction, const git_remote_callbacks *callbacks)
685+
static int resolve_url(
686+
git_buf *resolved_url,
687+
const char *url,
688+
int direction,
689+
const git_remote_callbacks *callbacks)
654690
{
691+
#ifdef GIT_DEPRECATE_HARD
692+
GIT_UNUSED(direction);
693+
GIT_UNUSED(callbacks);
694+
#else
655695
int status, error;
656696

657697
if (callbacks && callbacks->resolve_url) {
@@ -666,22 +706,35 @@ static int resolve_url(git_buf *resolved_url, const char *url, int direction, co
666706
return status;
667707
}
668708
}
709+
#endif
669710

670711
return git_buf_sets(resolved_url, url);
671712
}
672713

673-
int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks)
714+
int git_remote__urlfordirection(
715+
git_buf *url_out,
716+
struct git_remote *remote,
717+
int direction,
718+
const git_remote_callbacks *callbacks)
674719
{
675720
const char *url = NULL;
676721

677722
GIT_ASSERT_ARG(remote);
678723
GIT_ASSERT_ARG(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
679724

680-
if (direction == GIT_DIRECTION_FETCH) {
725+
if (callbacks && callbacks->remote_ready) {
726+
int status = callbacks->remote_ready(remote, direction, callbacks->payload);
727+
728+
if (status != 0 && status != GIT_PASSTHROUGH) {
729+
git_error_set_after_callback_function(status, "git_remote_ready_cb");
730+
return status;
731+
}
732+
}
733+
734+
if (direction == GIT_DIRECTION_FETCH)
681735
url = remote->url;
682-
} else if (direction == GIT_DIRECTION_PUSH) {
736+
else if (direction == GIT_DIRECTION_PUSH)
683737
url = remote->pushurl ? remote->pushurl : remote->url;
684-
}
685738

686739
if (!url) {
687740
git_error_set(GIT_ERROR_INVALID,
@@ -690,6 +743,7 @@ int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int
690743
direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
691744
return GIT_EINVALID;
692745
}
746+
693747
return resolve_url(url_out, url, direction, callbacks);
694748
}
695749

tests/network/remote/remotes.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,49 @@ void test_network_remote_remotes__parsing(void)
5656
git_buf_dispose(&url);
5757
}
5858

59+
static int remote_ready_callback(git_remote *remote, int direction, void *payload)
60+
{
61+
if (direction == GIT_DIRECTION_PUSH) {
62+
const char *url = git_remote_pushurl(remote);
63+
64+
cl_assert_equal_p(url, NULL);;
65+
cl_assert_equal_s(payload, "payload");
66+
return git_remote_set_instance_pushurl(remote, "push_url");
67+
}
68+
69+
if (direction == GIT_DIRECTION_FETCH) {
70+
const char *url = git_remote_url(remote);
71+
72+
cl_assert_equal_s(url, "git://github.com/libgit2/libgit2");
73+
cl_assert_equal_s(payload, "payload");
74+
return git_remote_set_instance_url(remote, "fetch_url");
75+
}
76+
77+
return -1;
78+
}
79+
80+
void test_network_remote_remotes__remote_ready(void)
81+
{
82+
git_buf url = GIT_BUF_INIT;
83+
84+
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
85+
callbacks.remote_ready = remote_ready_callback;
86+
callbacks.payload = "payload";
87+
88+
cl_assert_equal_s(git_remote_name(_remote), "test");
89+
cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
90+
cl_assert(git_remote_pushurl(_remote) == NULL);
91+
92+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks));
93+
cl_assert_equal_s(url.ptr, "fetch_url");
94+
95+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks));
96+
cl_assert_equal_s(url.ptr, "push_url");
97+
98+
git_buf_dispose(&url);
99+
}
100+
101+
#ifndef GIT_DEPRECATE_HARD
59102
static int urlresolve_callback(git_buf *url_resolved, const char *url, int direction, void *payload)
60103
{
61104
cl_assert(strcmp(url, "git://github.com/libgit2/libgit2") == 0);
@@ -69,9 +112,11 @@ static int urlresolve_callback(git_buf *url_resolved, const char *url, int direc
69112

70113
return GIT_OK;
71114
}
115+
#endif
72116

73117
void test_network_remote_remotes__urlresolve(void)
74118
{
119+
#ifndef GIT_DEPRECATE_HARD
75120
git_buf url = GIT_BUF_INIT;
76121

77122
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
@@ -89,8 +134,10 @@ void test_network_remote_remotes__urlresolve(void)
89134
cl_assert_equal_s(url.ptr, "pushresolve");
90135

91136
git_buf_dispose(&url);
137+
#endif
92138
}
93139

140+
#ifndef GIT_DEPRECATE_HARD
94141
static int urlresolve_passthrough_callback(git_buf *url_resolved, const char *url, int direction, void *payload)
95142
{
96143
GIT_UNUSED(url_resolved);
@@ -99,9 +146,11 @@ static int urlresolve_passthrough_callback(git_buf *url_resolved, const char *ur
99146
GIT_UNUSED(payload);
100147
return GIT_PASSTHROUGH;
101148
}
149+
#endif
102150

103151
void test_network_remote_remotes__urlresolve_passthrough(void)
104152
{
153+
#ifndef GIT_DEPRECATE_HARD
105154
git_buf url = GIT_BUF_INIT;
106155
const char *orig_url = "git://github.com/libgit2/libgit2";
107156

@@ -118,6 +167,52 @@ void test_network_remote_remotes__urlresolve_passthrough(void)
118167
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks));
119168
cl_assert_equal_s(url.ptr, orig_url);
120169

170+
git_buf_dispose(&url);
171+
#endif
172+
}
173+
174+
void test_network_remote_remotes__instance_url(void)
175+
{
176+
git_buf url = GIT_BUF_INIT;
177+
const char *orig_url = "git://github.com/libgit2/libgit2";
178+
179+
cl_assert_equal_s(git_remote_name(_remote), "test");
180+
cl_assert_equal_s(git_remote_url(_remote), orig_url);
181+
182+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
183+
cl_assert_equal_s(url.ptr, orig_url);
184+
git_buf_clear(&url);
185+
186+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
187+
cl_assert_equal_s(url.ptr, orig_url);
188+
git_buf_clear(&url);
189+
190+
/* Setting the instance url updates the fetch and push URLs */
191+
git_remote_set_instance_url(_remote, "https://github.com/new/remote/url");
192+
cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url");
193+
cl_assert_equal_p(git_remote_pushurl(_remote), NULL);
194+
195+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
196+
cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
197+
git_buf_clear(&url);
198+
199+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
200+
cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
201+
git_buf_clear(&url);
202+
203+
/* Setting the instance push url updates only the push URL */
204+
git_remote_set_instance_pushurl(_remote, "https://github.com/new/push/url");
205+
cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url");
206+
cl_assert_equal_s(git_remote_pushurl(_remote), "https://github.com/new/push/url");
207+
208+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
209+
cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url");
210+
git_buf_clear(&url);
211+
212+
cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
213+
cl_assert_equal_s(url.ptr, "https://github.com/new/push/url");
214+
git_buf_clear(&url);
215+
121216
git_buf_dispose(&url);
122217
}
123218

tests/online/push_util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extern const git_oid OID_ZERO;
1212
* @param data pointer to a record_callbacks_data instance
1313
*/
1414
#define RECORD_CALLBACKS_INIT(data) \
15-
{ GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, data, NULL }
15+
{ GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, NULL, data, NULL }
1616

1717
typedef struct {
1818
char *name;

0 commit comments

Comments
 (0)