# HG changeset patch # User Dirkjan Ochtman # Date 1239205770 -7200 # Node ID 4950b18cf949a88d71422d0d4b138211f6b2d0cc # Parent 1aa1d2d406d9265571b7d531a7a4db17e7d68a00 Move fetch_command.fetch_revisions() to svncommands.pull(). diff --git a/__init__.py b/__init__.py --- a/__init__.py +++ b/__init__.py @@ -21,7 +21,7 @@ from mercurial import util as mutil from svn import core import svncommand -import fetch_command +import svncommands import tag_repo import util @@ -58,7 +58,7 @@ def svn_fetch(ui, svn_url, hg_repo_path= should_update = not os.path.exists(hg_repo_path) svn_url = util.normalize_url(svn_url) try: - res = fetch_command.fetch_revisions(ui, svn_url, hg_repo_path, **opts) + res = svncommands.pull(ui, svn_url, hg_repo_path, **opts) except core.SubversionException, e: if e.apr_err == core.SVN_ERR_RA_SERF_SSL_CERT_UNTRUSTED: raise mutil.Abort('It appears svn does not trust the ssl cert for this site.\n' diff --git a/cmdutil.py b/cmdutil.py new file mode 100644 --- /dev/null +++ b/cmdutil.py @@ -0,0 +1,32 @@ + +def replay_convert_rev(hg_editor, svn, r): + hg_editor.set_current_rev(r) + svn.get_replay(r.revnum, hg_editor) + i = 1 + if hg_editor.missing_plaintexts: + hg_editor.ui.debug('Fetching %s files that could not use replay.\n' % + len(hg_editor.missing_plaintexts)) + files_to_grab = set() + rootpath = svn.subdir and svn.subdir[1:] or '' + for p in hg_editor.missing_plaintexts: + hg_editor.ui.note('.') + hg_editor.ui.flush() + if p[-1] == '/': + dirpath = p[len(rootpath):] + files_to_grab.update([dirpath + f for f,k in + svn.list_files(dirpath, r.revnum) + if k == 'f']) + else: + files_to_grab.add(p[len(rootpath):]) + hg_editor.ui.note('\nFetching files...\n') + for p in files_to_grab: + hg_editor.ui.note('.') + hg_editor.ui.flush() + if i % 50 == 0: + svn.init_ra_and_client() + i += 1 + data, mode = svn.get_file(p, r.revnum) + hg_editor.set_file(p, data, 'x' in mode, 'l' in mode) + hg_editor.missing_plaintexts = set() + hg_editor.ui.note('\n') + hg_editor.commit_current_delta() diff --git a/fetch_command.py b/fetch_command.py deleted file mode 100644 --- a/fetch_command.py +++ /dev/null @@ -1,132 +0,0 @@ -import os - -from mercurial import util as merc_util -from svn import core -from svn import delta - -import hg_delta_editor -import svnwrap -import stupid as stupidmod -import util - - -def fetch_revisions(ui, svn_url, hg_repo_path, skipto_rev=0, stupid=None, - tag_locations='tags', - authors=None, - filemap=None, - **opts): - """pull new revisions from Subversion - """ - svn_url = util.normalize_url(svn_url) - old_encoding = util.swap_out_encoding() - skipto_rev=int(skipto_rev) - have_replay = not stupid - if have_replay and not callable( - delta.svn_txdelta_apply(None, None, None)[0]): #pragma: no cover - ui.status('You are using old Subversion SWIG bindings. Replay will not' - ' work until you upgrade to 1.5.0 or newer. Falling back to' - ' a slower method that may be buggier. Please upgrade, or' - ' contribute a patch to use the ctypes bindings instead' - ' of SWIG.\n') - have_replay = False - initializing_repo = False - user = opts.get('username', merc_util.getuser()) - passwd = opts.get('password', '') - svn = svnwrap.SubversionRepo(svn_url, user, passwd) - author_host = "@%s" % svn.uuid - tag_locations = tag_locations.split(',') - hg_editor = hg_delta_editor.HgChangeReceiver(hg_repo_path, - ui_=ui, - subdir=svn.subdir, - author_host=author_host, - tag_locations=tag_locations, - authors=authors, - filemap=filemap) - if os.path.exists(hg_editor.uuid_file): - uuid = open(hg_editor.uuid_file).read() - assert uuid == svn.uuid - start = hg_editor.last_known_revision() - else: - open(hg_editor.uuid_file, 'w').write(svn.uuid) - open(hg_editor.svn_url_file, 'w').write(svn_url) - initializing_repo = True - start = skipto_rev - - if initializing_repo and start > 0: - raise merc_util.Abort('Revision skipping at repository initialization ' - 'remains unimplemented.') - - # start converting revisions - for r in svn.revisions(start=start): - valid = True - hg_editor.update_branch_tag_map_for_rev(r) - for p in r.paths: - if hg_editor._is_path_valid(p): - valid = True - break - if valid: - # got a 502? Try more than once! - tries = 0 - converted = False - while not converted: - try: - util.describe_revision(ui, r) - if have_replay: - try: - replay_convert_rev(hg_editor, svn, r) - except svnwrap.SubversionRepoCanNotReplay, e: #pragma: no cover - ui.status('%s\n' % e.message) - stupidmod.print_your_svn_is_old_message(ui) - have_replay = False - stupidmod.svn_server_pull_rev(ui, svn, hg_editor, r) - else: - stupidmod.svn_server_pull_rev(ui, svn, hg_editor, r) - converted = True - except core.SubversionException, e: #pragma: no cover - if (e.apr_err == core.SVN_ERR_RA_DAV_REQUEST_FAILED - and '502' in str(e) - and tries < 3): - tries += 1 - ui.status('Got a 502, retrying (%s)\n' % tries) - else: - raise merc_util.Abort(*e.args) - util.swap_out_encoding(old_encoding) - -fetch_revisions = util.register_subcommand('pull')(fetch_revisions) - - -def cleanup_file_handles(svn, count): - if count % 50 == 0: - svn.init_ra_and_client() - - -def replay_convert_rev(hg_editor, svn, r): - hg_editor.set_current_rev(r) - svn.get_replay(r.revnum, hg_editor) - i = 1 - if hg_editor.missing_plaintexts: - hg_editor.ui.debug('Fetching %s files that could not use replay.\n' % - len(hg_editor.missing_plaintexts)) - files_to_grab = set() - rootpath = svn.subdir and svn.subdir[1:] or '' - for p in hg_editor.missing_plaintexts: - hg_editor.ui.note('.') - hg_editor.ui.flush() - if p[-1] == '/': - dirpath = p[len(rootpath):] - files_to_grab.update([dirpath + f for f,k in - svn.list_files(dirpath, r.revnum) - if k == 'f']) - else: - files_to_grab.add(p[len(rootpath):]) - hg_editor.ui.note('\nFetching files...\n') - for p in files_to_grab: - hg_editor.ui.note('.') - hg_editor.ui.flush() - cleanup_file_handles(svn, i) - i += 1 - data, mode = svn.get_file(p, r.revnum) - hg_editor.set_file(p, data, 'x' in mode, 'l' in mode) - hg_editor.missing_plaintexts = set() - hg_editor.ui.note('\n') - hg_editor.commit_current_delta() diff --git a/push_cmd.py b/push_cmd.py --- a/push_cmd.py +++ b/push_cmd.py @@ -7,7 +7,7 @@ import util import hg_delta_editor import svnexternals import svnwrap -import fetch_command +import svncommands import utility_commands @@ -68,9 +68,8 @@ def push_revisions_to_subversion(ui, rep old_ctx) return 1 # 3. Fetch revisions from svn - r = fetch_command.fetch_revisions(ui, svn_url, hg_repo_path, - stupid=stupid, username=user, - password=passwd) + r = svncommands.pull(ui, svn_url, hg_repo_path, stupid=stupid, + username=user, password=passwd) assert not r or r == 0 # 4. Find the new head of the target branch repo = hg.repository(ui, hge.path) diff --git a/svncommand.py b/svncommand.py --- a/svncommand.py +++ b/svncommand.py @@ -10,13 +10,13 @@ import svnwrap import util from util import register_subcommand, svn_subcommands, generate_help, svn_commands_nourl # dirty trick to force demandimport to run my decorator anyway. +from svncommands import pull from utility_commands import print_wc_url -from fetch_command import fetch_revisions from push_cmd import commit_from_rev from diff_cmd import diff_command from rebuildmeta import rebuildmeta # shut up, pyflakes, we must import those -__x = [print_wc_url, fetch_revisions, commit_from_rev, diff_command, rebuildmeta] +__x = [print_wc_url, pull, commit_from_rev, diff_command, rebuildmeta] def svncmd(ui, repo, subcommand, *args, **opts): diff --git a/svncommands.py b/svncommands.py new file mode 100644 --- /dev/null +++ b/svncommands.py @@ -0,0 +1,93 @@ +import os + +from mercurial import util as hgutil +from svn import core +from svn import delta + +import hg_delta_editor +import svnwrap +import stupid as stupidmod +import cmdutil +import util + + +def pull(ui, svn_url, hg_repo_path, skipto_rev=0, stupid=None, + tag_locations='tags', authors=None, filemap=None, **opts): + """pull new revisions from Subversion + """ + svn_url = util.normalize_url(svn_url) + old_encoding = util.swap_out_encoding() + skipto_rev=int(skipto_rev) + have_replay = not stupid + if have_replay and not callable( + delta.svn_txdelta_apply(None, None, None)[0]): #pragma: no cover + ui.status('You are using old Subversion SWIG bindings. Replay will not' + ' work until you upgrade to 1.5.0 or newer. Falling back to' + ' a slower method that may be buggier. Please upgrade, or' + ' contribute a patch to use the ctypes bindings instead' + ' of SWIG.\n') + have_replay = False + initializing_repo = False + user = opts.get('username', hgutil.getuser()) + passwd = opts.get('password', '') + svn = svnwrap.SubversionRepo(svn_url, user, passwd) + author_host = "@%s" % svn.uuid + tag_locations = tag_locations.split(',') + hg_editor = hg_delta_editor.HgChangeReceiver(hg_repo_path, + ui_=ui, + subdir=svn.subdir, + author_host=author_host, + tag_locations=tag_locations, + authors=authors, + filemap=filemap) + if os.path.exists(hg_editor.uuid_file): + uuid = open(hg_editor.uuid_file).read() + assert uuid == svn.uuid + start = hg_editor.last_known_revision() + else: + open(hg_editor.uuid_file, 'w').write(svn.uuid) + open(hg_editor.svn_url_file, 'w').write(svn_url) + initializing_repo = True + start = skipto_rev + + if initializing_repo and start > 0: + raise hgutil.Abort('Revision skipping at repository initialization ' + 'remains unimplemented.') + + # start converting revisions + for r in svn.revisions(start=start): + valid = True + hg_editor.update_branch_tag_map_for_rev(r) + for p in r.paths: + if hg_editor._is_path_valid(p): + valid = True + break + if valid: + # got a 502? Try more than once! + tries = 0 + converted = False + while not converted: + try: + util.describe_revision(ui, r) + if have_replay: + try: + cmdutil.replay_convert_rev(hg_editor, svn, r) + except svnwrap.SubversionRepoCanNotReplay, e: #pragma: no cover + ui.status('%s\n' % e.message) + stupidmod.print_your_svn_is_old_message(ui) + have_replay = False + stupidmod.svn_server_pull_rev(ui, svn, hg_editor, r) + else: + stupidmod.svn_server_pull_rev(ui, svn, hg_editor, r) + converted = True + except core.SubversionException, e: #pragma: no cover + if (e.apr_err == core.SVN_ERR_RA_DAV_REQUEST_FAILED + and '502' in str(e) + and tries < 3): + tries += 1 + ui.status('Got a 502, retrying (%s)\n' % tries) + else: + raise hgutil.Abort(*e.args) + util.swap_out_encoding(old_encoding) + +pull = util.register_subcommand('pull')(pull) diff --git a/tests/comprehensive/test_stupid_pull.py b/tests/comprehensive/test_stupid_pull.py --- a/tests/comprehensive/test_stupid_pull.py +++ b/tests/comprehensive/test_stupid_pull.py @@ -6,7 +6,7 @@ from mercurial import hg from mercurial import ui from tests import test_util -import fetch_command +import svncommands def _do_case(self, name): @@ -18,10 +18,8 @@ def _do_case(self, name): checkout_path = self.repo_path if subdir: checkout_path += '/' + subdir - fetch_command.fetch_revisions(ui.ui(), - svn_url=test_util.fileurl(checkout_path), - hg_repo_path=wc2_path, - stupid=True) + svncommands.pull(ui.ui(), svn_url=test_util.fileurl(checkout_path), + hg_repo_path=wc2_path, stupid=True) self.repo2 = hg.repository(ui.ui(), wc2_path) self.assertEqual(self.repo.branchtags(), self.repo2.branchtags()) self.assertEqual(pickle.load(open(os.path.join(self.wc_path, '.hg', 'svn', 'tag_info'))), diff --git a/tests/test_fetch_mappings.py b/tests/test_fetch_mappings.py --- a/tests/test_fetch_mappings.py +++ b/tests/test_fetch_mappings.py @@ -7,7 +7,7 @@ from mercurial import ui from mercurial import node import test_util -import fetch_command +import svncommands class MapTests(test_util.TestBase): @property @@ -23,11 +23,9 @@ class MapTests(test_util.TestBase): authormap = open(self.authors, 'w') authormap.write("Augie=Augie Fackler \n") authormap.close() - fetch_command.fetch_revisions(ui.ui(), - svn_url=test_util.fileurl(self.repo_path), - hg_repo_path=self.wc_path, - stupid=stupid, - authors=self.authors) + svncommands.pull(ui.ui(), svn_url=test_util.fileurl(self.repo_path), + hg_repo_path=self.wc_path, stupid=stupid, + authors=self.authors) self.assertEqual(self.repo[0].user(), 'Augie Fackler ') self.assertEqual(self.repo['tip'].user(), @@ -41,11 +39,9 @@ class MapTests(test_util.TestBase): authormap = open(self.authors, 'w') authormap.write("evil=Testy ") authormap.close() - fetch_command.fetch_revisions(ui.ui(), - svn_url=test_util.fileurl(self.repo_path), - hg_repo_path=self.wc_path, - stupid=stupid, - authors=self.authors) + svncommands.pull(ui.ui(), svn_url=test_util.fileurl(self.repo_path), + hg_repo_path=self.wc_path, stupid=stupid, + authors=self.authors) self.assertEqual(self.repo[0].user(), 'Augie@5b65bade-98f3-4993-a01f-b7a6710da339') self.assertEqual(self.repo['tip'].user(), @@ -59,11 +55,9 @@ class MapTests(test_util.TestBase): filemap = open(self.filemap, 'w') filemap.write("include alpha\n") filemap.close() - fetch_command.fetch_revisions(ui.ui(), - svn_url=test_util.fileurl(self.repo_path), - hg_repo_path=self.wc_path, - stupid=stupid, - filemap=self.filemap) + svncommands.pull(ui.ui(), svn_url=test_util.fileurl(self.repo_path), + hg_repo_path=self.wc_path, stupid=stupid, + filemap=self.filemap) self.assertEqual(node.hex(self.repo[0].node()), '88e2c7492d83e4bf30fbb2dcbf6aa24d60ac688d') self.assertEqual(node.hex(self.repo['default'].node()), 'e524296152246b3837fe9503c83b727075835155') @@ -75,11 +69,9 @@ class MapTests(test_util.TestBase): filemap = open(self.filemap, 'w') filemap.write("exclude alpha\n") filemap.close() - fetch_command.fetch_revisions(ui.ui(), - svn_url=test_util.fileurl(self.repo_path), - hg_repo_path=self.wc_path, - stupid=stupid, - filemap=self.filemap) + svncommands.pull(ui.ui(), svn_url=test_util.fileurl(self.repo_path), + hg_repo_path=self.wc_path, stupid=stupid, + filemap=self.filemap) self.assertEqual(node.hex(self.repo[0].node()), '2c48f3525926ab6c8b8424bcf5eb34b149b61841') self.assertEqual(node.hex(self.repo['default'].node()), 'b37a3c0297b71f989064d9b545b5a478bbed7cc1') diff --git a/tests/test_fetch_truncated.py b/tests/test_fetch_truncated.py --- a/tests/test_fetch_truncated.py +++ b/tests/test_fetch_truncated.py @@ -3,7 +3,7 @@ import unittest from mercurial import hg from mercurial import ui -import fetch_command +import svncommands import test_util class TestFetchTruncatedHistory(test_util.TestBase): @@ -11,10 +11,8 @@ class TestFetchTruncatedHistory(test_uti # Test repository does not follow the usual layout test_util.load_svndump_fixture(self.repo_path, 'truncatedhistory.svndump') svn_url = test_util.fileurl(self.repo_path + '/project2') - fetch_command.fetch_revisions(ui.ui(), - svn_url=svn_url, - hg_repo_path=self.wc_path, - stupid=stupid) + svncommands.pull(ui.ui(), svn_url=svn_url, + hg_repo_path=self.wc_path, stupid=stupid) repo = hg.repository(ui.ui(), self.wc_path) # We are converting /project2/trunk coming from: diff --git a/tests/test_push_command.py b/tests/test_push_command.py --- a/tests/test_push_command.py +++ b/tests/test_push_command.py @@ -9,7 +9,7 @@ from mercurial import node from mercurial import ui from mercurial import revlog -import fetch_command +import svncommands import push_cmd import test_util import time @@ -38,9 +38,8 @@ class PushOverSvnserveTests(test_util.Te args = ['svnserve', '-d', '--foreground', '-r', self.repo_path] self.svnserve_pid = subprocess.Popen(args).pid time.sleep(2) - fetch_command.fetch_revisions(ui.ui(), - svn_url='svn://localhost/', - hg_repo_path=self.wc_path) + svncommands.pull(ui.ui(), svn_url='svn://localhost/', + hg_repo_path=self.wc_path) def tearDown(self): os.system('kill -9 %d' % self.svnserve_pid) diff --git a/tests/test_util.py b/tests/test_util.py --- a/tests/test_util.py +++ b/tests/test_util.py @@ -13,7 +13,7 @@ from mercurial import hg from mercurial import node from mercurial import ui -import fetch_command +import svncommands import push_cmd # Fixtures that need to be pulled at a subdirectory of the repo path @@ -49,10 +49,8 @@ def load_fixture_and_fetch(fixture_name, load_svndump_fixture(repo_path, fixture_name) if subdir: repo_path += '/' + subdir - fetch_command.fetch_revisions(ui.ui(), - svn_url=fileurl(repo_path), - hg_repo_path=wc_path, - stupid=stupid) + svncommands.pull(ui.ui(), svn_url=fileurl(repo_path), + hg_repo_path=wc_path, stupid=stupid) repo = hg.repository(ui.ui(), wc_path) return repo diff --git a/tests/test_utility_commands.py b/tests/test_utility_commands.py --- a/tests/test_utility_commands.py +++ b/tests/test_utility_commands.py @@ -8,7 +8,7 @@ from mercurial import context from mercurial import node import utility_commands -import fetch_command +import svncommands import test_util expected_info_output = '''URL: %(repourl)s/%(branch)s @@ -145,10 +145,9 @@ class UtilityTests(test_util.TestBase): """Verify url gets normalized on initial clone. """ test_util.load_svndump_fixture(self.repo_path, 'two_revs.svndump') - fetch_command.fetch_revisions(ui.ui(), - svn_url=test_util.fileurl(self.repo_path)+'/', - hg_repo_path=self.wc_path, - stupid=False) + svncommands.pull(ui.ui(), + svn_url=test_util.fileurl(self.repo_path) + '/', + hg_repo_path=self.wc_path, stupid=False) hg.update(self.repo, 'tip') u = ui.ui() utility_commands.print_wc_url(u, self.repo, self.wc_path) @@ -159,10 +158,9 @@ class UtilityTests(test_util.TestBase): """Verify url gets normalized on initial clone. """ test_util.load_svndump_fixture(self.repo_path, 'ignores.svndump') - fetch_command.fetch_revisions(ui.ui(), - svn_url=test_util.fileurl(self.repo_path)+'/', - hg_repo_path=self.wc_path, - stupid=False) + svncommands.pull(ui.ui(), + svn_url=test_util.fileurl(self.repo_path) + '/', + hg_repo_path=self.wc_path, stupid=False) hg.update(self.repo, 'tip') u = ui.ui() utility_commands.generate_ignore(u, self.repo, self.wc_path)