From: Derrick Stolee <derrickstolee@xxxxxxxxxx> To allow 'git clone' to check the 'features' capability, we need to fill in some boilerplate methods that help detect if the capability exists and then to execute the get_recommended_features() method with the proper context. This involves jumping through some vtables. Signed-off-by: Derrick Stolee <derrickstolee@xxxxxxxxxx> --- transport-helper.c | 14 ++++++++++++++ transport-internal.h | 9 +++++++++ transport.c | 38 ++++++++++++++++++++++++++++++++++++++ transport.h | 5 +++++ 4 files changed, 66 insertions(+) diff --git a/transport-helper.c b/transport-helper.c index a0297b0986c..642472e2adb 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -1264,11 +1264,25 @@ static struct ref *get_refs_list_using_list(struct transport *transport, return ret; } +static int get_features(struct transport *transport, + struct string_list *list) +{ + get_helper(transport); + + if (process_connect(transport, 0)) { + do_take_over(transport); + return transport->vtable->get_features(transport, list); + } + + return -1; +} + static struct transport_vtable vtable = { .set_option = set_helper_option, .get_refs_list = get_refs_list, .fetch_refs = fetch_refs, .push_refs = push_refs, + .get_features = get_features, .connect = connect_helper, .disconnect = release_helper }; diff --git a/transport-internal.h b/transport-internal.h index c4ca0b733ac..759c79148db 100644 --- a/transport-internal.h +++ b/transport-internal.h @@ -5,6 +5,7 @@ struct ref; struct transport; struct strvec; struct transport_ls_refs_options; +struct string_list; struct transport_vtable { /** @@ -51,6 +52,14 @@ struct transport_vtable { * process involved generating new commits. **/ int (*push_refs)(struct transport *transport, struct ref *refs, int flags); + + /** + * get_features() requests a list of recommended features and + * populates the given string_list with those 'key=value' pairs. + */ + int (*get_features)(struct transport *transport, + struct string_list *list); + int (*connect)(struct transport *connection, const char *name, const char *executable, int fd[2]); diff --git a/transport.c b/transport.c index 2a3e3241545..99d6b719f35 100644 --- a/transport.c +++ b/transport.c @@ -349,6 +349,20 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus return handshake(transport, for_push, options, 1); } +static int get_features(struct transport *transport, + struct string_list *list) +{ + struct git_transport_data *data = transport->data; + struct packet_reader reader; + + packet_reader_init(&reader, data->fd[0], NULL, 0, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_GENTLE_ON_EOF); + + return get_recommended_features(data->fd[1], &reader, list, + transport->stateless_rpc); +} + static int fetch_refs_via_pack(struct transport *transport, int nr_heads, struct ref **to_fetch) { @@ -890,6 +904,7 @@ static struct transport_vtable taken_over_vtable = { .get_refs_list = get_refs_via_connect, .fetch_refs = fetch_refs_via_pack, .push_refs = git_transport_push, + .get_features = get_features, .disconnect = disconnect_git }; @@ -1043,6 +1058,7 @@ static struct transport_vtable builtin_smart_vtable = { .get_refs_list = get_refs_via_connect, .fetch_refs = fetch_refs_via_pack, .push_refs = git_transport_push, + .get_features = get_features, .connect = connect_git, .disconnect = disconnect_git }; @@ -1456,6 +1472,28 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs) return rc; } +struct string_list *transport_remote_features(struct transport *transport) +{ + const struct transport_vtable *vtable = transport->vtable; + struct string_list *list = NULL; + + if (!server_supports_v2("features", 0)) + return NULL; + + if (!vtable->get_features) { + warning(_("'features' not supported by this remote")); + return NULL; + } + + CALLOC_ARRAY(list, 1); + string_list_init_dup(list); + + if (vtable->get_features(transport, list)) + warning(_("failed to get recommended features from remote")); + + return list; +} + void transport_unlock_pack(struct transport *transport, unsigned int flags) { int in_signal_handler = !!(flags & TRANSPORT_UNLOCK_PACK_IN_SIGNAL_HANDLER); diff --git a/transport.h b/transport.h index 3f16e50c196..bfa2dd48d85 100644 --- a/transport.h +++ b/transport.h @@ -272,6 +272,11 @@ struct transport_ls_refs_options { const struct ref *transport_get_remote_refs(struct transport *transport, struct transport_ls_refs_options *transport_options); +/** + * Get recommended config from remote. + */ +struct string_list *transport_remote_features(struct transport *transport); + /* * Fetch the hash algorithm used by a remote. * -- gitgitgadget