Re: [PATCH 13/26] connect: request remote refs using v2

2018-01-09 Thread Jonathan Tan
On Tue,  2 Jan 2018 16:18:15 -0800
Brandon Williams  wrote:

> diff --git a/connect.c b/connect.c
> index caa539b75..9badd403f 100644
> --- a/connect.c
> +++ b/connect.c
> @@ -12,9 +12,11 @@
>  #include "sha1-array.h"
>  #include "transport.h"
>  #include "strbuf.h"
> +#include "version.h"
>  #include "protocol.h"
>  
>  static char *server_capabilities;
> +static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;
>  static const char *parse_feature_value(const char *, const char *, int *);
>  
>  static int check_ref(const char *name, unsigned int flags)
> @@ -62,6 +64,33 @@ static void die_initial_contact(int unexpected)
> "and the repository exists."));
>  }
>  
> +static int server_supports_v2(const char *c, int die_on_error)

Document what "c" means.

[snip]

> +static void process_capabilities_v2(struct packet_reader *reader)
> +{
> + while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
> + argv_array_push(_capabilities_v2, reader->line);
> + }

No need for braces on single-line blocks.

> +static int process_ref_v2(const char *line, struct ref ***list)

The "list" is the tail of a linked list, so maybe name it "tail"
instead.


[PATCH 13/26] connect: request remote refs using v2

2018-01-02 Thread Brandon Williams
Teach the client to be able to request a remote's refs using protocol
v2.  This is done by having a client issue a 'ls-refs' request to a v2
server.

Signed-off-by: Brandon Williams 
---
 connect.c  | 101 -
 remote.h   |   4 ++
 t/t5701-protocol-v2.sh |  28 ++
 transport.c|   2 +-
 upload-pack.c  |   9 +++--
 5 files changed, 138 insertions(+), 6 deletions(-)
 create mode 100755 t/t5701-protocol-v2.sh

diff --git a/connect.c b/connect.c
index caa539b75..9badd403f 100644
--- a/connect.c
+++ b/connect.c
@@ -12,9 +12,11 @@
 #include "sha1-array.h"
 #include "transport.h"
 #include "strbuf.h"
+#include "version.h"
 #include "protocol.h"
 
 static char *server_capabilities;
+static struct argv_array server_capabilities_v2 = ARGV_ARRAY_INIT;
 static const char *parse_feature_value(const char *, const char *, int *);
 
 static int check_ref(const char *name, unsigned int flags)
@@ -62,6 +64,33 @@ static void die_initial_contact(int unexpected)
  "and the repository exists."));
 }
 
+static int server_supports_v2(const char *c, int die_on_error)
+{
+   int i;
+
+   for (i = 0; i < server_capabilities_v2.argc; i++) {
+   const char *out;
+   if (skip_prefix(server_capabilities_v2.argv[i], c, ) &&
+   (!*out || *out == '='))
+   return 1;
+   }
+
+   if (die_on_error)
+   die("server doesn't support '%s'", c);
+
+   return 0;
+}
+
+static void process_capabilities_v2(struct packet_reader *reader)
+{
+   while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+   argv_array_push(_capabilities_v2, reader->line);
+   }
+
+   if (reader->status != PACKET_READ_FLUSH)
+   die("protocol error");
+}
+
 enum protocol_version discover_version(struct packet_reader *reader)
 {
enum protocol_version version = protocol_unknown_version;
@@ -85,7 +114,7 @@ enum protocol_version discover_version(struct packet_reader 
*reader)
/* Maybe process capabilities here, at least for v2 */
switch (version) {
case protocol_v2:
-   die("support for protocol v2 not implemented yet");
+   process_capabilities_v2(reader);
break;
case protocol_v1:
/* Read the peeked version line */
@@ -292,6 +321,76 @@ struct ref **get_remote_heads(struct packet_reader *reader,
return list;
 }
 
+static int process_ref_v2(const char *line, struct ref ***list)
+{
+   int ret = 1;
+   int i = 0;
+   struct object_id old_oid;
+   struct ref *ref;
+   struct string_list line_sections = STRING_LIST_INIT_DUP;
+
+   if (string_list_split(_sections, line, ' ', -1) < 2) {
+   ret = 0;
+   goto out;
+   }
+
+   if (get_oid_hex(line_sections.items[i++].string, _oid)) {
+   ret = 0;
+   goto out;
+   }
+
+   ref = alloc_ref(line_sections.items[i++].string);
+
+   if (i < line_sections.nr)
+   ref->symref = xstrdup(line_sections.items[i++].string);
+
+   oidcpy(>old_oid, _oid);
+   **list = ref;
+   *list = >next;
+
+out:
+   string_list_clear(_sections, 0);
+   return ret;
+}
+
+struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
+struct ref **list, int for_push,
+const struct argv_array *ref_patterns)
+{
+   int i;
+   *list = NULL;
+
+   /* Check that the server supports the ls-refs command */
+   /* Issue request for ls-refs */
+   if (server_supports_v2("ls-refs", 1))
+   packet_write_fmt(fd_out, "command=ls-refs\n");
+
+   if (server_supports_v2("agent", 0))
+   packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
+
+   packet_delim(fd_out);
+   /* When pushing we don't want to request the peeled tags */
+   if (!for_push)
+   packet_write_fmt(fd_out, "peel\n");
+   packet_write_fmt(fd_out, "symrefs\n");
+   for (i = 0; ref_patterns && i < ref_patterns->argc; i++) {
+   packet_write_fmt(fd_out, "ref-pattern %s\n",
+ref_patterns->argv[i]);
+   }
+   packet_flush(fd_out);
+
+   /* Process response from server */
+   while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+   if (!process_ref_v2(reader->line, ))
+   die("invalid ls-refs response: %s", reader->line);
+   }
+
+   if (reader->status != PACKET_READ_FLUSH)
+   die("protocol error");
+
+   return list;
+}
+
 static const char *parse_feature_value(const char *feature_list, const char 
*feature, int *lenp)
 {
int len;
diff --git a/remote.h b/remote.h
index 2016461df..21d0c776c 100644
--- a/remote.h
+++ b/remote.h
@@ -151,10 +151,14 @@