Commit 37d98aaf4463db1ccb6a325409210aab799db115

Edward Thomson 2022-02-06T14:59:24

transport: transports can indicate support for fetch by oid

diff --git a/include/git2/sys/remote.h b/include/git2/sys/remote.h
new file mode 100644
index 0000000..dd243ca
--- /dev/null
+++ b/include/git2/sys/remote.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_sys_git_remote_h
+#define INCLUDE_sys_git_remote_h
+
+/**
+ * @file git2/sys/remote.h
+ * @brief Low-level remote functionality for custom transports
+ * @defgroup git_remote Low-level remote functionality
+ * @ingroup Git
+ * @{
+*/
+
+GIT_BEGIN_DECL
+
+typedef enum {
+	/** Remote supports fetching an advertised object by ID. */
+	GIT_REMOTE_CAPABILITY_TIP_OID = (1 << 0),
+
+	/** Remote supports fetching an individual reachable object. */
+	GIT_REMOTE_CAPABILITY_REACHABLE_OID = (1 << 1),
+} git_remote_capability_t;
+
+/** @} */
+GIT_END_DECL
+#endif
diff --git a/src/transports/local.c b/src/transports/local.c
index 0c768fa..6c754a0 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -28,6 +28,7 @@
 #include "git2/pack.h"
 #include "git2/commit.h"
 #include "git2/revparse.h"
+#include "git2/sys/remote.h"
 
 typedef struct {
 	git_transport parent;
@@ -260,7 +261,8 @@ static int local_capabilities(unsigned int *capabilities, git_transport *transpo
 {
 	GIT_UNUSED(transport);
 
-	*capabilities = 0;
+	*capabilities = GIT_REMOTE_CAPABILITY_TIP_OID |
+	                GIT_REMOTE_CAPABILITY_REACHABLE_OID;
 	return 0;
 }
 
diff --git a/src/transports/smart.c b/src/transports/smart.c
index 3b58b84..801fcbe 100644
--- a/src/transports/smart.c
+++ b/src/transports/smart.c
@@ -8,6 +8,7 @@
 #include "smart.h"
 
 #include "git2.h"
+#include "git2/sys/remote.h"
 #include "refs.h"
 #include "refspec.h"
 #include "proxy.h"
@@ -228,9 +229,16 @@ static int git_smart__set_connect_opts(
 
 static int git_smart__capabilities(unsigned int *capabilities, git_transport *transport)
 {
-	GIT_UNUSED(transport);
+	transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
 
 	*capabilities = 0;
+
+	if (t->caps.want_tip_sha1)
+		*capabilities |= GIT_REMOTE_CAPABILITY_TIP_OID;
+
+	if (t->caps.want_reachable_sha1)
+		*capabilities |= GIT_REMOTE_CAPABILITY_REACHABLE_OID;
+
 	return 0;
 }
 
diff --git a/src/transports/smart.h b/src/transports/smart.h
index 8860a1e..9323d6c 100644
--- a/src/transports/smart.h
+++ b/src/transports/smart.h
@@ -30,6 +30,8 @@
 #define GIT_CAP_REPORT_STATUS "report-status"
 #define GIT_CAP_THIN_PACK "thin-pack"
 #define GIT_CAP_SYMREF "symref"
+#define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want"
+#define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want"
 
 extern bool git_smart__ofs_delta_enabled;
 
@@ -128,7 +130,9 @@ typedef struct transport_smart_caps {
 	             include_tag:1,
 	             delete_refs:1,
 	             report_status:1,
-	             thin_pack:1;
+	             thin_pack:1,
+	             want_tip_sha1:1,
+	             want_reachable_sha1:1;
 } transport_smart_caps;
 
 typedef int (*packetsize_cb)(size_t received, void *payload);
diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c
index 0610281..e61c5f4 100644
--- a/src/transports/smart_protocol.c
+++ b/src/transports/smart_protocol.c
@@ -205,6 +205,18 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
 			continue;
 		}
 
+		if (!git__prefixcmp(ptr, GIT_CAP_WANT_TIP_SHA1)) {
+			caps->common = caps->want_tip_sha1 = 1;
+			ptr += strlen(GIT_CAP_DELETE_REFS);
+			continue;
+		}
+
+		if (!git__prefixcmp(ptr, GIT_CAP_WANT_REACHABLE_SHA1)) {
+			caps->common = caps->want_reachable_sha1 = 1;
+			ptr += strlen(GIT_CAP_DELETE_REFS);
+			continue;
+		}
+
 		/* We don't know this capability, so skip it */
 		ptr = strchr(ptr, ' ');
 	}