[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