Mercurial > hgsubversion
changeset 922:6b7ac659c855
updatemeta: correctly handle empty metadata
When the repo metadata is empty (just created/cloned but not populated yet),
there is no lastpulled file or the revmap doesn't have a last entry with hash.
Currently "hg svn updatemeta" would crash due to unexpected exception.
See issue reported at https://bitbucket.org/durin42/hgsubversion/issue/356/updatemeta-crashes-with-traceback-if-there
The fix is to check the existence of lastpulled file and the hash entry in
revmap, as part of "hg svn updatemeta" command. When they are not present,
do a rebuildmetadata.
Also added a new unit test, test_updatemeta.py.
author | Jun Fang <junfang@fb.com> |
---|---|
date | Mon, 06 Aug 2012 10:35:51 -0700 |
parents | 8faa91951bb1 |
children | 847953806c77 |
files | hgsubversion/svncommands.py tests/run.py tests/test_updatemeta.py |
diffstat | 3 files changed, 95 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/hgsubversion/svncommands.py +++ b/hgsubversion/svncommands.py @@ -64,12 +64,19 @@ def _buildmeta(ui, repo, args, partial=F if partial: try: youngestpath = os.path.join(svnmetadir, 'lastpulled') - youngest = int(util.load_string(youngestpath).strip()) - sofar = list(maps.RevMap.readmapfile(repo)) - lasthash = sofar[-1].split(' ', 2)[1] - startrev = repo[lasthash].rev() + 1 - branchinfo = pickle.load(open(os.path.join(svnmetadir, - 'branch_info'))) + foundpartialinfo = False + if os.path.exists(youngestpath): + youngest = int(util.load_string(youngestpath).strip()) + sofar = list(maps.RevMap.readmapfile(repo)) + if sofar and len(sofar[-1].split(' ', 2)) > 1: + lasthash = sofar[-1].split(' ', 2)[1] + startrev = repo[lasthash].rev() + 1 + branchinfo = pickle.load(open(os.path.join(svnmetadir, + 'branch_info'))) + foundpartialinfo = True + if not foundpartialinfo: + ui.status('missing some metadata -- doing a full rebuild\n') + partial = False except IOError, err: if err.errno != errno.ENOENT: raise
--- a/tests/run.py +++ b/tests/run.py @@ -32,6 +32,7 @@ def tests(): import test_template_keywords import test_utility_commands import test_unaffected_core + import test_updatemeta import test_urls sys.path.append(os.path.dirname(__file__))
new file mode 100644 --- /dev/null +++ b/tests/test_updatemeta.py @@ -0,0 +1,81 @@ +import test_util + +import os +import pickle +import unittest +import test_rebuildmeta + +from mercurial import context +from mercurial import extensions +from mercurial import hg +from mercurial import ui + +from hgsubversion import svncommands +from hgsubversion import svnmeta + + + +def _do_case(self, name, stupid, single): + subdir = test_util.subdir.get(name, '') + layout = 'auto' + if single: + layout = 'single' + repo, repo_path = self.load_and_fetch(name, subdir=subdir, stupid=stupid, + layout=layout) + assert len(self.repo) > 0 + wc2_path = self.wc_path + '_clone' + u = ui.ui() + src, dest = test_util.hgclone(u, self.wc_path, wc2_path, update=False) + src = getattr(src, 'local', lambda: src)() + dest = getattr(dest, 'local', lambda: dest)() + + # insert a wrapper that prevents calling changectx.children() + def failfn(orig, ctx): + self.fail('calling %s is forbidden; it can cause massive slowdowns ' + 'when rebuilding large repositories' % orig) + + origchildren = getattr(context.changectx, 'children') + extensions.wrapfunction(context.changectx, 'children', failfn) + + # test updatemeta on an empty repo + try: + svncommands.updatemeta(u, dest, + args=[test_util.fileurl(repo_path + + subdir), ]) + finally: + # remove the wrapper + context.changectx.children = origchildren + + self._run_assertions(name, stupid, single, src, dest, u) + + +def _run_assertions(self, name, stupid, single, src, dest, u): + test_rebuildmeta._run_assertions(self, name, stupid, single, src, dest, u) + + +skip = set([ + 'project_root_not_repo_root.svndump', + 'corrupt.svndump', +]) + +attrs = {'_do_case': _do_case, + '_run_assertions': _run_assertions, + } +for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')]: + # this fixture results in an empty repository, don't use it + if case in skip: + continue + bname = 'test_' + case[:-len('.svndump')] + attrs[bname] = test_rebuildmeta.buildmethod(case, bname, False, False) + name = bname + '_stupid' + attrs[name] = test_rebuildmeta.buildmethod(case, name, True, False) + name = bname + '_single' + attrs[name] = test_rebuildmeta.buildmethod(case, name, False, True) + +UpdateMetaTests = type('UpdateMetaTests', (test_util.TestBase,), attrs) + + +def suite(): + all_tests = [unittest.TestLoader().loadTestsFromTestCase(UpdateMetaTests), + ] + return unittest.TestSuite(all_tests)