hgext/clonebundles.py
changeset 26623 5a95fe44121d
child 26644 74de1c59f71c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/clonebundles.py	Fri Oct 09 11:22:01 2015 -0700
@@ -0,0 +1,69 @@
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+"""server side extension to advertise pre-generated bundles to seed clones.
+
+The extension essentially serves the content of a .hg/clonebundles.manifest
+file to clients that request it.
+
+The clonebundles.manifest file contains a list of URLs and attributes. URLs
+hold pre-generated bundles that a client fetches and applies. After applying
+the pre-generated bundle, the client will connect back to the original server
+and pull data not in the pre-generated bundle.
+
+Manifest File Format:
+
+The manifest file contains a newline (\n) delimited list of entries.
+
+Each line in this file defines an available bundle. Lines have the format:
+
+    <URL> [<key>=<value]
+
+That is, a URL followed by extra metadata describing it. Metadata keys and
+values should be URL encoded.
+
+This metadata is optional. It is up to server operators to populate this
+metadata.
+
+Keys in UPPERCASE are reserved for use by Mercurial. All non-uppercase keys
+can be used by site installations.
+
+The server operator is responsible for generating the bundle manifest file.
+
+Metadata Attributes:
+
+TBD
+"""
+
+from mercurial import (
+    extensions,
+    wireproto,
+)
+
+testedwith = 'internal'
+
+def capabilities(orig, repo, proto):
+    caps = orig(repo, proto)
+
+    # Only advertise if a manifest exists. This does add some I/O to requests.
+    # But this should be cheaper than a wasted network round trip due to
+    # missing file.
+    if repo.opener.exists('clonebundles.manifest'):
+        caps.append('clonebundles')
+
+    return caps
+
+@wireproto.wireprotocommand('clonebundles', '')
+def bundles(repo, proto):
+    """Server command for returning info for available bundles to seed clones.
+
+    Clients will parse this response and determine what bundle to fetch.
+
+    Other extensions may wrap this command to filter or dynamically emit
+    data depending on the request. e.g. you could advertise URLs for
+    the closest data center given the client's IP address.
+    """
+    return repo.opener.tryread('clonebundles.manifest')
+
+def extsetup(ui):
+    extensions.wrapfunction(wireproto, '_capabilities', capabilities)