Re: [WIP 12/15] ls-refs: introduce ls-refs server command

2017-12-13 Thread Philip Oakley

From: "Brandon Williams" 
Sent: Monday, December 04, 2017 11:58 PM

Introduce the ls-refs server command.  In protocol v2, the ls-refs
command is used to request the ref advertisement from the server.  Since
it is a command which can be requested (as opposed to manditory in v1),
a clinet can sent a number of parameters in its request to limit the ref


s/clinet/client/


advertisement based on provided ref-patterns.

Signed-off-by: Brandon Williams 
---

Philip


[WIP 12/15] ls-refs: introduce ls-refs server command

2017-12-04 Thread Brandon Williams
Introduce the ls-refs server command.  In protocol v2, the ls-refs
command is used to request the ref advertisement from the server.  Since
it is a command which can be requested (as opposed to manditory in v1),
a clinet can sent a number of parameters in its request to limit the ref
advertisement based on provided ref-patterns.

Signed-off-by: Brandon Williams 
---
 Makefile  |  1 +
 ls-refs.c | 96 +++
 ls-refs.h |  9 ++
 serve.c   |  8 ++
 4 files changed, 114 insertions(+)
 create mode 100644 ls-refs.c
 create mode 100644 ls-refs.h

diff --git a/Makefile b/Makefile
index 710672cf4..be3c2f98b 100644
--- a/Makefile
+++ b/Makefile
@@ -807,6 +807,7 @@ LIB_OBJS += list-objects.o
 LIB_OBJS += ll-merge.o
 LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
+LIB_OBJS += ls-refs.o
 LIB_OBJS += mailinfo.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
diff --git a/ls-refs.c b/ls-refs.c
new file mode 100644
index 0..591dd105d
--- /dev/null
+++ b/ls-refs.c
@@ -0,0 +1,96 @@
+#include "cache.h"
+#include "repository.h"
+#include "refs.h"
+#include "remote.h"
+#include "argv-array.h"
+#include "ls-refs.h"
+#include "pkt-line.h"
+
+struct ls_refs_data {
+   unsigned peel;
+   unsigned symrefs;
+   struct argv_array patterns;
+};
+
+/*
+ * Is there one among the list of patterns that match the tail part
+ * of the path?
+ */
+static int tail_match(const char **pattern, const char *path)
+{
+   const char *p;
+   char *pathbuf;
+
+   if (!pattern)
+   return 1; /* no restriction */
+
+   pathbuf = xstrfmt("/%s", path);
+   while ((p = *(pattern++)) != NULL) {
+   if (!wildmatch(p, pathbuf, 0)) {
+   free(pathbuf);
+   return 1;
+   }
+   }
+   free(pathbuf);
+   return 0;
+}
+
+static int send_ref(const char *refname, const struct object_id *oid,
+   int flag, void *cb_data)
+{
+   struct ls_refs_data *data = cb_data;
+   const char *refname_nons = strip_namespace(refname);
+   struct strbuf refline = STRBUF_INIT;
+
+   if (data->patterns.argc && !tail_match(data->patterns.argv, refname))
+   return 0;
+
+   strbuf_addf(, "%s %s", oid_to_hex(oid), refname_nons);
+   if (data->symrefs && flag & REF_ISSYMREF) {
+   struct object_id unused;
+   const char *symref_target = resolve_ref_unsafe(refname, 0,
+  unused.hash,
+  );
+
+   if (!symref_target)
+   die("'%s' is a symref but it is not?", refname);
+
+   strbuf_addf(, " %s", symref_target);
+   }
+
+   strbuf_addch(, '\n');
+
+   packet_write(1, refline.buf, refline.len);
+   if (data->peel) {
+   struct object_id peeled;
+   if (!peel_ref(refname, peeled.hash))
+   packet_write_fmt(1, "%s %s^{}\n", oid_to_hex(),
+refname_nons);
+   }
+
+   strbuf_release();
+   return 0;
+}
+
+int ls_refs(struct repository *r, struct argv_array *keys, struct argv_array 
*args)
+{
+   int i;
+   struct ls_refs_data data = { 0, 0, ARGV_ARRAY_INIT };
+
+   for (i = 0; i < args->argc; i++) {
+   if (!strcmp("--peeled", args->argv[i]))
+   data.peel = 1;
+   else if (!strcmp("--symrefs", args->argv[i]))
+   data.symrefs = 1;
+   else
+   /* Pattern */
+   argv_array_pushf(, "*/%s", args->argv[i]);
+
+   }
+
+   head_ref_namespaced(send_ref, );
+   for_each_namespaced_ref(send_ref, );
+   packet_flush(1);
+   argv_array_clear();
+   return 0;
+}
diff --git a/ls-refs.h b/ls-refs.h
new file mode 100644
index 0..9e4c57bfe
--- /dev/null
+++ b/ls-refs.h
@@ -0,0 +1,9 @@
+#ifndef LS_REFS_H
+#define LS_REFS_H
+
+struct repository;
+struct argv_array;
+extern int ls_refs(struct repository *r, struct argv_array *keys,
+  struct argv_array *args);
+
+#endif /* LS_REFS_H */
diff --git a/serve.c b/serve.c
index 476e73b54..36f77c365 100644
--- a/serve.c
+++ b/serve.c
@@ -4,8 +4,15 @@
 #include "pkt-line.h"
 #include "version.h"
 #include "argv-array.h"
+#include "ls-refs.h"
 #include "serve.h"
 
+static int always_advertise(struct repository *r,
+   struct strbuf *value)
+{
+   return 1;
+}
+
 static int agent_advertise(struct repository *r,
   struct strbuf *value)
 {
@@ -26,6 +33,7 @@ struct protocol_capability {
 
 static struct protocol_capability capabilities[] = {
{ "agent", 0, agent_advertise, NULL },
+   { "ls-refs", 0, always_advertise, ls_refs },
 };
 
 static void advertise_capabilities(void)
--