[PATCH] subrepo: transfer .hg/subpaths on clone and pull

Martin Geisler mg at lazybytes.net
Thu Sep 2 05:28:11 CDT 2010


# HG changeset patch
# User Martin Geisler <mg at lazybytes.net>
# Date 1283423274 -7200
# Node ID c207b5e0b8ff229b8efe7c5af039dd6097aae4f7
# Parent  be9c4131a8f4b9d90671ce13b151c3627ddb6904
subrepo: transfer .hg/subpaths on clone and pull

The automatic transfer of this file lets the owner of a repository
distribute a consistent remapping of the .hgsub file to all clones.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -9,8 +9,8 @@
 from lock import release
 from i18n import _, gettext
 import os, re, sys, difflib, time, tempfile
-import hg, util, revlog, bundlerepo, extensions, copies, error
-import patch, help, mdiff, url, encoding, templatekw, discovery
+import hg, util, revlog, bundlerepo, extensions, copies, error, config
+import patch, help, mdiff, url, encoding, templatekw, discovery, subrepo
 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
 import merge as mergemod
 import minirst, revset
@@ -2823,6 +2823,8 @@
     modheads = repo.pull(other, heads=revs, force=opts.get('force'))
     if checkout:
         checkout = str(repo.changelog.rev(other.lookup(checkout)))
+
+    subrepo.transfersubpaths(ui, repo, other)
     return postincoming(ui, repo, modheads, opts.get('update'), checkout)
 
 def push(ui, repo, dest=None, **opts):
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -75,7 +75,7 @@
 
     @propertycache
     def substate(self):
-        return subrepo.state(self, self._repo.ui)
+        return subrepo.state(self, self._repo, self._repo.ui)
 
     def __contains__(self, key):
         return key in self._manifest
diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -9,7 +9,7 @@
 from i18n import _
 from lock import release
 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
-import lock, util, extensions, error, encoding, node
+import lock, util, extensions, error, encoding, node, subrepo
 import merge as mergemod
 import verify as verifymod
 import errno, os, shutil
@@ -366,6 +366,7 @@
                 dest_repo.ui.status(_("updating to branch %s\n")
                                     % encoding.tolocal(bn))
                 _update(dest_repo, uprev)
+            subrepo.transfersubpaths(ui, dest_repo, src_repo)
 
         return src_repo, dest_repo
     finally:
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1803,3 +1803,14 @@
 
 def islocal(path):
     return True
+
+def pushsubpaths(repo, key, old, new):
+    pass
+
+def listsubpaths(repo):
+    if os.path.exists(repo.join('subpaths')):
+        return {'data': repo.opener('subpaths').read()}
+    else:
+        return {}
+
+pushkey.register('subpaths', pushsubpaths, listsubpaths)
diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -12,7 +12,7 @@
 
 nullstate = ('', '', 'empty')
 
-def state(ctx, ui):
+def state(ctx, repo, ui):
     """return a state dict, mapping subrepo paths configured in .hgsub
     to tuple: (source from .hgsub, revision from .hgsubstate, kind
     (key in types dict))
@@ -27,6 +27,10 @@
     if '.hgsub' in ctx:
         read('.hgsub')
 
+    if os.path.exists(repo.join('subpaths')):
+        p.parse(repo.join('subpaths'), repo.opener('subpaths').read(),
+                ['subpaths'])
+
     for path, src in ui.configitems('subpaths'):
         p.set('subpaths', path, src, ui.configsource('subpaths', path))
 
@@ -73,6 +77,22 @@
                 ''.join(['%s %s\n' % (state[s][1], s)
                          for s in sorted(state)]), '')
 
+def transfersubpaths(ui, repo, other):
+    subpaths = other.listkeys('subpaths')
+    if subpaths:
+        data = subpaths['data']
+        # verify that we can parse the file we got
+        try:
+            c = config.config()
+            c.parse('subpaths', data)
+            fp = repo.opener('subpaths', 'w')
+            fp.write(data)
+            fp.close()
+        except error.ParseError, e:
+            ui.warn(_("not saving retrieved subpaths file: "
+                      "parse error at '%s' on %s\n") % e.args)
+
+
 def submerge(repo, wctx, mctx, actx):
     """delegated from merge.applyupdates: merging of .hgsubstate file
     in working context, merging context and ancestor context"""
diff --git a/tests/test-subrepo-paths.t b/tests/test-subrepo-paths.t
--- a/tests/test-subrepo-paths.t
+++ b/tests/test-subrepo-paths.t
@@ -21,6 +21,24 @@
    source   C:\libs\foo-lib\
    revision 
 
+remapping through .hg/subpaths file
+
+  $ mv .hg/hgrc .hg/subpaths
+  $ hg debugsub
+  path sub
+   source   C:\libs\foo-lib\
+   revision 
+
+test .hg/hgrc overriding .hg/subpaths
+
+  $ echo '[subpaths]' > .hg/hgrc
+  $ echo 'http://example.net/lib(.*) = /local/lib\1' >> .hg/hgrc
+
+  $ hg debugsub
+  path sub
+   source   /local/libfoo
+   revision 
+
 test bad subpaths pattern
 
   $ cat > .hg/hgrc <<EOF
@@ -29,5 +47,31 @@
   > EOF
   $ hg debugsub
   abort: bad subrepository pattern in .*/test-subrepo-paths.t/outer/.hg/hgrc:2: invalid group reference
+  $ rm .hg/hgrc
 
-  $ exit 0
+test propagation of .hg/subpaths file
+
+  $ hg commit -m checkin
+  committing subrepository sub
+  $ cd ..
+  $ hg clone outer outer2
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd outer2
+  $ hg debugsub
+  path sub
+   source   C:\libs\foo-lib\
+   revision 0000000000000000000000000000000000000000
+
+change .hg/subpaths file and test pull:
+
+  $ echo '# empty' > ../outer/.hg/subpaths
+  $ hg pull
+  pulling from .*/test-subrepo-paths.t/outer
+  searching for changes
+  no changes found
+  $ hg debugsub
+  path sub
+   source   http://example.net/libfoo
+   revision 0000000000000000000000000000000000000000
+


More information about the Mercurial-devel mailing list