hg site extension
 
(Arne Babenhauserheide)
2012-08-11: get incoming changes from any kind of remote repo which can be

get incoming changes from any kind of remote repo which can be cloned - except for ftp repos, because those are likely site repos which get accessed via http.

diff --git a/staticsite.py b/staticsite.py
--- a/staticsite.py
+++ b/staticsite.py
@@ -139,7 +139,7 @@ def writeoverview(ui, repo, target, name
         overview += " | " + _("forks: ")
         for forkname, forkuri in forks.items():
             overview += "<a href='" + getforkdir(target, forkname) + "'>" + forkname + "</a> "
-            incoming, fn = getincoming(ui, repo, forkuri)
+            incoming, fn, localother = getincoming(ui, repo, otheruri=forkuri, othername=forkname)
             overview += "<small>(" + str(len(incoming))
             outgoing, fn = getoutgoing(ui, repo, forkuri)
             overview += "<small>↓↑</small>" + str(len(outgoing)) + ")</small> "
@@ -256,13 +256,39 @@ def writelog(ui, repo, target, name):
             with open(filepath, "w") as f: 
                 f.write(data)
 
-def getincoming(ui, repo, otheruri, other=None):
+def getlocalother(repo, ui, otheruri, othername):
+    """Get a local clone of the repo identified by uri and name within .hg/paths.
+
+    This creates that local clone!
+    """
+    # if we cannot get the changes via bundlerepo, we create a
+    # local clone in .hg/paths/<othername>-<sha1-of-otheruri> and
+    # check from there.  in case that local clone already exists,
+    # we tell it to pull there.  The hash is necessary to prevent
+    # collisions when the uri changes.
+    if othername is None:
+        othername = ""
+    urihash = util.sha1(otheruri).hexdigest()
+    localcopy = os.path.join(repo.root, ".hg", "paths", 
+                     othername+"-"+urihash)
+    # if getting remote changes directly fails, we take the
+    # completely safe path: dispatch uses the only really stable
+    # interface: the cli.
+    if os.path.isdir(localcopy):
+        req = dispatch.request(["-R", localcopy, "pull", otheruri])
+    else:
+        req = dispatch.request(["clone", otheruri, localcopy], ui=ui)
+    dispatch.dispatch(req)
+    other = hg.peer(repo, {}, localcopy)
+    return other
+
+def getincoming(ui, repo, otheruri, other=None, othername=None):
     # cannot do that for ftp repos, yet
-    if otheruri.startswith("ftp://") or otheruri.startswith("freenet://"):
+    if otheruri.startswith("ftp://"):# or otheruri.startswith("freenet://"):
         chlist = []
         def cleanupfn():
             pass
-        return chlist, cleanupfn
+        return chlist, cleanupfn, other
 
     if not other:
         other = hg.peer(repo, {}, otheruri)
@@ -274,12 +300,13 @@ def getincoming(ui, repo, otheruri, othe
     try: # FIXME: This breaks on http repos! 
         other, chlist, cleanupfn = hg.bundlerepo.getremotechanges(ui, repo, other,
                                                                revs, False, False)
-    except AttributeError:
-        chlist = []
-        def cleanupfn():
-            pass
+    except (AttributeError, util.Abort):
+        other = getlocalother(repo, ui, otheruri, othername)
+        other, chlist, cleanupfn = hg.bundlerepo.getremotechanges(ui, repo, other,
+                                                               revs, False, False)
+        
     ui.popbuffer()
-    return chlist, cleanupfn
+    return chlist, cleanupfn, other
 
 def getoutgoing(ui, repo, otheruri, other=None):
     # cannot do that for ftp repos, yet
@@ -334,11 +361,11 @@ def getforkdata(ui, repo, target, name, 
 
     # Add incoming commits
     html += "<div id='incoming'><h2>Incoming commits</h2>"
-    chlist, cleanupfn = getincoming(ui, repo, forkuri, other=other)
+    chlist, cleanupfn, localother = getincoming(ui, repo, otheruri=forkuri, other=other, othername=forkname)
     
     ui.pushbuffer()
     for ch in chlist:
-        ctx = other.changectx(ch)
+        ctx = localother.changectx(ch)
         t.show(ctx)
     html += ui.popbuffer()
     cleanupfn()