changeset 26691:23c0da28c034

clonebundles: advertise clone bundles feature to clients Server operators that have enabled clone bundles probably want clients to use it. This patch introduces a feature that will insert a bundle2 "output" part that advertises the existence of the clone bundles feature to clients that aren't using it. The server uses the "cbattempted" argument to "getbundle" to determine whether a client supports clone bundles and to avoid sending the message to clients that failed the clone bundle for whatever reason.
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 14 Oct 2015 11:05:53 -0700
parents 704818fb170d
children 8d1cfd77b64f
files hgext/clonebundles.py tests/test-clonebundles.t
diffstat 2 files changed, 53 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/clonebundles.py	Wed Oct 14 10:36:20 2015 -0700
+++ b/hgext/clonebundles.py	Wed Oct 14 11:05:53 2015 -0700
@@ -64,7 +64,10 @@
    Value should be "true".
 """
 
+from mercurial.i18n import _
+from mercurial.node import nullid
 from mercurial import (
+    exchange,
     extensions,
     wireproto,
 )
@@ -94,5 +97,44 @@
     """
     return repo.opener.tryread('clonebundles.manifest')
 
+@exchange.getbundle2partsgenerator('clonebundlesadvertise', 0)
+def advertiseclonebundlespart(bundler, repo, source, bundlecaps=None,
+                              b2caps=None, heads=None, common=None,
+                              cbattempted=None, **kwargs):
+    """Inserts an output part to advertise clone bundles availability."""
+    # Allow server operators to disable this behavior.
+    # # experimental config: ui.clonebundleadvertise
+    if not repo.ui.configbool('ui', 'clonebundleadvertise', True):
+        return
+
+    # Only advertise if a manifest is present.
+    if not repo.opener.exists('clonebundles.manifest'):
+        return
+
+    # And when changegroup data is requested.
+    if not kwargs.get('cg', True):
+        return
+
+    # And when the client supports clone bundles.
+    if cbattempted is None:
+        return
+
+    # And when the client didn't attempt a clone bundle as part of this pull.
+    if cbattempted:
+        return
+
+    # And when a full clone is requested.
+    # Note: client should not send "cbattempted" for regular pulls. This check
+    # is defense in depth.
+    if common and common != [nullid]:
+        return
+
+    msg = _('this server supports the experimental "clone bundles" feature '
+            'that should enable faster and more reliable cloning\n'
+            'help test it by setting the "experimental.clonebundles" config '
+            'flag to "true"')
+
+    bundler.newpart('output', data=msg)
+
 def extsetup(ui):
     extensions.wrapfunction(wireproto, '_capabilities', capabilities)
--- a/tests/test-clonebundles.t	Wed Oct 14 10:36:20 2015 -0700
+++ b/tests/test-clonebundles.t	Wed Oct 14 11:05:53 2015 -0700
@@ -64,6 +64,17 @@
   adding file changes
   added 2 changesets with 2 changes to 2 files
 
+Server advertises presence of feature to client requesting full clone
+
+  $ hg --config experimental.clonebundles=false clone -U http://localhost:$HGPORT advertise-on-clone
+  requesting all changes
+  remote: this server supports the experimental "clone bundles" feature that should enable faster and more reliable cloning
+  remote: help test it by setting the "experimental.clonebundles" config flag to "true"
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+
 Manifest file with invalid URL aborts
 
   $ echo 'http://does.not.exist/bundle.hg' > server/.hg/clonebundles.manifest