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

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


changeset:   54:ccfac5e72669
user:        Simon Law <simon at akoha.org>
date:        Mon Jul 16 11:44:42 2007 -0400
files:       forest.py test-forest.out
description:
Cloning a forest is now possible over static HTTP.


diff -r 5f46981d6b9c -r ccfac5e72669 forest.py
--- a/forest.py	Tue Jul 10 16:21:50 2007 -0400
+++ b/forest.py	Mon Jul 16 11:44:42 2007 -0400
@@ -49,7 +49,7 @@ import re
 import re
 
 from mercurial import commands, hg, node, util
-from mercurial import localrepo, sshrepo, sshserver, httprepo
+from mercurial import localrepo, sshrepo, sshserver, httprepo, statichttprepo
 from mercurial.hgweb import hgweb_mod
 if not hasattr(commands, "findcmd"):
     from mercurial.cmdutil import findcmd
@@ -220,6 +220,88 @@ hgweb_mod.hgweb.do_forests = _httpserver
 hgweb_mod.hgweb.do_forests = _httpserver_do_forests
 
 
+def _statichttprepo_forests(self, walkhg):
+    """Shim this function into
+    mercurial.statichttprepo.statichttprepository so that it gives you
+    the list of subforests.
+
+    It depends on the fact that most directory indices have directory
+    names followed by a slash.  There is no reliable way of telling
+    whether a link leads into a subdirectory.
+
+    Return a list of roots in filesystem representation relative to
+    the self repository.  This list is lexigraphically sorted.
+    """
+
+    import HTMLParser
+    import string
+    import urllib
+    import urllib2
+    import urlparse
+
+    class HtmlIndexParser(HTMLParser.HTMLParser):
+        def __init__(self, ui, paths, walkhg):
+            self._paths = paths
+            self._ui = ui
+            self._walkhg = walkhg
+            self.current = None
+        def handle_starttag(self, tag, attrs):
+            if string.lower(tag) == "a":
+                for attr in attrs:
+                    if (string.lower(attr[0]) == "href" and
+                        attr[1].endswith('/')):
+                        link = urlparse.urlsplit(attr[1])
+                        if (not self._walkhg and
+                            link[2].rstrip('/').split('/')[-1] == '.hg'):
+                            break
+                        if not link[0] and not link[2].startswith('/'):
+                            self._ui.debug(_("matched on '%s'") % attr[1])
+                            self._paths.append(urlparse.urljoin(self.current,
+                                                                attr[1]))
+
+    if self._url.endswith('/'):
+        url = self._url
+    else:
+        url = self._url + '/'
+
+    res = []
+    paths = [url]
+    seen = {}
+
+    parser = HtmlIndexParser(self.ui, paths, walkhg)
+    while paths:
+        path = paths.pop()
+        if not seen.has_key(path):
+            seen[path] = True
+            parser.current = path
+            index = None
+            try:
+                self.ui.debug(_("retrieving '%s'\n") % path)
+                index = urllib2.urlopen(path)
+                parser.reset()
+                parser.feed(index.read())
+                parser.close()
+                hg_path = urlparse.urljoin(path, '.hg')
+                self.ui.debug(_("retrieving '%s'\n") % hg_path)
+                hg = urllib2.urlopen(hg_path)
+                res.append(path)
+            except urllib2.HTTPError, inst:
+                pass
+                #raise IOError(None, inst)
+            except urllib2.URLError, inst:
+                pass
+                #raise IOError(None, inst.reason[1])
+
+    res.sort()
+    # Turn things into relative paths
+    result = []
+    for root in res:
+        result.append(root[len(url):].rstrip('/') or ".")
+    return result
+
+statichttprepo.statichttprepository.forests = _statichttprepo_forests
+
+
 tree_section_re = re.compile(r"^tree(\w+)$")
 
 def tree_sections(cfg, withtop=True):
@@ -362,7 +444,7 @@ class ForestSnapshot(object):
             if mq_fatal and mq_patches_applied(abspath):
                 raise util.Abort(_("'%s' has mq patches applied") % relpath)
             if tip:
-                rev = 'tip'
+                rev = None
             else:
                 rev = node.hex(repo.dirstate.parents()[0])
             paths = dict(repo.ui.configitems('paths'))
@@ -397,7 +479,10 @@ def clone(ui, source, dest, walkhg, **op
             destpfx = os.path.dirname(destpath)
             if not os.path.exists(destpfx):
                 os.makedirs(destpfx)
-        opts['rev'] = [rev]
+        if rev:
+            opts['rev'] = [rev]
+        else:
+            opts['rev'] = []
         url = repo.url()
         if hasattr(repo, "root"):
             url = repo.root
@@ -405,7 +490,7 @@ def clone(ui, source, dest, walkhg, **op
 
     snapshot = ForestSnapshot()
     repo = hg.repository(ui, source)
-    snapshot.update(ui, repo, isinstance(repo, localrepo.localrepository),
+    snapshot.update(ui, repo, hasattr(repo, "root"),
                     walkhgenabled(ui, walkhg), True)
     snapshot(ui, repo, doit, mq_check=False)
 
diff -r 5f46981d6b9c -r ccfac5e72669 test-forest.out
--- a/test-forest.out	Tue Jul 10 16:21:50 2007 -0400
+++ b/test-forest.out	Mon Jul 16 11:44:42 2007 -0400
@@ -37,43 +37,18 @@ M f
 
 # fclone
 [.]
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 1 changesets with 3 changes to 3 files
 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 [d/d/t]
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-[e/d]
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-[t]
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-
-[t/t]
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 1 changesets with 1 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+[e/d]
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+[t]
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+[t/t]
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 # fsnap



More information about the CIG-COMMITS mailing list