# HG changeset patch # User Dirkjan Ochtman # Date 1244740445 -7200 # Node ID 636e9bf5d49c212d1d8c816d3bf2cb0d050b533a # Parent d70c8e45cb9e12de46968b8debeaf05a6528813a svncommands: add verify command diff --git a/hgsubversion/svncommands.py b/hgsubversion/svncommands.py --- a/hgsubversion/svncommands.py +++ b/hgsubversion/svncommands.py @@ -55,6 +55,57 @@ def incoming(ui, svn_url, hg_repo_path, str(r.__getattribute__(attr)).strip(), )) +def verify(ui, repo, *args, **opts): + '''verify current revision against Subversion repository + ''' + + if not args: + url = repo.ui.expandpath('default') + else: + url = args[0] + + ctx = repo['.'] + if 'close' in ctx.extra(): + ui.write('cannot verify closed branch') + return 0 + srev = ctx.extra().get('convert_revision') + if srev is None: + raise hgutil.Abort('revision %s not from SVN' % ctx) + + srev = int(srev.split('@')[1]) + ui.write('verifying %s against r%i\n' % (ctx, srev)) + + url = util.normalize_url(url.rstrip('/')) + user, passwd = util.getuserpass(opts) + svn = svnwrap.SubversionRepo(url, user, passwd) + + btypes = {'default': 'trunk'} + branchpath = btypes.get(ctx.branch(), 'branches/%s' % ctx.branch()) + svnfiles = set() + result = 0 + for fn, type in svn.list_files(branchpath, srev): + if type != 'f': + continue + svnfiles.add(fn) + data, mode = svn.get_file(branchpath + '/' + fn, srev) + fctx = ctx[fn] + dmatch = fctx.data() == data + mmatch = fctx.flags() == mode + if not (dmatch and mmatch): + ui.write('difference in file %s' % fn) + result = 1 + + hgfiles = set(ctx) + hgfiles.discard('.hgtags') + hgfiles.discard('.hgsvnexternals') + if hgfiles != svnfiles: + missing = set(hgfiles).symmetric_difference(svnfiles) + ui.write('missing files: %s' % (', '.join(missing))) + result = 1 + + return result + + def rebuildmeta(ui, repo, hg_repo_path, args, **opts): """rebuild hgsubversion metadata using values stored in revisions """ @@ -200,6 +251,7 @@ table = { 'rebuildmeta': rebuildmeta, 'incoming': incoming, 'updateexternals': svnexternals.updateexternals, + 'verify': verify, } table.update(utility_commands.table) diff --git a/tests/comprehensive/test_verify.py b/tests/comprehensive/test_verify.py new file mode 100644 --- /dev/null +++ b/tests/comprehensive/test_verify.py @@ -0,0 +1,43 @@ +import os +import pickle +import unittest + +import test_util + +from mercurial import hg +from mercurial import ui + +from hgsubversion import svncommands + +def _do_case(self, name, stupid): + subdir = test_util.subdir.get(name, '') + repo = self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid) + assert len(self.repo) > 0 + for i in repo: + ctx = repo[i] + hg.clean(repo, ctx.node(), False) + self.assertEqual(svncommands.verify(repo.ui, repo), 0) + +def buildmethod(case, name, stupid): + m = lambda self: self._do_case(case, stupid) + m.__name__ = name + bits = case, stupid and 'stupid' or 'real' + m.__doc__ = 'Test verify on %s with %s replay.' % bits + return m + +attrs = {'_do_case': _do_case} +fixtures = [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')] +for case in fixtures: + # this fixture results in an empty repository, don't use it + if case == 'project_root_not_repo_root.svndump': + continue + name = 'test_' + case[:-len('.svndump')] + attrs[name] = buildmethod(case, name, False) + name += '_stupid' + attrs[name] = buildmethod(case, name, True) + +VerifyTests = type('VerifyTests', (test_util.TestBase,), attrs) + +def suite(): + all = [unittest.TestLoader().loadTestsFromTestCase(VerifyTests)] + return unittest.TestSuite(all) diff --git a/tests/run.py b/tests/run.py --- a/tests/run.py +++ b/tests/run.py @@ -26,6 +26,7 @@ import test_utility_commands import test_urls from comprehensive import test_stupid_pull +from comprehensive import test_verify def comprehensive(mod): dir = os.path.basename(os.path.dirname(mod.__file__))