connect: discover protocol version outside of get_remote_heads
[gitweb.git] / transport.c
index 7cc39b7c0b9c547752924c82038ed0ac226a22bf..63c3dbab94216f660b422757bfbbac878066804e 100644 (file)
@@ -17,6 +17,8 @@
 #include "string-list.h"
 #include "sha1-array.h"
 #include "sigchain.h"
+#include "transport-internal.h"
+#include "protocol.h"
 
 static void set_upstreams(struct transport *transport, struct ref *refs,
        int pretend)
@@ -189,13 +191,26 @@ static int connect_setup(struct transport *transport, int for_push)
 static struct ref *get_refs_via_connect(struct transport *transport, int for_push)
 {
        struct git_transport_data *data = transport->data;
-       struct ref *refs;
+       struct ref *refs = NULL;
+       struct packet_reader reader;
 
        connect_setup(transport, for_push);
-       get_remote_heads(data->fd[0], NULL, 0, &refs,
-                        for_push ? REF_NORMAL : 0,
-                        &data->extra_have,
-                        &data->shallow);
+
+       packet_reader_init(&reader, data->fd[0], NULL, 0,
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_GENTLE_ON_EOF);
+
+       switch (discover_version(&reader)) {
+       case protocol_v1:
+       case protocol_v0:
+               get_remote_heads(&reader, &refs,
+                                for_push ? REF_NORMAL : 0,
+                                &data->extra_have,
+                                &data->shallow);
+               break;
+       case protocol_unknown_version:
+               BUG("unknown protocol version");
+       }
        data->got_remote_heads = 1;
 
        return refs;
@@ -229,12 +244,8 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.cloning = transport->cloning;
        args.update_shallow = data->options.update_shallow;
 
-       if (!data->got_remote_heads) {
-               connect_setup(transport, 0);
-               get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0,
-                                NULL, &data->shallow);
-               data->got_remote_heads = 1;
-       }
+       if (!data->got_remote_heads)
+               refs_tmp = get_refs_via_connect(transport, 0);
 
        refs = fetch_pack(&args, data->fd, data->conn,
                          refs_tmp ? refs_tmp : transport->remote_refs,
@@ -540,14 +551,8 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
        struct send_pack_args args;
        int ret;
 
-       if (!data->got_remote_heads) {
-               struct ref *tmp_refs;
-               connect_setup(transport, 1);
-
-               get_remote_heads(data->fd[0], NULL, 0, &tmp_refs, REF_NORMAL,
-                                NULL, &data->shallow);
-               data->got_remote_heads = 1;
-       }
+       if (!data->got_remote_heads)
+               get_refs_via_connect(transport, 1);
 
        memset(&args, 0, sizeof(args));
        args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
@@ -607,6 +612,15 @@ static int disconnect_git(struct transport *transport)
        return 0;
 }
 
+static struct transport_vtable taken_over_vtable = {
+       NULL,
+       get_refs_via_connect,
+       fetch_refs_via_pack,
+       git_transport_push,
+       NULL,
+       disconnect_git
+};
+
 void transport_take_over(struct transport *transport,
                         struct child_process *child)
 {
@@ -624,11 +638,7 @@ void transport_take_over(struct transport *transport,
        data->got_remote_heads = 0;
        transport->data = data;
 
-       transport->set_option = NULL;
-       transport->get_refs_list = get_refs_via_connect;
-       transport->fetch = fetch_refs_via_pack;
-       transport->push_refs = git_transport_push;
-       transport->disconnect = disconnect_git;
+       transport->vtable = &taken_over_vtable;
        transport->smart_options = &(data->options);
 
        transport->cannot_reuse = 1;
@@ -751,6 +761,24 @@ void transport_check_allowed(const char *type)
                die("transport '%s' not allowed", type);
 }
 
+static struct transport_vtable bundle_vtable = {
+       NULL,
+       get_refs_from_bundle,
+       fetch_refs_from_bundle,
+       NULL,
+       NULL,
+       close_bundle
+};
+
+static struct transport_vtable builtin_smart_vtable = {
+       NULL,
+       get_refs_via_connect,
+       fetch_refs_via_pack,
+       git_transport_push,
+       connect_git,
+       disconnect_git
+};
+
 struct transport *transport_get(struct remote *remote, const char *url)
 {
        const char *helper;
@@ -787,9 +815,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
                struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
                transport_check_allowed("file");
                ret->data = data;
-               ret->get_refs_list = get_refs_from_bundle;
-               ret->fetch = fetch_refs_from_bundle;
-               ret->disconnect = close_bundle;
+               ret->vtable = &bundle_vtable;
                ret->smart_options = NULL;
        } else if (!is_url(url)
                || starts_with(url, "file://")
@@ -804,12 +830,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
                 */
                struct git_transport_data *data = xcalloc(1, sizeof(*data));
                ret->data = data;
-               ret->set_option = NULL;
-               ret->get_refs_list = get_refs_via_connect;
-               ret->fetch = fetch_refs_via_pack;
-               ret->push_refs = git_transport_push;
-               ret->connect = connect_git;
-               ret->disconnect = disconnect_git;
+               ret->vtable = &builtin_smart_vtable;
                ret->smart_options = &(data->options);
 
                data->conn = NULL;
@@ -843,9 +864,9 @@ int transport_set_option(struct transport *transport,
                git_reports = set_git_option(transport->smart_options,
                                             name, value);
 
-       if (transport->set_option)
-               protocol_reports = transport->set_option(transport, name,
-                                                       value);
+       if (transport->vtable->set_option)
+               protocol_reports = transport->vtable->set_option(transport,
+                                                                name, value);
 
        /* If either report is 0, report 0 (success). */
        if (!git_reports || !protocol_reports)
@@ -968,7 +989,7 @@ int transport_push(struct transport *transport,
        *reject_reasons = 0;
        transport_verify_remote_names(refspec_nr, refspec);
 
-       if (transport->push_refs) {
+       if (transport->vtable->push_refs) {
                struct ref *remote_refs;
                struct ref *local_refs = get_local_heads();
                int match_flags = MATCH_REFS_NONE;
@@ -981,7 +1002,7 @@ int transport_push(struct transport *transport,
                if (check_push_refs(local_refs, refspec_nr, refspec) < 0)
                        return -1;
 
-               remote_refs = transport->get_refs_list(transport, 1);
+               remote_refs = transport->vtable->get_refs_list(transport, 1);
 
                if (flags & TRANSPORT_PUSH_ALL)
                        match_flags |= MATCH_REFS_ALL;
@@ -1056,7 +1077,7 @@ int transport_push(struct transport *transport,
                }
 
                if (!(flags & TRANSPORT_RECURSE_SUBMODULES_ONLY))
-                       push_ret = transport->push_refs(transport, remote_refs, flags);
+                       push_ret = transport->vtable->push_refs(transport, remote_refs, flags);
                else
                        push_ret = 0;
                err = push_had_errors(remote_refs);
@@ -1090,7 +1111,7 @@ int transport_push(struct transport *transport,
 const struct ref *transport_get_remote_refs(struct transport *transport)
 {
        if (!transport->got_remote_refs) {
-               transport->remote_refs = transport->get_refs_list(transport, 0);
+               transport->remote_refs = transport->vtable->get_refs_list(transport, 0);
                transport->got_remote_refs = 1;
        }
 
@@ -1127,7 +1148,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
                        heads[nr_heads++] = rm;
        }
 
-       rc = transport->fetch(transport, nr_heads, heads);
+       rc = transport->vtable->fetch(transport, nr_heads, heads);
 
        free(heads);
        return rc;
@@ -1144,8 +1165,8 @@ void transport_unlock_pack(struct transport *transport)
 int transport_connect(struct transport *transport, const char *name,
                      const char *exec, int fd[2])
 {
-       if (transport->connect)
-               return transport->connect(transport, name, exec, fd);
+       if (transport->vtable->connect)
+               return transport->vtable->connect(transport, name, exec, fd);
        else
                die("Operation not supported by protocol");
 }
@@ -1153,8 +1174,8 @@ int transport_connect(struct transport *transport, const char *name,
 int transport_disconnect(struct transport *transport)
 {
        int ret = 0;
-       if (transport->disconnect)
-               ret = transport->disconnect(transport);
+       if (transport->vtable->disconnect)
+               ret = transport->vtable->disconnect(transport);
        free(transport);
        return ret;
 }