Merge lp:~mwhudson/launchpad/bzr-svn-imports into lp:launchpad

Proposed by Michael Hudson-Doyle
Status: Merged
Approved by: Tim Penhey
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~mwhudson/launchpad/bzr-svn-imports
Merge into: lp:launchpad
Diff against target: 577 lines (+133/-85)
8 files modified
lib/lp/codehosting/codeimport/tests/servers.py (+3/-16)
lib/lp/codehosting/codeimport/tests/test_dispatcher.py (+2/-4)
lib/lp/codehosting/codeimport/tests/test_worker.py (+76/-44)
lib/lp/codehosting/codeimport/tests/test_workermonitor.py (+5/-6)
lib/lp/codehosting/codeimport/worker.py (+40/-10)
lib/lp/testing/factory.py (+1/-1)
scripts/code-import-worker.py (+5/-3)
sourcecode/Makefile (+1/-1)
To merge this branch: bzr merge lp:~mwhudson/launchpad/bzr-svn-imports
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Review via email: mp+15027@code.launchpad.net

Commit message

Add support for bzr-svn to the code import worker

To post a comment you must log in.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

This branch adds support for bzr-svn to the code import worker, the lowest level of the code import system.

Revision history for this message
Tim Penhey (thumper) wrote :

Looks pretty good to me.

Will be happy to see bzr-svn working.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/codehosting/codeimport/tests/servers.py'
--- lib/lp/codehosting/codeimport/tests/servers.py 2009-06-30 16:56:07 +0000
+++ lib/lp/codehosting/codeimport/tests/servers.py 2009-11-23 21:24:23 +0000
@@ -11,7 +11,6 @@
1111
12__metaclass__ = type12__metaclass__ = type
1313
14import logging
15import os14import os
16import shutil15import shutil
17import tempfile16import tempfile
@@ -24,6 +23,7 @@
24from bzrlib.transport import Server23from bzrlib.transport import Server
25from bzrlib.tests.treeshape import build_tree_contents24from bzrlib.tests.treeshape import build_tree_contents
2625
26from canonical.launchpad.scripts.logger import QuietFakeLogger
2727
28def local_path_to_url(local_path):28def local_path_to_url(local_path):
29 """Return a file:// URL to `local_path`.29 """Return a file:// URL to `local_path`.
@@ -35,19 +35,6 @@
35 os.path.normpath(os.path.abspath(local_path)))35 os.path.normpath(os.path.abspath(local_path)))
3636
3737
38def _make_silent_logger():
39 """Create a logger that prints nothing."""
40
41 class SilentLogHandler(logging.Handler):
42 def emit(self, record):
43 pass
44
45 logger = logging.Logger("collector")
46 handler = SilentLogHandler()
47 logger.addHandler(handler)
48 return logger
49
50
51def run_in_temporary_directory(function):38def run_in_temporary_directory(function):
52 """Decorate `function` to be run in a temporary directory.39 """Decorate `function` to be run in a temporary directory.
5340
@@ -79,7 +66,7 @@
7966
80 def createRepository(self, path):67 def createRepository(self, path):
81 """Create a Subversion repository at `path`."""68 """Create a Subversion repository at `path`."""
82 svn_oo.Repository.Create(path, _make_silent_logger())69 svn_oo.Repository.Create(path, QuietFakeLogger())
8370
84 def get_url(self):71 def get_url(self):
85 """Return a URL to the Subversion repository."""72 """Return a URL to the Subversion repository."""
@@ -139,7 +126,7 @@
139 :param path: The local path to create a repository in.126 :param path: The local path to create a repository in.
140 :return: A CVS.Repository`.127 :return: A CVS.Repository`.
141 """128 """
142 return CVS.init(path, _make_silent_logger())129 return CVS.init(path, QuietFakeLogger())
143130
144 def getRoot(self):131 def getRoot(self):
145 """Return the CVS root for this server."""132 """Return the CVS root for this server."""
146133
=== modified file 'lib/lp/codehosting/codeimport/tests/test_dispatcher.py'
--- lib/lp/codehosting/codeimport/tests/test_dispatcher.py 2009-06-25 04:06:00 +0000
+++ lib/lp/codehosting/codeimport/tests/test_dispatcher.py 2009-11-23 21:24:23 +0000
@@ -10,7 +10,6 @@
10import os10import os
11import shutil11import shutil
12import socket12import socket
13import sys
14import tempfile13import tempfile
15from textwrap import dedent14from textwrap import dedent
16from unittest import TestLoader15from unittest import TestLoader
@@ -19,9 +18,8 @@
1918
20from canonical.config import config19from canonical.config import config
21from lp.codehosting.codeimport.dispatcher import CodeImportDispatcher20from lp.codehosting.codeimport.dispatcher import CodeImportDispatcher
22from lp.codehosting.codeimport.tests.servers import (
23 _make_silent_logger)
24from canonical.launchpad import scripts21from canonical.launchpad import scripts
22from canonical.launchpad.scripts.logger import QuietFakeLogger
25from canonical.testing.layers import TwistedLaunchpadZopelessLayer23from canonical.testing.layers import TwistedLaunchpadZopelessLayer
2624
2725
@@ -43,7 +41,7 @@
43 def setUp(self):41 def setUp(self):
44 self.config_count = 042 self.config_count = 0
45 self.pushConfig(forced_hostname='none')43 self.pushConfig(forced_hostname='none')
46 self.dispatcher = CodeImportDispatcher(_make_silent_logger())44 self.dispatcher = CodeImportDispatcher(QuietFakeLogger())
4745
48 def pushConfig(self, **args):46 def pushConfig(self, **args):
49 """Push some key-value pairs into the codeimportdispatcher config.47 """Push some key-value pairs into the codeimportdispatcher config.
5048
=== modified file 'lib/lp/codehosting/codeimport/tests/test_worker.py'
--- lib/lp/codehosting/codeimport/tests/test_worker.py 2009-11-21 00:28:10 +0000
+++ lib/lp/codehosting/codeimport/tests/test_worker.py 2009-11-23 21:24:23 +0000
@@ -9,6 +9,7 @@
9import os9import os
10import shutil10import shutil
11import subprocess11import subprocess
12import sys
12import tempfile13import tempfile
13import time14import time
14import unittest15import unittest
@@ -21,18 +22,23 @@
21from bzrlib.upgrade import upgrade22from bzrlib.upgrade import upgrade
22from bzrlib.urlutils import join as urljoin23from bzrlib.urlutils import join as urljoin
2324
25from CVS import Repository, tree
26
24from canonical.cachedproperty import cachedproperty27from canonical.cachedproperty import cachedproperty
28from canonical.config import config
29from canonical.launchpad.scripts.logger import QuietFakeLogger
30from canonical.testing import BaseLayer
31
25from lp.codehosting import load_optional_plugin32from lp.codehosting import load_optional_plugin
26from lp.codehosting.codeimport.worker import (33from lp.codehosting.codeimport.worker import (
27 BazaarBranchStore, CSCVSImportWorker, ForeignTreeStore, GitImportWorker,34 BazaarBranchStore, BzrSvnImportWorker, CSCVSImportWorker,
28 ImportDataStore, ImportWorker, get_default_bazaar_branch_store)35 ForeignTreeStore, GitImportWorker, ImportDataStore, ImportWorker,
36 get_default_bazaar_branch_store)
29from lp.codehosting.codeimport.tests.servers import (37from lp.codehosting.codeimport.tests.servers import (
30 CVSServer, GitServer, SubversionServer)38 CVSServer, GitServer, SubversionServer)
31from lp.codehosting.tests.helpers import (39from lp.codehosting.tests.helpers import (
32 create_branch_with_one_revision)40 create_branch_with_one_revision)
33from canonical.config import config
34from lp.testing.factory import LaunchpadObjectFactory41from lp.testing.factory import LaunchpadObjectFactory
35from canonical.testing import BaseLayer
3642
37import pysvn43import pysvn
3844
@@ -120,7 +126,7 @@
120 store = self.makeBranchStore()126 store = self.makeBranchStore()
121 target_url = store._getMirrorURL(self.arbitrary_branch_id)127 target_url = store._getMirrorURL(self.arbitrary_branch_id)
122 knit_format = format_registry.get('knit')()128 knit_format = format_registry.get('knit')()
123 tree = create_branch_with_one_revision(target_url, format=knit_format)129 create_branch_with_one_revision(target_url, format=knit_format)
124 default_format = BzrDirFormat.get_default_format()130 default_format = BzrDirFormat.get_default_format()
125131
126 # The fetched branch is in the default format.132 # The fetched branch is in the default format.
@@ -142,7 +148,7 @@
142 store = self.makeBranchStore()148 store = self.makeBranchStore()
143 target_url = store._getMirrorURL(self.arbitrary_branch_id)149 target_url = store._getMirrorURL(self.arbitrary_branch_id)
144 knit_format = format_registry.get('knit')()150 knit_format = format_registry.get('knit')()
145 tree = create_branch_with_one_revision(target_url, format=knit_format)151 create_branch_with_one_revision(target_url, format=knit_format)
146 upgrade(target_url, format_registry.get('dirstate-tags')())152 upgrade(target_url, format_registry.get('dirstate-tags')())
147 self.failUnless(get_transport(target_url).has('backup.bzr'))153 self.failUnless(get_transport(target_url).has('backup.bzr'))
148 default_format = BzrDirFormat.get_default_format()154 default_format = BzrDirFormat.get_default_format()
@@ -587,7 +593,6 @@
587 if filename.startswith(prefix):593 if filename.startswith(prefix):
588 tree_transport.delete(filename)594 tree_transport.delete(filename)
589 branchstore = get_default_bazaar_branch_store()595 branchstore = get_default_bazaar_branch_store()
590 branch_transport = branchstore.transport
591 branch_name = '%08x' % source_details.branch_id596 branch_name = '%08x' % source_details.branch_id
592 if branchstore.transport.has(branch_name):597 if branchstore.transport.has(branch_name):
593 branchstore.transport.delete_tree(branch_name)598 branchstore.transport.delete_tree(branch_name)
@@ -615,8 +620,10 @@
615 raise NotImplementedError(620 raise NotImplementedError(
616 "Override this with a VCS-specific implementation.")621 "Override this with a VCS-specific implementation.")
617622
618 def commitInForeignTree(self, foreign_tree):623 def makeForeignCommit(self):
619 """Commit a single revision to `foreign_tree`.624 """Commit a revision to the repo described by `self.source_details`.
625
626 Increment `self.foreign_commit_count` as appropriate.
620627
621 Override this in your subclass.628 Override this in your subclass.
622 """629 """
@@ -626,6 +633,8 @@
626 def makeSourceDetails(self, module_name, files):633 def makeSourceDetails(self, module_name, files):
627 """Make a `CodeImportSourceDetails` that points to a real repository.634 """Make a `CodeImportSourceDetails` that points to a real repository.
628635
636 This should set `self.foreign_commit_count` to an appropriate value.
637
629 Override this in your subclass.638 Override this in your subclass.
630 """639 """
631 raise NotImplementedError(640 raise NotImplementedError(
@@ -656,18 +665,7 @@
656 self.foreign_commit_count, len(branch.revision_history()))665 self.foreign_commit_count, len(branch.revision_history()))
657666
658 # Change the remote branch.667 # Change the remote branch.
659668 self.makeForeignCommit()
660 tree_dir = self.makeTemporaryDirectory()
661 # This is pretty gross, but it works: the call to worker.run() will
662 # chdir() again to the worker's scratch directory, and in any case the
663 # tests subclass bzrlib's TestCaseInTempdir, so the directory will be
664 # restored at the end of the test.
665 os.chdir(tree_dir)
666 if isinstance(worker, CSCVSImportWorker):
667 foreign_tree = worker.foreign_tree_store.fetch(tree_dir)
668 else:
669 foreign_tree = None
670 self.commitInForeignTree(foreign_tree)
671669
672 # Run the same worker again.670 # Run the same worker again.
673 worker.run()671 worker.run()
@@ -736,15 +734,17 @@
736 super(TestCVSImport, self).setUp()734 super(TestCVSImport, self).setUp()
737 self.setUpImport()735 self.setUpImport()
738736
739 def commitInForeignTree(self, foreign_tree):737 def makeForeignCommit(self):
740 # If you write to a file in the same second as the previous commit,738 # If you write to a file in the same second as the previous commit,
741 # CVS will not think that it has changed.739 # CVS will not think that it has changed.
742 time.sleep(1)740 time.sleep(1)
743 self.build_tree_contents(741 repo = Repository(self.source_details.cvs_root, QuietFakeLogger())
744 [(os.path.join(foreign_tree.local_path, 'README'),742 repo.get(self.source_details.cvs_module, 'working_dir')
745 'New content')])743 wt = tree('working_dir')
746 foreign_tree.commit()744 self.build_tree_contents([('working_dir/README', 'New content')])
745 wt.commit(log='Log message')
747 self.foreign_commit_count += 1746 self.foreign_commit_count += 1
747 shutil.rmtree('working_dir')
748748
749 def makeSourceDetails(self, module_name, files):749 def makeSourceDetails(self, module_name, files):
750 """Make a CVS `CodeImportSourceDetails` pointing at a real CVS repo.750 """Make a CVS `CodeImportSourceDetails` pointing at a real CVS repo.
@@ -761,18 +761,14 @@
761 rcstype='cvs', cvs_root=cvs_server.getRoot(), cvs_module='trunk')761 rcstype='cvs', cvs_root=cvs_server.getRoot(), cvs_module='trunk')
762762
763763
764class TestSubversionImport(WorkerTest, CSCVSActualImportMixin):764class SubversionImportHelpers:
765 """Tests for the worker importing and syncing a Subversion branch."""765 """Implementations of `makeForeignCommit` and `makeSourceDetails` for svn.
766766 """
767 def setUp(self):767
768 WorkerTest.setUp(self)768 def makeForeignCommit(self):
769 self.setUpImport()769 """Change the foreign tree."""
770
771 def commitInForeignTree(self, foreign_tree):
772 """Change the foreign tree, generating exactly one commit."""
773 svn_url = foreign_tree.remote_url
774 client = pysvn.Client()770 client = pysvn.Client()
775 client.checkout(svn_url, 'working_tree')771 client.checkout(self.source_details.svn_branch_url, 'working_tree')
776 file = open('working_tree/newfile', 'w')772 file = open('working_tree/newfile', 'w')
777 file.write('No real content\n')773 file.write('No real content\n')
778 file.close()774 file.close()
@@ -789,10 +785,21 @@
789 self.addCleanup(svn_server.tearDown)785 self.addCleanup(svn_server.tearDown)
790786
791 svn_branch_url = svn_server.makeBranch(branch_name, files)787 svn_branch_url = svn_server.makeBranch(branch_name, files)
788 svn_branch_url = svn_branch_url.replace('://localhost/', ':///')
792 self.foreign_commit_count = 2789 self.foreign_commit_count = 2
793
794 return self.factory.makeCodeImportSourceDetails(790 return self.factory.makeCodeImportSourceDetails(
795 rcstype='svn', svn_branch_url=svn_branch_url)791 rcstype=self.rcstype, svn_branch_url=svn_branch_url)
792
793
794class TestSubversionImport(WorkerTest, SubversionImportHelpers,
795 CSCVSActualImportMixin):
796 """Tests for the worker importing and syncing a Subversion branch."""
797
798 rcstype = 'svn'
799
800 def setUp(self):
801 WorkerTest.setUp(self)
802 self.setUpImport()
796803
797804
798class TestGitImport(WorkerTest, TestActualImportMixin):805class TestGitImport(WorkerTest, TestActualImportMixin):
@@ -820,11 +827,11 @@
820 self.source_details, self.get_transport('import_data'),827 self.source_details, self.get_transport('import_data'),
821 self.bazaar_store, logging.getLogger())828 self.bazaar_store, logging.getLogger())
822829
823 def commitInForeignTree(self, foreign_tree):830 def makeForeignCommit(self):
824 """Change the foreign tree, generating exactly one commit."""831 """Change the foreign tree, generating exactly one commit."""
825 from bzrlib.plugins.git.tests import run_git832 from bzrlib.plugins.git.tests import run_git
826 wd = os.getcwd()833 wd = os.getcwd()
827 os.chdir(self.repository_path)834 os.chdir(self.source_details.git_repo_url)
828 try:835 try:
829 run_git('config', 'user.name', 'Joe Random Hacker')836 run_git('config', 'user.name', 'Joe Random Hacker')
830 run_git('commit', '-m', 'dsadas')837 run_git('commit', '-m', 'dsadas')
@@ -835,8 +842,8 @@
835 def makeSourceDetails(self, branch_name, files):842 def makeSourceDetails(self, branch_name, files):
836 """Make a Git `CodeImportSourceDetails` pointing at a real Git repo.843 """Make a Git `CodeImportSourceDetails` pointing at a real Git repo.
837 """844 """
838 self.repository_path = self.makeTemporaryDirectory()845 repository_path = self.makeTemporaryDirectory()
839 git_server = GitServer(self.repository_path)846 git_server = GitServer(repository_path)
840 git_server.setUp()847 git_server.setUp()
841 self.addCleanup(git_server.tearDown)848 self.addCleanup(git_server.tearDown)
842849
@@ -844,7 +851,32 @@
844 self.foreign_commit_count = 1851 self.foreign_commit_count = 1
845852
846 return self.factory.makeCodeImportSourceDetails(853 return self.factory.makeCodeImportSourceDetails(
847 rcstype='git', git_repo_url=self.repository_path)854 rcstype='git', git_repo_url=repository_path)
855
856
857class TestBzrSvnImport(WorkerTest, SubversionImportHelpers,
858 TestActualImportMixin):
859
860 rcstype = 'bzr-svn'
861
862 def setUp(self):
863 super(TestBzrSvnImport, self).setUp()
864 load_optional_plugin('svn')
865 self.setUpImport()
866 # XXX MichaelHudson, 2009-11-24, bug=464174:
867 # TestCaseWithMemoryTransport likes to set these environment variables
868 # to unicode strings and bzr-svn hits an assertion failure in this
869 # case.
870 os.environ['BZR_HOME'] = os.environ['BZR_HOME'].encode(
871 sys.getfilesystemencoding())
872 os.environ['HOME'] = os.environ['HOME'].encode(
873 sys.getfilesystemencoding())
874
875 def makeImportWorker(self):
876 """Make a new `ImportWorker`."""
877 return BzrSvnImportWorker(
878 self.source_details, self.get_transport('import_data'),
879 self.bazaar_store, logging.getLogger())
848880
849881
850def test_suite():882def test_suite():
851883
=== modified file 'lib/lp/codehosting/codeimport/tests/test_workermonitor.py'
--- lib/lp/codehosting/codeimport/tests/test_workermonitor.py 2009-11-21 01:08:05 +0000
+++ lib/lp/codehosting/codeimport/tests/test_workermonitor.py 2009-11-23 21:24:23 +0000
@@ -24,6 +24,7 @@
24from zope.security.proxy import removeSecurityProxy24from zope.security.proxy import removeSecurityProxy
2525
26from canonical.config import config26from canonical.config import config
27from canonical.launchpad.scripts.logger import QuietFakeLogger
27from canonical.testing.layers import (28from canonical.testing.layers import (
28 TwistedLayer, TwistedLaunchpadZopelessLayer)29 TwistedLayer, TwistedLaunchpadZopelessLayer)
29from canonical.twistedsupport.tests.test_processmonitor import (30from canonical.twistedsupport.tests.test_processmonitor import (
@@ -41,7 +42,7 @@
41 CodeImportWorkerMonitor, CodeImportWorkerMonitorProtocol, ExitQuietly,42 CodeImportWorkerMonitor, CodeImportWorkerMonitorProtocol, ExitQuietly,
42 read_only_transaction)43 read_only_transaction)
43from lp.codehosting.codeimport.tests.servers import (44from lp.codehosting.codeimport.tests.servers import (
44 CVSServer, GitServer, SubversionServer, _make_silent_logger)45 CVSServer, GitServer, SubversionServer)
45from lp.codehosting.codeimport.tests.test_worker import (46from lp.codehosting.codeimport.tests.test_worker import (
46 clean_up_default_stores_for_import)47 clean_up_default_stores_for_import)
47from lp.testing import login, logout48from lp.testing import login, logout
@@ -173,8 +174,7 @@
173 getUtility(ICodeImportJobWorkflow).startJob(174 getUtility(ICodeImportJobWorkflow).startJob(
174 job, self.factory.makeCodeImportMachine(set_online=True))175 job, self.factory.makeCodeImportMachine(set_online=True))
175 self.job_id = job.id176 self.job_id = job.id
176 self.worker_monitor = self.WorkerMonitor(177 self.worker_monitor = self.WorkerMonitor(job.id, QuietFakeLogger())
177 job.id, _make_silent_logger())
178 self.worker_monitor._failures = []178 self.worker_monitor._failures = []
179 self.layer.txn.commit()179 self.layer.txn.commit()
180 self.layer.switchDbUser('codeimportworker')180 self.layer.switchDbUser('codeimportworker')
@@ -349,8 +349,7 @@
349 getUtility(ICodeImportJobWorkflow).startJob(349 getUtility(ICodeImportJobWorkflow).startJob(
350 job, self.factory.makeCodeImportMachine(set_online=True))350 job, self.factory.makeCodeImportMachine(set_online=True))
351 self.job_id = job.id351 self.job_id = job.id
352 self.worker_monitor = self.WorkerMonitor(352 self.worker_monitor = self.WorkerMonitor(job.id, QuietFakeLogger())
353 job.id, _make_silent_logger())
354 self.worker_monitor.result_status = None353 self.worker_monitor.result_status = None
355 self.layer.txn.commit()354 self.layer.txn.commit()
356 self.layer.switchDbUser('codeimportworker')355 self.layer.switchDbUser('codeimportworker')
@@ -540,7 +539,7 @@
540 This implementation does it in-process.539 This implementation does it in-process.
541 """540 """
542 self.layer.switchDbUser('codeimportworker')541 self.layer.switchDbUser('codeimportworker')
543 monitor = CIWorkerMonitorForTesting(job_id, _make_silent_logger())542 monitor = CIWorkerMonitorForTesting(job_id, QuietFakeLogger())
544 deferred = monitor.run()543 deferred = monitor.run()
545 def save_protocol_object(result):544 def save_protocol_object(result):
546 """Save the process protocol object.545 """Save the process protocol object.
547546
=== modified file 'lib/lp/codehosting/codeimport/worker.py'
--- lib/lp/codehosting/codeimport/worker.py 2009-09-18 01:36:48 +0000
+++ lib/lp/codehosting/codeimport/worker.py 2009-11-23 21:24:23 +0000
@@ -6,18 +6,21 @@
6__metaclass__ = type6__metaclass__ = type
7__all__ = [7__all__ = [
8 'BazaarBranchStore',8 'BazaarBranchStore',
9 'BzrSvnImportWorker',
9 'CSCVSImportWorker',10 'CSCVSImportWorker',
10 'CodeImportSourceDetails',11 'CodeImportSourceDetails',
11 'ForeignTreeStore',12 'ForeignTreeStore',
13 'GitImportWorker',
12 'ImportWorker',14 'ImportWorker',
13 'get_default_bazaar_branch_store']15 'get_default_bazaar_branch_store',
16 ]
1417
1518
16import os19import os
17import shutil20import shutil
1821
19from bzrlib.branch import Branch22from bzrlib.branch import Branch
20from bzrlib.bzrdir import BzrDir, BzrDirFormat, format_registry23from bzrlib.bzrdir import BzrDir, BzrDirFormat
21from bzrlib.transport import get_transport24from bzrlib.transport import get_transport
22from bzrlib.errors import NoSuchFile, NotBranchError25from bzrlib.errors import NoSuchFile, NotBranchError
23import bzrlib.ui26import bzrlib.ui
@@ -105,9 +108,12 @@
105 :ivar branch_id: The id of the branch associated to this code import, used108 :ivar branch_id: The id of the branch associated to this code import, used
106 for locating the existing import and the foreign tree.109 for locating the existing import and the foreign tree.
107 :ivar rcstype: 'svn' or 'cvs' as appropriate.110 :ivar rcstype: 'svn' or 'cvs' as appropriate.
108 :ivar svn_branch_url: The branch URL if rcstype == 'svn', None otherwise.111 :ivar svn_branch_url: The branch URL if rcstype in ['svn', 'bzr-svn'],
112 None otherwise.
109 :ivar cvs_root: The $CVSROOT if rcstype == 'cvs', None otherwise.113 :ivar cvs_root: The $CVSROOT if rcstype == 'cvs', None otherwise.
110 :ivar cvs_module: The CVS module if rcstype == 'cvs', None otherwise.114 :ivar cvs_module: The CVS module if rcstype == 'cvs', None otherwise.
115 :ivar git_repo_url: The URL of the git repo, if rcstype == 'git', None,
116 otherwise.
111 """117 """
112118
113 def __init__(self, branch_id, rcstype, svn_branch_url=None, cvs_root=None,119 def __init__(self, branch_id, rcstype, svn_branch_url=None, cvs_root=None,
@@ -124,7 +130,7 @@
124 """Convert command line-style arguments to an instance."""130 """Convert command line-style arguments to an instance."""
125 branch_id = int(arguments.pop(0))131 branch_id = int(arguments.pop(0))
126 rcstype = arguments.pop(0)132 rcstype = arguments.pop(0)
127 if rcstype == 'svn':133 if rcstype in ['svn', 'bzr-svn']:
128 [svn_branch_url] = arguments134 [svn_branch_url] = arguments
129 cvs_root = cvs_module = git_repo_url = None135 cvs_root = cvs_module = git_repo_url = None
130 elif rcstype == 'cvs':136 elif rcstype == 'cvs':
@@ -165,7 +171,7 @@
165 """Return a list of arguments suitable for passing to a child process.171 """Return a list of arguments suitable for passing to a child process.
166 """172 """
167 result = [str(self.branch_id), self.rcstype]173 result = [str(self.branch_id), self.rcstype]
168 if self.rcstype == 'svn':174 if self.rcstype in ['svn', 'bzr-svn']:
169 result.append(self.svn_branch_url)175 result.append(self.svn_branch_url)
170 elif self.rcstype == 'cvs':176 elif self.rcstype == 'cvs':
171 result.append(self.cvs_root)177 result.append(self.cvs_root)
@@ -209,8 +215,8 @@
209 characters. For example 'tree.tar.gz' might become '0000a23d.tar.gz'215 characters. For example 'tree.tar.gz' might become '0000a23d.tar.gz'
210 or 'git.db' might become '00003e4.db'.216 or 'git.db' might become '00003e4.db'.
211217
212 :param local_name: The local name of the file to be stored. :return:218 :param local_name: The local name of the file to be stored.
213 The name to store the file as on the remote transport.219 :return: The name to store the file as on the remote transport.
214 """220 """
215 if '/' in local_name:221 if '/' in local_name:
216 raise AssertionError("local_name must be a name, not a path")222 raise AssertionError("local_name must be a name, not a path")
@@ -393,11 +399,13 @@
393 if os.path.exists(working_directory):399 if os.path.exists(working_directory):
394 shutil.rmtree(working_directory)400 shutil.rmtree(working_directory)
395 os.makedirs(working_directory)401 os.makedirs(working_directory)
402 saved_pwd = os.getcwd()
396 os.chdir(working_directory)403 os.chdir(working_directory)
397 try:404 try:
398 self._doImport()405 self._doImport()
399 finally:406 finally:
400 shutil.rmtree(working_directory)407 shutil.rmtree(working_directory)
408 os.chdir(saved_pwd)
401409
402 def _doImport(self):410 def _doImport(self):
403 raise NotImplementedError()411 raise NotImplementedError()
@@ -479,17 +487,25 @@
479487
480488
481class PullingImportWorker(ImportWorker):489class PullingImportWorker(ImportWorker):
482 """An import worker for imports that can be done by a bzr plugin."""490 """An import worker for imports that can be done by a bzr plugin.
491
492 Subclasses need to implement `pull_url`.
493 """
494 @property
495 def pull_url(self):
496 """Return the URL that should be pulled from."""
497 raise NotImplementedError
483498
484 def _doImport(self):499 def _doImport(self):
485 bazaar_tree = self.getBazaarWorkingTree()500 bazaar_tree = self.getBazaarWorkingTree()
501 self.bazaar_branch_store.push(
502 self.source_details.branch_id, bazaar_tree, self.required_format)
486 saved_factory = bzrlib.ui.ui_factory503 saved_factory = bzrlib.ui.ui_factory
487 bzrlib.ui.ui_factory = LoggingUIFactory(504 bzrlib.ui.ui_factory = LoggingUIFactory(
488 writer=lambda m: self._logger.info('%s', m))505 writer=lambda m: self._logger.info('%s', m))
489 try:506 try:
490 bazaar_tree.branch.pull(507 bazaar_tree.branch.pull(
491 Branch.open(self.source_details.git_repo_url),508 Branch.open(self.pull_url), overwrite=True)
492 overwrite=True)
493 finally:509 finally:
494 bzrlib.ui.ui_factory = saved_factory510 bzrlib.ui.ui_factory = saved_factory
495 self.pushBazaarWorkingTree(bazaar_tree)511 self.pushBazaarWorkingTree(bazaar_tree)
@@ -501,6 +517,11 @@
501 The only behaviour we add is preserving the 'git.db' shamap between runs.517 The only behaviour we add is preserving the 'git.db' shamap between runs.
502 """518 """
503519
520 @property
521 def pull_url(self):
522 """See `PullingImportWorker.pull_url`."""
523 return self.source_details.git_repo_url
524
504 def getBazaarWorkingTree(self):525 def getBazaarWorkingTree(self):
505 """See `ImportWorker.getBazaarWorkingTree`.526 """See `ImportWorker.getBazaarWorkingTree`.
506527
@@ -523,3 +544,12 @@
523 PullingImportWorker.pushBazaarWorkingTree(self, bazaar_tree)544 PullingImportWorker.pushBazaarWorkingTree(self, bazaar_tree)
524 self.import_data_store.put(545 self.import_data_store.put(
525 'git.db', bazaar_tree.branch.repository._transport)546 'git.db', bazaar_tree.branch.repository._transport)
547
548
549class BzrSvnImportWorker(PullingImportWorker):
550 """An import worker for importing Subversion via bzr-svn."""
551
552 @property
553 def pull_url(self):
554 """See `PullingImportWorker.pull_url`."""
555 return self.source_details.svn_branch_url
526556
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2009-11-20 15:42:50 +0000
+++ lib/lp/testing/factory.py 2009-11-23 21:24:23 +0000
@@ -1311,7 +1311,7 @@
1311 branch_id = self.getUniqueInteger()1311 branch_id = self.getUniqueInteger()
1312 if rcstype is None:1312 if rcstype is None:
1313 rcstype = 'svn'1313 rcstype = 'svn'
1314 if rcstype == 'svn':1314 if rcstype in ['svn', 'bzr-svn']:
1315 assert cvs_root is cvs_module is git_repo_url is None1315 assert cvs_root is cvs_module is git_repo_url is None
1316 if svn_branch_url is None:1316 if svn_branch_url is None:
1317 svn_branch_url = self.getUniqueURL()1317 svn_branch_url = self.getUniqueURL()
13181318
=== added symlink 'lib/subvertpy'
=== target is u'../sourcecode/subvertpy/subvertpy'
=== added symlink 'optionalbzrplugins/svn'
=== target is u'../sourcecode/bzr-svn'
=== modified file 'scripts/code-import-worker.py'
--- scripts/code-import-worker.py 2009-10-13 14:38:07 +0000
+++ scripts/code-import-worker.py 2009-11-23 21:24:23 +0000
@@ -25,12 +25,11 @@
25from canonical.config import config25from canonical.config import config
26from lp.codehosting import load_optional_plugin26from lp.codehosting import load_optional_plugin
27from lp.codehosting.codeimport.worker import (27from lp.codehosting.codeimport.worker import (
28 CSCVSImportWorker, CodeImportSourceDetails, GitImportWorker,28 BzrSvnImportWorker, CSCVSImportWorker, CodeImportSourceDetails,
29 get_default_bazaar_branch_store)29 GitImportWorker, get_default_bazaar_branch_store)
30from canonical.launchpad import scripts30from canonical.launchpad import scripts
3131
3232
33
34class CodeImportWorker:33class CodeImportWorker:
3534
36 def __init__(self):35 def __init__(self):
@@ -44,6 +43,9 @@
44 if source_details.rcstype == 'git':43 if source_details.rcstype == 'git':
45 load_optional_plugin('git')44 load_optional_plugin('git')
46 import_worker_cls = GitImportWorker45 import_worker_cls = GitImportWorker
46 elif source_details.rcstype == 'bzr-svn':
47 load_optional_plugin('svn')
48 import_worker_cls = BzrSvnImportWorker
47 else:49 else:
48 if source_details.rcstype not in ['cvs', 'svn']:50 if source_details.rcstype not in ['cvs', 'svn']:
49 raise AssertionError(51 raise AssertionError(
5052
=== modified file 'sourcecode/Makefile'
--- sourcecode/Makefile 2009-11-18 15:09:01 +0000
+++ sourcecode/Makefile 2009-11-23 21:24:23 +0000
@@ -4,7 +4,7 @@
4# the ones we test. If we fix them all to have EITHER a good makefile4# the ones we test. If we fix them all to have EITHER a good makefile
5# (build and check targets work), or no makefile we can reenable auto5# (build and check targets work), or no makefile we can reenable auto
6# detection.6# detection.
7build_dirs:=cscvs dulwich pygettextpo pygpgme twisted7build_dirs:=cscvs dulwich pygettextpo pygpgme twisted subvertpy
8test_dirs:=cscvs pygettextpo twisted8test_dirs:=cscvs pygettextpo twisted
99
10TEST_ENV_VARS = \10TEST_ENV_VARS = \