[cig-commits] commit: Cloning a forest is now possible over SSH.

Mercurial hg at geodynamics.org
Mon Nov 24 11:27:04 PST 2008


changeset:   48:d8e40f82bb3d
user:        Simon Law <simon at akoha.org>
date:        Mon Jul 09 17:46:20 2007 -0400
files:       forest.py
description:
Cloning a forest is now possible over SSH.


diff -r 7ed36c52acd0 -r d8e40f82bb3d forest.py
--- a/forest.py	Wed Jun 13 12:36:37 2007 +0200
+++ b/forest.py	Mon Jul 09 17:46:20 2007 -0400
@@ -49,6 +49,7 @@ import re
 import re
 
 from mercurial import commands, hg, node, util
+from mercurial import localrepo, httprepo, sshrepo, sshserver
 if not hasattr(commands, "findcmd"):
     from mercurial.cmdutil import findcmd
 else:
@@ -84,13 +85,22 @@ def enumerate_repos(ui, top, walkhg):
 
     Return a list of roots in filesystem representation.
     """
+    return top.forests(walkhg)
+
+def _localrepo_forests(self, walkhg):
+    """Shim this function into mercurial.localrepo.localrepository so
+    that it gives you the list of subforests.
+
+    Return a list of roots in filesystem representation relative to
+    the self repository.
+    """
 
     def errhandler(err):
-        if err.filename == top:
+        if err.filename == self.root:
             raise err
 
     res = []
-    paths = [top]
+    paths = [self.root]
     while paths:
         path = paths.pop()
         for root, dirs, files in os.walk(path, onerror=errhandler):
@@ -111,7 +121,71 @@ def enumerate_repos(ui, top, walkhg):
                 if os.path.isdir(os.path.join(path, '.hg')):
                     res.append(path)
     res.sort()
+    # Turn things into relative paths
+    pfx = len(self.root) + 1
+    res = [r[pfx:] or "." for r in res]
     return res
+
+localrepo.localrepository.forests = _localrepo_forests
+
+
+def _sshrepo_forests(self, walkhg):
+    """Shim this function into mercurial.sshrepo.sshrepository so
+    that it gives you the list of subforests.
+
+    Return a list of roots as ssh:// URLs.
+    """
+    if 'forests' not in self.capabilities:
+        raise util.Abort(_("Remote forests cannot be cloned because the other repository doesn't support the forest extension."))
+    data = self.call("forests", walkhg=("", "True")[walkhg])
+    print data
+    return data.splitlines()
+
+sshrepo.sshrepository.forests = _sshrepo_forests
+
+
+def _sshserver_do_hello(self):
+    '''the hello command returns a set of lines describing various
+    interesting things about the server, in an RFC822-like format.
+    Currently the only one defined is "capabilities", which
+    consists of a line in the form:
+    
+    capabilities: space separated list of tokens
+    '''
+
+    caps = ['unbundle', 'lookup', 'changegroupsubset', 'forests']
+    if self.ui.configbool('server', 'uncompressed'):
+        caps.append('stream=%d' % self.repo.revlogversion)
+    self.respond("capabilities: %s\n" % (' '.join(caps),))
+
+sshserver.sshserver.do_hello = _sshserver_do_hello
+
+
+def _sshserver_do_forests(self):
+    key, walkhg = self.getarg()
+    f = self.repo.forests(bool(walkhg))
+    self.respond("\n".join(f))
+
+sshserver.sshserver.do_forests = _sshserver_do_forests
+
+
+
+def _httprepo_forests(self, walkhg):
+    """Shim this function into mercurial.httprepo.httprepository so
+    that it gives you the list of subforests.
+
+    Return a list of roots as http:// URLs.
+    """
+    if 'forests' not in self.capabilities:
+        raise util.Abort(_("Remote forests cannot be cloned because the other repository doesn't support the forest extension."))
+    d = self.do_read("forests", walkhg=("", "True")[walkhg])
+    success, data = d[:-1].split(" ", 1)
+    if int(success):
+        return data.splitlines()
+    else:
+        self.raise_(hg.RepoError(data))
+
+httprepo.httprepository.forests = _httprepo_forests
 
 
 tree_section_re = re.compile(r"^tree(\w+)$")
@@ -138,6 +212,10 @@ def tree_sections(cfg, withtop=True):
 
 
 def mq_patches_applied(rpath):
+    if rpath.startswith("file:"):
+        rpath = rpath[len("file:"):]
+    else:
+        raise util.Abort(_("'%s' does not start with file:") % rpath)
     rpath = os.path.join(rpath, ".hg")
     entries = os.listdir(rpath)
     for e in entries:
@@ -203,7 +281,7 @@ class ForestSnapshot(object):
         """
 
         repo = None
-        pfx = toprepo.root
+        pfx = toprepo.url()
         for t in self.trees:
             root, rev, path = t.info(pathalias)
             ui.write("[%s]\n" % root)
@@ -221,7 +299,7 @@ class ForestSnapshot(object):
                     ui.write(_("skipped, no valid repo found\n\n"))
                     continue
             func(repo, root, path, rev,
-                 mq_check and mq_patches_applied(repo.root))
+                 mq_check and mq_patches_applied(repo.url()))
             ui.write("\n")
 
 
@@ -237,26 +315,27 @@ class ForestSnapshot(object):
 
         rootmap = {}
         self.trees = []
-        pfxlen = len(repo.root + os.sep)
-        for rpath in enumerate_repos(ui, repo.root, walkhg):
-            root = util.pconvert(rpath[pfxlen:])
-            if root == '':
-                root = '.'
-            else:
-                repo = hg.repository(ui, rpath)
-            if mq_fatal and mq_patches_applied(rpath):
-                raise util.Abort(_("'%s' has mq patches applied") % root)
+        top = repo.url()
+        for f in repo.forests(walkhg):
+            relpath = util.pconvert(f)
+            if f == ".":
+                f = ""
+            abspath = os.sep.join((top, f))
+            if relpath != '.':
+                repo = hg.repository(ui, abspath)
+            if mq_fatal and mq_patches_applied(abspath):
+                raise util.Abort(_("'%s' has mq patches applied") % abspath)
             if tip:
                 rev = 'tip'
             else:
                 rev = node.hex(repo.dirstate.parents()[0])
             paths = dict(repo.ui.configitems('paths'))
-            if self.rootmap.has_key(root):
-                tree = self.rootmap[root]
+            if self.rootmap.has_key(relpath):
+                tree = self.rootmap[relpath]
                 tree.update(rev, paths)
             else:
-                tree = ForestSnapshot.Tree(root, rev, paths)
-            rootmap[root] = tree
+                tree = ForestSnapshot.Tree(relpath, rev, paths)
+            rootmap[relpath] = tree
             self.trees.append(tree)
         self.rootmap = rootmap
 
@@ -271,7 +350,7 @@ class ForestSnapshot(object):
 
 
 def clone(ui, source, dest, walkhg, **opts):
-    """Clone a local forest."""
+    """Clone a forest."""
     dest = os.path.normpath(dest)
 
     def doit(repo, root, path, rev, *unused):
@@ -283,11 +362,11 @@ def clone(ui, source, dest, walkhg, **op
             if not os.path.exists(destpfx):
                 os.makedirs(destpfx)
         opts['rev'] = [rev]
-        commands.clone(ui, repo.root, destpath, **opts)
+        commands.clone(ui, repo.url(), destpath, **opts)
 
     snapshot = ForestSnapshot()
     repo = hg.repository(ui, source)
-    snapshot.update(ui, repo, True, walkhgenabled(ui, walkhg))
+    snapshot.update(ui, repo, False, walkhgenabled(ui, walkhg), True)
     snapshot(ui, repo, doit, mq_check=False)
 
 



More information about the CIG-COMMITS mailing list