diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py index 52c552a05414ef6bf001c48c14bb39f25fbfbf31_aGdleHQvY29udmVydC9fX2luaXRfXy5weQ==..daf9f7ee2a5c9b51a9b14decff75cbd7910ea316_aGdleHQvY29udmVydC9fX2luaXRfXy5weQ== 100644 --- a/hgext/convert/__init__.py +++ b/hgext/convert/__init__.py @@ -328,6 +328,23 @@ Mercurial Destination ##################### + The Mercurial destination will recognize Mercurial subrepositories in the + destination directory, and update the .hgsubstate file automatically if the + destination subrepositories contain the <dest>/<sub>/.hg/shamap file. + Converting a repository with subrepositories requires converting a single + repository at a time, from the bottom up. + + .. container:: verbose + + An example showing how to convert a repository with subrepositories:: + + # so convert knows the type when it sees a non empty destination + $ hg init converted + + $ hg convert orig/sub1 converted/sub1 + $ hg convert orig/sub2 converted/sub2 + $ hg convert orig converted + The following options are supported: :convert.hg.clonebranches: dispatch source branches in separate diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py index 52c552a05414ef6bf001c48c14bb39f25fbfbf31_aGdleHQvY29udmVydC9oZy5weQ==..daf9f7ee2a5c9b51a9b14decff75cbd7910ea316_aGdleHQvY29udmVydC9oZy5weQ== 100644 --- a/hgext/convert/hg.py +++ b/hgext/convert/hg.py @@ -23,7 +23,7 @@ from mercurial.node import bin, hex, nullid from mercurial import hg, util, context, bookmarks, error, scmutil, exchange -from common import NoRepo, commit, converter_source, converter_sink +from common import NoRepo, commit, converter_source, converter_sink, mapfile import re sha1re = re.compile(r'\b[0-9a-f]{12,40}\b') @@ -59,6 +59,7 @@ self.lock = None self.wlock = None self.filemapmode = False + self.subrevmaps = {} def before(self): self.ui.debug('run hg sink pre-conversion action\n') @@ -135,6 +136,45 @@ fp.write('%s %s\n' % (revid, s[1])) return fp.getvalue() + def _rewritesubstate(self, source, data): + fp = cStringIO.StringIO() + for line in data.splitlines(): + s = line.split(' ', 1) + if len(s) != 2: + continue + + revid = s[0] + subpath = s[1] + if revid != hex(nullid): + revmap = self.subrevmaps.get(subpath) + if revmap is None: + revmap = mapfile(self.ui, + self.repo.wjoin(subpath, '.hg/shamap')) + self.subrevmaps[subpath] = revmap + + # It is reasonable that one or more of the subrepos don't + # need to be converted, in which case they can be cloned + # into place instead of converted. Therefore, only warn + # once. + msg = _('no ".hgsubstate" updates will be made for "%s"\n') + if len(revmap) == 0: + sub = self.repo.wvfs.reljoin(subpath, '.hg') + + if self.repo.wvfs.exists(sub): + self.ui.warn(msg % subpath) + + newid = revmap.get(revid) + if not newid: + if len(revmap) > 0: + self.ui.warn(_("%s is missing from %s/.hg/shamap\n") % + (revid, subpath)) + else: + revid = newid + + fp.write('%s %s\n' % (revid, subpath)) + + return fp.getvalue() + def putcommit(self, files, copies, parents, commit, source, revmap, full, cleanp2): files = dict(files) @@ -152,6 +192,8 @@ return None if f == '.hgtags': data = self._rewritetags(source, revmap, data) + if f == '.hgsubstate': + data = self._rewritesubstate(source, data) return context.memfilectx(self.repo, f, data, 'l' in mode, 'x' in mode, copies.get(f)) diff --git a/tests/test-convert.t b/tests/test-convert.t index 52c552a05414ef6bf001c48c14bb39f25fbfbf31_dGVzdHMvdGVzdC1jb252ZXJ0LnQ=..daf9f7ee2a5c9b51a9b14decff75cbd7910ea316_dGVzdHMvdGVzdC1jb252ZXJ0LnQ= 100644 --- a/tests/test-convert.t +++ b/tests/test-convert.t @@ -279,6 +279,12 @@ Mercurial Destination ##################### + The Mercurial destination will recognize Mercurial subrepositories in the + destination directory, and update the .hgsubstate file automatically if + the destination subrepositories contain the <dest>/<sub>/.hg/shamap file. + Converting a repository with subrepositories requires converting a single + repository at a time, from the bottom up. + The following options are supported: convert.hg.clonebranches diff --git a/tests/test-fileset.t b/tests/test-fileset.t index 52c552a05414ef6bf001c48c14bb39f25fbfbf31_dGVzdHMvdGVzdC1maWxlc2V0LnQ=..daf9f7ee2a5c9b51a9b14decff75cbd7910ea316_dGVzdHMvdGVzdC1maWxlc2V0LnQ= 100644 --- a/tests/test-fileset.t +++ b/tests/test-fileset.t @@ -180,7 +180,12 @@ $ hg -R sub add sub/suba $ hg -R sub ci -m sub $ echo 'sub = sub' > .hgsub + $ hg init sub2 + $ echo b > sub2/b + $ hg -R sub2 ci -Am sub2 + adding b + $ echo 'sub2 = sub2' >> .hgsub $ fileset 'subrepo()' $ hg add .hgsub $ fileset 'subrepo()' sub @@ -183,8 +188,9 @@ $ fileset 'subrepo()' $ hg add .hgsub $ fileset 'subrepo()' sub + sub2 $ fileset 'subrepo("sub")' sub $ fileset 'subrepo("glob:*")' sub @@ -187,6 +193,7 @@ $ fileset 'subrepo("sub")' sub $ fileset 'subrepo("glob:*")' sub + sub2 $ hg ci -m subrepo @@ -191,5 +198,36 @@ $ hg ci -m subrepo +Test that .hgsubstate is updated as appropriate during a conversion. The +saverev property is enough to alter the hashes of the subrepo. + + $ hg init ../converted + $ hg --config extensions.convert= convert --config convert.hg.saverev=True \ + > sub ../converted/sub + initializing destination ../converted/sub repository + scanning source... + sorting... + converting... + 0 sub + $ hg clone -U sub2 ../converted/sub2 + $ hg --config extensions.convert= convert --config convert.hg.saverev=True \ + > . ../converted + scanning source... + sorting... + converting... + 4 addfiles + 3 manychanges + 2 diverging + 1 merge + 0 subrepo + no ".hgsubstate" updates will be made for "sub2" + $ hg up -q -R ../converted -r tip + $ hg --cwd ../converted cat sub/suba sub2/b -r tip + a + b + $ oldnode=`hg log -r tip -T "{node}\n"` + $ newnode=`hg log -R ../converted -r tip -T "{node}\n"` + $ [[ "$oldnode" != "$newnode" ]] || echo "nothing changed" + Test with a revision $ hg log -G --template '{rev} {desc}\n' @@ -241,6 +279,7 @@ $ fileset -r4 'subrepo("re:su.*")' sub + sub2 $ fileset -r4 'subrepo("sub")' sub $ fileset -r4 'b2 or c1'