largefiles: add support for 'largefiles://' url scheme
authorBoris Feld <boris.feld@octobus.net>
Thu, 21 Dec 2017 13:57:57 +0100
changeset 35564 cf841f2b5a72
parent 35563 4aa6ed598323
child 35565 bdae51a83dfb
largefiles: add support for 'largefiles://' url scheme This changesets allows Mercurial to transparently download content from the configured largefile store. This handle all authentication and largefile protocol details. The target usecase is to leverage largefile infrastructure for clone bundle. See next changeset for details
hgext/largefiles/overrides.py
hgext/largefiles/remotestore.py
hgext/largefiles/storefactory.py
hgext/largefiles/uisetup.py
tests/test-url-download.t
--- a/hgext/largefiles/overrides.py	Thu Dec 21 13:53:26 2017 +0100
+++ b/hgext/largefiles/overrides.py	Thu Dec 21 13:57:57 2017 +0100
@@ -1479,3 +1479,14 @@
     if 'largefiles' in repo.requirements:
         reqs.add('largefiles')
     return reqs
+
+_lfscheme = 'largefile://'
+def openlargefile(orig, ui, url_, data=None):
+    if url_.startswith(_lfscheme):
+        if data:
+            msg = "cannot use data on a 'largefile://' url"
+            raise error.ProgrammingError(msg)
+        lfid = url_[len(_lfscheme):]
+        return storefactory.getlfile(ui, lfid)
+    else:
+        return orig(ui, url_, data=data)
--- a/hgext/largefiles/remotestore.py	Thu Dec 21 13:53:26 2017 +0100
+++ b/hgext/largefiles/remotestore.py	Thu Dec 21 13:57:57 2017 +0100
@@ -27,7 +27,9 @@
     '''a largefile store accessed over a network'''
     def __init__(self, ui, repo, url):
         super(remotestore, self).__init__(ui, repo, url)
-        self._lstore = localstore.localstore(self.ui, self.repo, self.repo)
+        self._lstore = None
+        if repo is not None:
+            self._lstore = localstore.localstore(self.ui, self.repo, self.repo)
 
     def put(self, source, hash):
         if self.sendfile(source, hash):
--- a/hgext/largefiles/storefactory.py	Thu Dec 21 13:53:26 2017 +0100
+++ b/hgext/largefiles/storefactory.py	Thu Dec 21 13:57:57 2017 +0100
@@ -22,8 +22,9 @@
 # During clone this function is passed the src's ui object
 # but it needs the dest's ui object so it can read out of
 # the config file. Use repo.ui instead.
-def openstore(repo, remote=None, put=False):
-    ui = repo.ui
+def openstore(repo=None, remote=None, put=False, ui=None):
+    if ui is None:
+        ui = repo.ui
 
     if not remote:
         lfpullsource = getattr(repo, 'lfpullsource', None)
@@ -37,12 +38,16 @@
         # ui.expandpath() leaves 'default-push' and 'default' alone if
         # they cannot be expanded: fallback to the empty string,
         # meaning the current directory.
-        if path == 'default-push' or path == 'default':
+        if repo is None:
+            path = ui.expandpath('default')
+            path, _branches = hg.parseurl(path)
+            remote = hg.peer(repo or ui, {}, path)
+        elif path == 'default-push' or path == 'default':
             path = ''
             remote = repo
         else:
             path, _branches = hg.parseurl(path)
-            remote = hg.peer(repo, {}, path)
+            remote = hg.peer(repo or ui, {}, path)
 
     # The path could be a scheme so use Mercurial's normal functionality
     # to resolve the scheme to a repository and use its path
@@ -76,3 +81,6 @@
     }
 
 _scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
+
+def getlfile(ui, hash):
+    return util.chunkbuffer(openstore(ui=ui)._get(hash))
--- a/hgext/largefiles/uisetup.py	Thu Dec 21 13:53:26 2017 +0100
+++ b/hgext/largefiles/uisetup.py	Thu Dec 21 13:57:57 2017 +0100
@@ -31,6 +31,7 @@
     sshpeer,
     subrepo,
     upgrade,
+    url,
     wireproto,
 )
 
@@ -160,6 +161,9 @@
     extensions.wrapfunction(scmutil, 'marktouched',
                             overrides.scmutilmarktouched)
 
+    extensions.wrapfunction(url, 'open',
+                            overrides.openlargefile)
+
     # create the new wireproto commands ...
     wireproto.commands['putlfile'] = (proto.putlfile, 'sha')
     wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
--- a/tests/test-url-download.t	Thu Dec 21 13:53:26 2017 +0100
+++ b/tests/test-url-download.t	Thu Dec 21 13:57:57 2017 +0100
@@ -34,3 +34,21 @@
   $ hg debugdownload ./null.txt
   1 0000000000000000000000000000000000000000
 
+Test largefile URL
+------------------
+
+  $ cat << EOF >> $HGRCPATH
+  > [extensions]
+  > largefiles=
+  > EOF
+
+  $ killdaemons.py
+  $ rm -f error.log hg1.pid
+  $ hg serve -R server -p $HGPORT -d --pid-file=hg1.pid -E error.log
+  $ cat hg1.pid >> $DAEMON_PIDS
+
+  $ hg -R server debuglfput null.txt
+  a57b57b39ee4dc3da1e03526596007f480ecdbe8
+
+  $ hg --traceback debugdownload "largefile://a57b57b39ee4dc3da1e03526596007f480ecdbe8" --config paths.default=http://localhost:$HGPORT/
+  1 0000000000000000000000000000000000000000