Merge lp:~mwhudson/launchpad/bzr-svn-imports into lp:launchpad
- bzr-svn-imports
- Merge into devel
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 |
Related bugs: |
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
Description of the change
To post a comment you must log in.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote : | # |
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
1 | === modified file 'lib/lp/codehosting/codeimport/tests/servers.py' | |||
2 | --- lib/lp/codehosting/codeimport/tests/servers.py 2009-06-30 16:56:07 +0000 | |||
3 | +++ lib/lp/codehosting/codeimport/tests/servers.py 2009-11-23 21:24:23 +0000 | |||
4 | @@ -11,7 +11,6 @@ | |||
5 | 11 | 11 | ||
6 | 12 | __metaclass__ = type | 12 | __metaclass__ = type |
7 | 13 | 13 | ||
8 | 14 | import logging | ||
9 | 15 | import os | 14 | import os |
10 | 16 | import shutil | 15 | import shutil |
11 | 17 | import tempfile | 16 | import tempfile |
12 | @@ -24,6 +23,7 @@ | |||
13 | 24 | from bzrlib.transport import Server | 23 | from bzrlib.transport import Server |
14 | 25 | from bzrlib.tests.treeshape import build_tree_contents | 24 | from bzrlib.tests.treeshape import build_tree_contents |
15 | 26 | 25 | ||
16 | 26 | from canonical.launchpad.scripts.logger import QuietFakeLogger | ||
17 | 27 | 27 | ||
18 | 28 | def local_path_to_url(local_path): | 28 | def local_path_to_url(local_path): |
19 | 29 | """Return a file:// URL to `local_path`. | 29 | """Return a file:// URL to `local_path`. |
20 | @@ -35,19 +35,6 @@ | |||
21 | 35 | os.path.normpath(os.path.abspath(local_path))) | 35 | os.path.normpath(os.path.abspath(local_path))) |
22 | 36 | 36 | ||
23 | 37 | 37 | ||
24 | 38 | def _make_silent_logger(): | ||
25 | 39 | """Create a logger that prints nothing.""" | ||
26 | 40 | |||
27 | 41 | class SilentLogHandler(logging.Handler): | ||
28 | 42 | def emit(self, record): | ||
29 | 43 | pass | ||
30 | 44 | |||
31 | 45 | logger = logging.Logger("collector") | ||
32 | 46 | handler = SilentLogHandler() | ||
33 | 47 | logger.addHandler(handler) | ||
34 | 48 | return logger | ||
35 | 49 | |||
36 | 50 | |||
37 | 51 | def run_in_temporary_directory(function): | 38 | def run_in_temporary_directory(function): |
38 | 52 | """Decorate `function` to be run in a temporary directory. | 39 | """Decorate `function` to be run in a temporary directory. |
39 | 53 | 40 | ||
40 | @@ -79,7 +66,7 @@ | |||
41 | 79 | 66 | ||
42 | 80 | def createRepository(self, path): | 67 | def createRepository(self, path): |
43 | 81 | """Create a Subversion repository at `path`.""" | 68 | """Create a Subversion repository at `path`.""" |
45 | 82 | svn_oo.Repository.Create(path, _make_silent_logger()) | 69 | svn_oo.Repository.Create(path, QuietFakeLogger()) |
46 | 83 | 70 | ||
47 | 84 | def get_url(self): | 71 | def get_url(self): |
48 | 85 | """Return a URL to the Subversion repository.""" | 72 | """Return a URL to the Subversion repository.""" |
49 | @@ -139,7 +126,7 @@ | |||
50 | 139 | :param path: The local path to create a repository in. | 126 | :param path: The local path to create a repository in. |
51 | 140 | :return: A CVS.Repository`. | 127 | :return: A CVS.Repository`. |
52 | 141 | """ | 128 | """ |
54 | 142 | return CVS.init(path, _make_silent_logger()) | 129 | return CVS.init(path, QuietFakeLogger()) |
55 | 143 | 130 | ||
56 | 144 | def getRoot(self): | 131 | def getRoot(self): |
57 | 145 | """Return the CVS root for this server.""" | 132 | """Return the CVS root for this server.""" |
58 | 146 | 133 | ||
59 | === modified file 'lib/lp/codehosting/codeimport/tests/test_dispatcher.py' | |||
60 | --- lib/lp/codehosting/codeimport/tests/test_dispatcher.py 2009-06-25 04:06:00 +0000 | |||
61 | +++ lib/lp/codehosting/codeimport/tests/test_dispatcher.py 2009-11-23 21:24:23 +0000 | |||
62 | @@ -10,7 +10,6 @@ | |||
63 | 10 | import os | 10 | import os |
64 | 11 | import shutil | 11 | import shutil |
65 | 12 | import socket | 12 | import socket |
66 | 13 | import sys | ||
67 | 14 | import tempfile | 13 | import tempfile |
68 | 15 | from textwrap import dedent | 14 | from textwrap import dedent |
69 | 16 | from unittest import TestLoader | 15 | from unittest import TestLoader |
70 | @@ -19,9 +18,8 @@ | |||
71 | 19 | 18 | ||
72 | 20 | from canonical.config import config | 19 | from canonical.config import config |
73 | 21 | from lp.codehosting.codeimport.dispatcher import CodeImportDispatcher | 20 | from lp.codehosting.codeimport.dispatcher import CodeImportDispatcher |
74 | 22 | from lp.codehosting.codeimport.tests.servers import ( | ||
75 | 23 | _make_silent_logger) | ||
76 | 24 | from canonical.launchpad import scripts | 21 | from canonical.launchpad import scripts |
77 | 22 | from canonical.launchpad.scripts.logger import QuietFakeLogger | ||
78 | 25 | from canonical.testing.layers import TwistedLaunchpadZopelessLayer | 23 | from canonical.testing.layers import TwistedLaunchpadZopelessLayer |
79 | 26 | 24 | ||
80 | 27 | 25 | ||
81 | @@ -43,7 +41,7 @@ | |||
82 | 43 | def setUp(self): | 41 | def setUp(self): |
83 | 44 | self.config_count = 0 | 42 | self.config_count = 0 |
84 | 45 | self.pushConfig(forced_hostname='none') | 43 | self.pushConfig(forced_hostname='none') |
86 | 46 | self.dispatcher = CodeImportDispatcher(_make_silent_logger()) | 44 | self.dispatcher = CodeImportDispatcher(QuietFakeLogger()) |
87 | 47 | 45 | ||
88 | 48 | def pushConfig(self, **args): | 46 | def pushConfig(self, **args): |
89 | 49 | """Push some key-value pairs into the codeimportdispatcher config. | 47 | """Push some key-value pairs into the codeimportdispatcher config. |
90 | 50 | 48 | ||
91 | === modified file 'lib/lp/codehosting/codeimport/tests/test_worker.py' | |||
92 | --- lib/lp/codehosting/codeimport/tests/test_worker.py 2009-11-21 00:28:10 +0000 | |||
93 | +++ lib/lp/codehosting/codeimport/tests/test_worker.py 2009-11-23 21:24:23 +0000 | |||
94 | @@ -9,6 +9,7 @@ | |||
95 | 9 | import os | 9 | import os |
96 | 10 | import shutil | 10 | import shutil |
97 | 11 | import subprocess | 11 | import subprocess |
98 | 12 | import sys | ||
99 | 12 | import tempfile | 13 | import tempfile |
100 | 13 | import time | 14 | import time |
101 | 14 | import unittest | 15 | import unittest |
102 | @@ -21,18 +22,23 @@ | |||
103 | 21 | from bzrlib.upgrade import upgrade | 22 | from bzrlib.upgrade import upgrade |
104 | 22 | from bzrlib.urlutils import join as urljoin | 23 | from bzrlib.urlutils import join as urljoin |
105 | 23 | 24 | ||
106 | 25 | from CVS import Repository, tree | ||
107 | 26 | |||
108 | 24 | from canonical.cachedproperty import cachedproperty | 27 | from canonical.cachedproperty import cachedproperty |
109 | 28 | from canonical.config import config | ||
110 | 29 | from canonical.launchpad.scripts.logger import QuietFakeLogger | ||
111 | 30 | from canonical.testing import BaseLayer | ||
112 | 31 | |||
113 | 25 | from lp.codehosting import load_optional_plugin | 32 | from lp.codehosting import load_optional_plugin |
114 | 26 | from lp.codehosting.codeimport.worker import ( | 33 | from lp.codehosting.codeimport.worker import ( |
117 | 27 | BazaarBranchStore, CSCVSImportWorker, ForeignTreeStore, GitImportWorker, | 34 | BazaarBranchStore, BzrSvnImportWorker, CSCVSImportWorker, |
118 | 28 | ImportDataStore, ImportWorker, get_default_bazaar_branch_store) | 35 | ForeignTreeStore, GitImportWorker, ImportDataStore, ImportWorker, |
119 | 36 | get_default_bazaar_branch_store) | ||
120 | 29 | from lp.codehosting.codeimport.tests.servers import ( | 37 | from lp.codehosting.codeimport.tests.servers import ( |
121 | 30 | CVSServer, GitServer, SubversionServer) | 38 | CVSServer, GitServer, SubversionServer) |
122 | 31 | from lp.codehosting.tests.helpers import ( | 39 | from lp.codehosting.tests.helpers import ( |
123 | 32 | create_branch_with_one_revision) | 40 | create_branch_with_one_revision) |
124 | 33 | from canonical.config import config | ||
125 | 34 | from lp.testing.factory import LaunchpadObjectFactory | 41 | from lp.testing.factory import LaunchpadObjectFactory |
126 | 35 | from canonical.testing import BaseLayer | ||
127 | 36 | 42 | ||
128 | 37 | import pysvn | 43 | import pysvn |
129 | 38 | 44 | ||
130 | @@ -120,7 +126,7 @@ | |||
131 | 120 | store = self.makeBranchStore() | 126 | store = self.makeBranchStore() |
132 | 121 | target_url = store._getMirrorURL(self.arbitrary_branch_id) | 127 | target_url = store._getMirrorURL(self.arbitrary_branch_id) |
133 | 122 | knit_format = format_registry.get('knit')() | 128 | knit_format = format_registry.get('knit')() |
135 | 123 | tree = create_branch_with_one_revision(target_url, format=knit_format) | 129 | create_branch_with_one_revision(target_url, format=knit_format) |
136 | 124 | default_format = BzrDirFormat.get_default_format() | 130 | default_format = BzrDirFormat.get_default_format() |
137 | 125 | 131 | ||
138 | 126 | # The fetched branch is in the default format. | 132 | # The fetched branch is in the default format. |
139 | @@ -142,7 +148,7 @@ | |||
140 | 142 | store = self.makeBranchStore() | 148 | store = self.makeBranchStore() |
141 | 143 | target_url = store._getMirrorURL(self.arbitrary_branch_id) | 149 | target_url = store._getMirrorURL(self.arbitrary_branch_id) |
142 | 144 | knit_format = format_registry.get('knit')() | 150 | knit_format = format_registry.get('knit')() |
144 | 145 | tree = create_branch_with_one_revision(target_url, format=knit_format) | 151 | create_branch_with_one_revision(target_url, format=knit_format) |
145 | 146 | upgrade(target_url, format_registry.get('dirstate-tags')()) | 152 | upgrade(target_url, format_registry.get('dirstate-tags')()) |
146 | 147 | self.failUnless(get_transport(target_url).has('backup.bzr')) | 153 | self.failUnless(get_transport(target_url).has('backup.bzr')) |
147 | 148 | default_format = BzrDirFormat.get_default_format() | 154 | default_format = BzrDirFormat.get_default_format() |
148 | @@ -587,7 +593,6 @@ | |||
149 | 587 | if filename.startswith(prefix): | 593 | if filename.startswith(prefix): |
150 | 588 | tree_transport.delete(filename) | 594 | tree_transport.delete(filename) |
151 | 589 | branchstore = get_default_bazaar_branch_store() | 595 | branchstore = get_default_bazaar_branch_store() |
152 | 590 | branch_transport = branchstore.transport | ||
153 | 591 | branch_name = '%08x' % source_details.branch_id | 596 | branch_name = '%08x' % source_details.branch_id |
154 | 592 | if branchstore.transport.has(branch_name): | 597 | if branchstore.transport.has(branch_name): |
155 | 593 | branchstore.transport.delete_tree(branch_name) | 598 | branchstore.transport.delete_tree(branch_name) |
156 | @@ -615,8 +620,10 @@ | |||
157 | 615 | raise NotImplementedError( | 620 | raise NotImplementedError( |
158 | 616 | "Override this with a VCS-specific implementation.") | 621 | "Override this with a VCS-specific implementation.") |
159 | 617 | 622 | ||
162 | 618 | def commitInForeignTree(self, foreign_tree): | 623 | def makeForeignCommit(self): |
163 | 619 | """Commit a single revision to `foreign_tree`. | 624 | """Commit a revision to the repo described by `self.source_details`. |
164 | 625 | |||
165 | 626 | Increment `self.foreign_commit_count` as appropriate. | ||
166 | 620 | 627 | ||
167 | 621 | Override this in your subclass. | 628 | Override this in your subclass. |
168 | 622 | """ | 629 | """ |
169 | @@ -626,6 +633,8 @@ | |||
170 | 626 | def makeSourceDetails(self, module_name, files): | 633 | def makeSourceDetails(self, module_name, files): |
171 | 627 | """Make a `CodeImportSourceDetails` that points to a real repository. | 634 | """Make a `CodeImportSourceDetails` that points to a real repository. |
172 | 628 | 635 | ||
173 | 636 | This should set `self.foreign_commit_count` to an appropriate value. | ||
174 | 637 | |||
175 | 629 | Override this in your subclass. | 638 | Override this in your subclass. |
176 | 630 | """ | 639 | """ |
177 | 631 | raise NotImplementedError( | 640 | raise NotImplementedError( |
178 | @@ -656,18 +665,7 @@ | |||
179 | 656 | self.foreign_commit_count, len(branch.revision_history())) | 665 | self.foreign_commit_count, len(branch.revision_history())) |
180 | 657 | 666 | ||
181 | 658 | # Change the remote branch. | 667 | # Change the remote branch. |
194 | 659 | 668 | self.makeForeignCommit() | |
183 | 660 | tree_dir = self.makeTemporaryDirectory() | ||
184 | 661 | # This is pretty gross, but it works: the call to worker.run() will | ||
185 | 662 | # chdir() again to the worker's scratch directory, and in any case the | ||
186 | 663 | # tests subclass bzrlib's TestCaseInTempdir, so the directory will be | ||
187 | 664 | # restored at the end of the test. | ||
188 | 665 | os.chdir(tree_dir) | ||
189 | 666 | if isinstance(worker, CSCVSImportWorker): | ||
190 | 667 | foreign_tree = worker.foreign_tree_store.fetch(tree_dir) | ||
191 | 668 | else: | ||
192 | 669 | foreign_tree = None | ||
193 | 670 | self.commitInForeignTree(foreign_tree) | ||
195 | 671 | 669 | ||
196 | 672 | # Run the same worker again. | 670 | # Run the same worker again. |
197 | 673 | worker.run() | 671 | worker.run() |
198 | @@ -736,15 +734,17 @@ | |||
199 | 736 | super(TestCVSImport, self).setUp() | 734 | super(TestCVSImport, self).setUp() |
200 | 737 | self.setUpImport() | 735 | self.setUpImport() |
201 | 738 | 736 | ||
203 | 739 | def commitInForeignTree(self, foreign_tree): | 737 | def makeForeignCommit(self): |
204 | 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, |
205 | 741 | # CVS will not think that it has changed. | 739 | # CVS will not think that it has changed. |
206 | 742 | time.sleep(1) | 740 | time.sleep(1) |
211 | 743 | self.build_tree_contents( | 741 | repo = Repository(self.source_details.cvs_root, QuietFakeLogger()) |
212 | 744 | [(os.path.join(foreign_tree.local_path, 'README'), | 742 | repo.get(self.source_details.cvs_module, 'working_dir') |
213 | 745 | 'New content')]) | 743 | wt = tree('working_dir') |
214 | 746 | foreign_tree.commit() | 744 | self.build_tree_contents([('working_dir/README', 'New content')]) |
215 | 745 | wt.commit(log='Log message') | ||
216 | 747 | self.foreign_commit_count += 1 | 746 | self.foreign_commit_count += 1 |
217 | 747 | shutil.rmtree('working_dir') | ||
218 | 748 | 748 | ||
219 | 749 | def makeSourceDetails(self, module_name, files): | 749 | def makeSourceDetails(self, module_name, files): |
220 | 750 | """Make a CVS `CodeImportSourceDetails` pointing at a real CVS repo. | 750 | """Make a CVS `CodeImportSourceDetails` pointing at a real CVS repo. |
221 | @@ -761,18 +761,14 @@ | |||
222 | 761 | rcstype='cvs', cvs_root=cvs_server.getRoot(), cvs_module='trunk') | 761 | rcstype='cvs', cvs_root=cvs_server.getRoot(), cvs_module='trunk') |
223 | 762 | 762 | ||
224 | 763 | 763 | ||
235 | 764 | class TestSubversionImport(WorkerTest, CSCVSActualImportMixin): | 764 | class SubversionImportHelpers: |
236 | 765 | """Tests for the worker importing and syncing a Subversion branch.""" | 765 | """Implementations of `makeForeignCommit` and `makeSourceDetails` for svn. |
237 | 766 | 766 | """ | |
238 | 767 | def setUp(self): | 767 | |
239 | 768 | WorkerTest.setUp(self) | 768 | def makeForeignCommit(self): |
240 | 769 | self.setUpImport() | 769 | """Change the foreign tree.""" |
231 | 770 | |||
232 | 771 | def commitInForeignTree(self, foreign_tree): | ||
233 | 772 | """Change the foreign tree, generating exactly one commit.""" | ||
234 | 773 | svn_url = foreign_tree.remote_url | ||
241 | 774 | client = pysvn.Client() | 770 | client = pysvn.Client() |
243 | 775 | client.checkout(svn_url, 'working_tree') | 771 | client.checkout(self.source_details.svn_branch_url, 'working_tree') |
244 | 776 | file = open('working_tree/newfile', 'w') | 772 | file = open('working_tree/newfile', 'w') |
245 | 777 | file.write('No real content\n') | 773 | file.write('No real content\n') |
246 | 778 | file.close() | 774 | file.close() |
247 | @@ -789,10 +785,21 @@ | |||
248 | 789 | self.addCleanup(svn_server.tearDown) | 785 | self.addCleanup(svn_server.tearDown) |
249 | 790 | 786 | ||
250 | 791 | svn_branch_url = svn_server.makeBranch(branch_name, files) | 787 | svn_branch_url = svn_server.makeBranch(branch_name, files) |
251 | 788 | svn_branch_url = svn_branch_url.replace('://localhost/', ':///') | ||
252 | 792 | self.foreign_commit_count = 2 | 789 | self.foreign_commit_count = 2 |
253 | 793 | |||
254 | 794 | return self.factory.makeCodeImportSourceDetails( | 790 | return self.factory.makeCodeImportSourceDetails( |
256 | 795 | rcstype='svn', svn_branch_url=svn_branch_url) | 791 | rcstype=self.rcstype, svn_branch_url=svn_branch_url) |
257 | 792 | |||
258 | 793 | |||
259 | 794 | class TestSubversionImport(WorkerTest, SubversionImportHelpers, | ||
260 | 795 | CSCVSActualImportMixin): | ||
261 | 796 | """Tests for the worker importing and syncing a Subversion branch.""" | ||
262 | 797 | |||
263 | 798 | rcstype = 'svn' | ||
264 | 799 | |||
265 | 800 | def setUp(self): | ||
266 | 801 | WorkerTest.setUp(self) | ||
267 | 802 | self.setUpImport() | ||
268 | 796 | 803 | ||
269 | 797 | 804 | ||
270 | 798 | class TestGitImport(WorkerTest, TestActualImportMixin): | 805 | class TestGitImport(WorkerTest, TestActualImportMixin): |
271 | @@ -820,11 +827,11 @@ | |||
272 | 820 | self.source_details, self.get_transport('import_data'), | 827 | self.source_details, self.get_transport('import_data'), |
273 | 821 | self.bazaar_store, logging.getLogger()) | 828 | self.bazaar_store, logging.getLogger()) |
274 | 822 | 829 | ||
276 | 823 | def commitInForeignTree(self, foreign_tree): | 830 | def makeForeignCommit(self): |
277 | 824 | """Change the foreign tree, generating exactly one commit.""" | 831 | """Change the foreign tree, generating exactly one commit.""" |
278 | 825 | from bzrlib.plugins.git.tests import run_git | 832 | from bzrlib.plugins.git.tests import run_git |
279 | 826 | wd = os.getcwd() | 833 | wd = os.getcwd() |
281 | 827 | os.chdir(self.repository_path) | 834 | os.chdir(self.source_details.git_repo_url) |
282 | 828 | try: | 835 | try: |
283 | 829 | run_git('config', 'user.name', 'Joe Random Hacker') | 836 | run_git('config', 'user.name', 'Joe Random Hacker') |
284 | 830 | run_git('commit', '-m', 'dsadas') | 837 | run_git('commit', '-m', 'dsadas') |
285 | @@ -835,8 +842,8 @@ | |||
286 | 835 | def makeSourceDetails(self, branch_name, files): | 842 | def makeSourceDetails(self, branch_name, files): |
287 | 836 | """Make a Git `CodeImportSourceDetails` pointing at a real Git repo. | 843 | """Make a Git `CodeImportSourceDetails` pointing at a real Git repo. |
288 | 837 | """ | 844 | """ |
291 | 838 | self.repository_path = self.makeTemporaryDirectory() | 845 | repository_path = self.makeTemporaryDirectory() |
292 | 839 | git_server = GitServer(self.repository_path) | 846 | git_server = GitServer(repository_path) |
293 | 840 | git_server.setUp() | 847 | git_server.setUp() |
294 | 841 | self.addCleanup(git_server.tearDown) | 848 | self.addCleanup(git_server.tearDown) |
295 | 842 | 849 | ||
296 | @@ -844,7 +851,32 @@ | |||
297 | 844 | self.foreign_commit_count = 1 | 851 | self.foreign_commit_count = 1 |
298 | 845 | 852 | ||
299 | 846 | return self.factory.makeCodeImportSourceDetails( | 853 | return self.factory.makeCodeImportSourceDetails( |
301 | 847 | rcstype='git', git_repo_url=self.repository_path) | 854 | rcstype='git', git_repo_url=repository_path) |
302 | 855 | |||
303 | 856 | |||
304 | 857 | class TestBzrSvnImport(WorkerTest, SubversionImportHelpers, | ||
305 | 858 | TestActualImportMixin): | ||
306 | 859 | |||
307 | 860 | rcstype = 'bzr-svn' | ||
308 | 861 | |||
309 | 862 | def setUp(self): | ||
310 | 863 | super(TestBzrSvnImport, self).setUp() | ||
311 | 864 | load_optional_plugin('svn') | ||
312 | 865 | self.setUpImport() | ||
313 | 866 | # XXX MichaelHudson, 2009-11-24, bug=464174: | ||
314 | 867 | # TestCaseWithMemoryTransport likes to set these environment variables | ||
315 | 868 | # to unicode strings and bzr-svn hits an assertion failure in this | ||
316 | 869 | # case. | ||
317 | 870 | os.environ['BZR_HOME'] = os.environ['BZR_HOME'].encode( | ||
318 | 871 | sys.getfilesystemencoding()) | ||
319 | 872 | os.environ['HOME'] = os.environ['HOME'].encode( | ||
320 | 873 | sys.getfilesystemencoding()) | ||
321 | 874 | |||
322 | 875 | def makeImportWorker(self): | ||
323 | 876 | """Make a new `ImportWorker`.""" | ||
324 | 877 | return BzrSvnImportWorker( | ||
325 | 878 | self.source_details, self.get_transport('import_data'), | ||
326 | 879 | self.bazaar_store, logging.getLogger()) | ||
327 | 848 | 880 | ||
328 | 849 | 881 | ||
329 | 850 | def test_suite(): | 882 | def test_suite(): |
330 | 851 | 883 | ||
331 | === modified file 'lib/lp/codehosting/codeimport/tests/test_workermonitor.py' | |||
332 | --- lib/lp/codehosting/codeimport/tests/test_workermonitor.py 2009-11-21 01:08:05 +0000 | |||
333 | +++ lib/lp/codehosting/codeimport/tests/test_workermonitor.py 2009-11-23 21:24:23 +0000 | |||
334 | @@ -24,6 +24,7 @@ | |||
335 | 24 | from zope.security.proxy import removeSecurityProxy | 24 | from zope.security.proxy import removeSecurityProxy |
336 | 25 | 25 | ||
337 | 26 | from canonical.config import config | 26 | from canonical.config import config |
338 | 27 | from canonical.launchpad.scripts.logger import QuietFakeLogger | ||
339 | 27 | from canonical.testing.layers import ( | 28 | from canonical.testing.layers import ( |
340 | 28 | TwistedLayer, TwistedLaunchpadZopelessLayer) | 29 | TwistedLayer, TwistedLaunchpadZopelessLayer) |
341 | 29 | from canonical.twistedsupport.tests.test_processmonitor import ( | 30 | from canonical.twistedsupport.tests.test_processmonitor import ( |
342 | @@ -41,7 +42,7 @@ | |||
343 | 41 | CodeImportWorkerMonitor, CodeImportWorkerMonitorProtocol, ExitQuietly, | 42 | CodeImportWorkerMonitor, CodeImportWorkerMonitorProtocol, ExitQuietly, |
344 | 42 | read_only_transaction) | 43 | read_only_transaction) |
345 | 43 | from lp.codehosting.codeimport.tests.servers import ( | 44 | from lp.codehosting.codeimport.tests.servers import ( |
347 | 44 | CVSServer, GitServer, SubversionServer, _make_silent_logger) | 45 | CVSServer, GitServer, SubversionServer) |
348 | 45 | from lp.codehosting.codeimport.tests.test_worker import ( | 46 | from lp.codehosting.codeimport.tests.test_worker import ( |
349 | 46 | clean_up_default_stores_for_import) | 47 | clean_up_default_stores_for_import) |
350 | 47 | from lp.testing import login, logout | 48 | from lp.testing import login, logout |
351 | @@ -173,8 +174,7 @@ | |||
352 | 173 | getUtility(ICodeImportJobWorkflow).startJob( | 174 | getUtility(ICodeImportJobWorkflow).startJob( |
353 | 174 | job, self.factory.makeCodeImportMachine(set_online=True)) | 175 | job, self.factory.makeCodeImportMachine(set_online=True)) |
354 | 175 | self.job_id = job.id | 176 | self.job_id = job.id |
357 | 176 | self.worker_monitor = self.WorkerMonitor( | 177 | self.worker_monitor = self.WorkerMonitor(job.id, QuietFakeLogger()) |
356 | 177 | job.id, _make_silent_logger()) | ||
358 | 178 | self.worker_monitor._failures = [] | 178 | self.worker_monitor._failures = [] |
359 | 179 | self.layer.txn.commit() | 179 | self.layer.txn.commit() |
360 | 180 | self.layer.switchDbUser('codeimportworker') | 180 | self.layer.switchDbUser('codeimportworker') |
361 | @@ -349,8 +349,7 @@ | |||
362 | 349 | getUtility(ICodeImportJobWorkflow).startJob( | 349 | getUtility(ICodeImportJobWorkflow).startJob( |
363 | 350 | job, self.factory.makeCodeImportMachine(set_online=True)) | 350 | job, self.factory.makeCodeImportMachine(set_online=True)) |
364 | 351 | self.job_id = job.id | 351 | self.job_id = job.id |
367 | 352 | self.worker_monitor = self.WorkerMonitor( | 352 | self.worker_monitor = self.WorkerMonitor(job.id, QuietFakeLogger()) |
366 | 353 | job.id, _make_silent_logger()) | ||
368 | 354 | self.worker_monitor.result_status = None | 353 | self.worker_monitor.result_status = None |
369 | 355 | self.layer.txn.commit() | 354 | self.layer.txn.commit() |
370 | 356 | self.layer.switchDbUser('codeimportworker') | 355 | self.layer.switchDbUser('codeimportworker') |
371 | @@ -540,7 +539,7 @@ | |||
372 | 540 | This implementation does it in-process. | 539 | This implementation does it in-process. |
373 | 541 | """ | 540 | """ |
374 | 542 | self.layer.switchDbUser('codeimportworker') | 541 | self.layer.switchDbUser('codeimportworker') |
376 | 543 | monitor = CIWorkerMonitorForTesting(job_id, _make_silent_logger()) | 542 | monitor = CIWorkerMonitorForTesting(job_id, QuietFakeLogger()) |
377 | 544 | deferred = monitor.run() | 543 | deferred = monitor.run() |
378 | 545 | def save_protocol_object(result): | 544 | def save_protocol_object(result): |
379 | 546 | """Save the process protocol object. | 545 | """Save the process protocol object. |
380 | 547 | 546 | ||
381 | === modified file 'lib/lp/codehosting/codeimport/worker.py' | |||
382 | --- lib/lp/codehosting/codeimport/worker.py 2009-09-18 01:36:48 +0000 | |||
383 | +++ lib/lp/codehosting/codeimport/worker.py 2009-11-23 21:24:23 +0000 | |||
384 | @@ -6,18 +6,21 @@ | |||
385 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
386 | 7 | __all__ = [ | 7 | __all__ = [ |
387 | 8 | 'BazaarBranchStore', | 8 | 'BazaarBranchStore', |
388 | 9 | 'BzrSvnImportWorker', | ||
389 | 9 | 'CSCVSImportWorker', | 10 | 'CSCVSImportWorker', |
390 | 10 | 'CodeImportSourceDetails', | 11 | 'CodeImportSourceDetails', |
391 | 11 | 'ForeignTreeStore', | 12 | 'ForeignTreeStore', |
392 | 13 | 'GitImportWorker', | ||
393 | 12 | 'ImportWorker', | 14 | 'ImportWorker', |
395 | 13 | 'get_default_bazaar_branch_store'] | 15 | 'get_default_bazaar_branch_store', |
396 | 16 | ] | ||
397 | 14 | 17 | ||
398 | 15 | 18 | ||
399 | 16 | import os | 19 | import os |
400 | 17 | import shutil | 20 | import shutil |
401 | 18 | 21 | ||
402 | 19 | from bzrlib.branch import Branch | 22 | from bzrlib.branch import Branch |
404 | 20 | from bzrlib.bzrdir import BzrDir, BzrDirFormat, format_registry | 23 | from bzrlib.bzrdir import BzrDir, BzrDirFormat |
405 | 21 | from bzrlib.transport import get_transport | 24 | from bzrlib.transport import get_transport |
406 | 22 | from bzrlib.errors import NoSuchFile, NotBranchError | 25 | from bzrlib.errors import NoSuchFile, NotBranchError |
407 | 23 | import bzrlib.ui | 26 | import bzrlib.ui |
408 | @@ -105,9 +108,12 @@ | |||
409 | 105 | :ivar branch_id: The id of the branch associated to this code import, used | 108 | :ivar branch_id: The id of the branch associated to this code import, used |
410 | 106 | for locating the existing import and the foreign tree. | 109 | for locating the existing import and the foreign tree. |
411 | 107 | :ivar rcstype: 'svn' or 'cvs' as appropriate. | 110 | :ivar rcstype: 'svn' or 'cvs' as appropriate. |
413 | 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'], |
414 | 112 | None otherwise. | ||
415 | 109 | :ivar cvs_root: The $CVSROOT if rcstype == 'cvs', None otherwise. | 113 | :ivar cvs_root: The $CVSROOT if rcstype == 'cvs', None otherwise. |
416 | 110 | :ivar cvs_module: The CVS module if rcstype == 'cvs', None otherwise. | 114 | :ivar cvs_module: The CVS module if rcstype == 'cvs', None otherwise. |
417 | 115 | :ivar git_repo_url: The URL of the git repo, if rcstype == 'git', None, | ||
418 | 116 | otherwise. | ||
419 | 111 | """ | 117 | """ |
420 | 112 | 118 | ||
421 | 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, |
422 | @@ -124,7 +130,7 @@ | |||
423 | 124 | """Convert command line-style arguments to an instance.""" | 130 | """Convert command line-style arguments to an instance.""" |
424 | 125 | branch_id = int(arguments.pop(0)) | 131 | branch_id = int(arguments.pop(0)) |
425 | 126 | rcstype = arguments.pop(0) | 132 | rcstype = arguments.pop(0) |
427 | 127 | if rcstype == 'svn': | 133 | if rcstype in ['svn', 'bzr-svn']: |
428 | 128 | [svn_branch_url] = arguments | 134 | [svn_branch_url] = arguments |
429 | 129 | cvs_root = cvs_module = git_repo_url = None | 135 | cvs_root = cvs_module = git_repo_url = None |
430 | 130 | elif rcstype == 'cvs': | 136 | elif rcstype == 'cvs': |
431 | @@ -165,7 +171,7 @@ | |||
432 | 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. |
433 | 166 | """ | 172 | """ |
434 | 167 | result = [str(self.branch_id), self.rcstype] | 173 | result = [str(self.branch_id), self.rcstype] |
436 | 168 | if self.rcstype == 'svn': | 174 | if self.rcstype in ['svn', 'bzr-svn']: |
437 | 169 | result.append(self.svn_branch_url) | 175 | result.append(self.svn_branch_url) |
438 | 170 | elif self.rcstype == 'cvs': | 176 | elif self.rcstype == 'cvs': |
439 | 171 | result.append(self.cvs_root) | 177 | result.append(self.cvs_root) |
440 | @@ -209,8 +215,8 @@ | |||
441 | 209 | characters. For example 'tree.tar.gz' might become '0000a23d.tar.gz' | 215 | characters. For example 'tree.tar.gz' might become '0000a23d.tar.gz' |
442 | 210 | or 'git.db' might become '00003e4.db'. | 216 | or 'git.db' might become '00003e4.db'. |
443 | 211 | 217 | ||
446 | 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. |
447 | 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. |
448 | 214 | """ | 220 | """ |
449 | 215 | if '/' in local_name: | 221 | if '/' in local_name: |
450 | 216 | raise AssertionError("local_name must be a name, not a path") | 222 | raise AssertionError("local_name must be a name, not a path") |
451 | @@ -393,11 +399,13 @@ | |||
452 | 393 | if os.path.exists(working_directory): | 399 | if os.path.exists(working_directory): |
453 | 394 | shutil.rmtree(working_directory) | 400 | shutil.rmtree(working_directory) |
454 | 395 | os.makedirs(working_directory) | 401 | os.makedirs(working_directory) |
455 | 402 | saved_pwd = os.getcwd() | ||
456 | 396 | os.chdir(working_directory) | 403 | os.chdir(working_directory) |
457 | 397 | try: | 404 | try: |
458 | 398 | self._doImport() | 405 | self._doImport() |
459 | 399 | finally: | 406 | finally: |
460 | 400 | shutil.rmtree(working_directory) | 407 | shutil.rmtree(working_directory) |
461 | 408 | os.chdir(saved_pwd) | ||
462 | 401 | 409 | ||
463 | 402 | def _doImport(self): | 410 | def _doImport(self): |
464 | 403 | raise NotImplementedError() | 411 | raise NotImplementedError() |
465 | @@ -479,17 +487,25 @@ | |||
466 | 479 | 487 | ||
467 | 480 | 488 | ||
468 | 481 | class PullingImportWorker(ImportWorker): | 489 | class PullingImportWorker(ImportWorker): |
470 | 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. |
471 | 491 | |||
472 | 492 | Subclasses need to implement `pull_url`. | ||
473 | 493 | """ | ||
474 | 494 | @property | ||
475 | 495 | def pull_url(self): | ||
476 | 496 | """Return the URL that should be pulled from.""" | ||
477 | 497 | raise NotImplementedError | ||
478 | 483 | 498 | ||
479 | 484 | def _doImport(self): | 499 | def _doImport(self): |
480 | 485 | bazaar_tree = self.getBazaarWorkingTree() | 500 | bazaar_tree = self.getBazaarWorkingTree() |
481 | 501 | self.bazaar_branch_store.push( | ||
482 | 502 | self.source_details.branch_id, bazaar_tree, self.required_format) | ||
483 | 486 | saved_factory = bzrlib.ui.ui_factory | 503 | saved_factory = bzrlib.ui.ui_factory |
484 | 487 | bzrlib.ui.ui_factory = LoggingUIFactory( | 504 | bzrlib.ui.ui_factory = LoggingUIFactory( |
485 | 488 | writer=lambda m: self._logger.info('%s', m)) | 505 | writer=lambda m: self._logger.info('%s', m)) |
486 | 489 | try: | 506 | try: |
487 | 490 | bazaar_tree.branch.pull( | 507 | bazaar_tree.branch.pull( |
490 | 491 | Branch.open(self.source_details.git_repo_url), | 508 | Branch.open(self.pull_url), overwrite=True) |
489 | 492 | overwrite=True) | ||
491 | 493 | finally: | 509 | finally: |
492 | 494 | bzrlib.ui.ui_factory = saved_factory | 510 | bzrlib.ui.ui_factory = saved_factory |
493 | 495 | self.pushBazaarWorkingTree(bazaar_tree) | 511 | self.pushBazaarWorkingTree(bazaar_tree) |
494 | @@ -501,6 +517,11 @@ | |||
495 | 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. |
496 | 502 | """ | 518 | """ |
497 | 503 | 519 | ||
498 | 520 | @property | ||
499 | 521 | def pull_url(self): | ||
500 | 522 | """See `PullingImportWorker.pull_url`.""" | ||
501 | 523 | return self.source_details.git_repo_url | ||
502 | 524 | |||
503 | 504 | def getBazaarWorkingTree(self): | 525 | def getBazaarWorkingTree(self): |
504 | 505 | """See `ImportWorker.getBazaarWorkingTree`. | 526 | """See `ImportWorker.getBazaarWorkingTree`. |
505 | 506 | 527 | ||
506 | @@ -523,3 +544,12 @@ | |||
507 | 523 | PullingImportWorker.pushBazaarWorkingTree(self, bazaar_tree) | 544 | PullingImportWorker.pushBazaarWorkingTree(self, bazaar_tree) |
508 | 524 | self.import_data_store.put( | 545 | self.import_data_store.put( |
509 | 525 | 'git.db', bazaar_tree.branch.repository._transport) | 546 | 'git.db', bazaar_tree.branch.repository._transport) |
510 | 547 | |||
511 | 548 | |||
512 | 549 | class BzrSvnImportWorker(PullingImportWorker): | ||
513 | 550 | """An import worker for importing Subversion via bzr-svn.""" | ||
514 | 551 | |||
515 | 552 | @property | ||
516 | 553 | def pull_url(self): | ||
517 | 554 | """See `PullingImportWorker.pull_url`.""" | ||
518 | 555 | return self.source_details.svn_branch_url | ||
519 | 526 | 556 | ||
520 | === modified file 'lib/lp/testing/factory.py' | |||
521 | --- lib/lp/testing/factory.py 2009-11-20 15:42:50 +0000 | |||
522 | +++ lib/lp/testing/factory.py 2009-11-23 21:24:23 +0000 | |||
523 | @@ -1311,7 +1311,7 @@ | |||
524 | 1311 | branch_id = self.getUniqueInteger() | 1311 | branch_id = self.getUniqueInteger() |
525 | 1312 | if rcstype is None: | 1312 | if rcstype is None: |
526 | 1313 | rcstype = 'svn' | 1313 | rcstype = 'svn' |
528 | 1314 | if rcstype == 'svn': | 1314 | if rcstype in ['svn', 'bzr-svn']: |
529 | 1315 | assert cvs_root is cvs_module is git_repo_url is None | 1315 | assert cvs_root is cvs_module is git_repo_url is None |
530 | 1316 | if svn_branch_url is None: | 1316 | if svn_branch_url is None: |
531 | 1317 | svn_branch_url = self.getUniqueURL() | 1317 | svn_branch_url = self.getUniqueURL() |
532 | 1318 | 1318 | ||
533 | === added symlink 'lib/subvertpy' | |||
534 | === target is u'../sourcecode/subvertpy/subvertpy' | |||
535 | === added symlink 'optionalbzrplugins/svn' | |||
536 | === target is u'../sourcecode/bzr-svn' | |||
537 | === modified file 'scripts/code-import-worker.py' | |||
538 | --- scripts/code-import-worker.py 2009-10-13 14:38:07 +0000 | |||
539 | +++ scripts/code-import-worker.py 2009-11-23 21:24:23 +0000 | |||
540 | @@ -25,12 +25,11 @@ | |||
541 | 25 | from canonical.config import config | 25 | from canonical.config import config |
542 | 26 | from lp.codehosting import load_optional_plugin | 26 | from lp.codehosting import load_optional_plugin |
543 | 27 | from lp.codehosting.codeimport.worker import ( | 27 | from lp.codehosting.codeimport.worker import ( |
546 | 28 | CSCVSImportWorker, CodeImportSourceDetails, GitImportWorker, | 28 | BzrSvnImportWorker, CSCVSImportWorker, CodeImportSourceDetails, |
547 | 29 | get_default_bazaar_branch_store) | 29 | GitImportWorker, get_default_bazaar_branch_store) |
548 | 30 | from canonical.launchpad import scripts | 30 | from canonical.launchpad import scripts |
549 | 31 | 31 | ||
550 | 32 | 32 | ||
551 | 33 | |||
552 | 34 | class CodeImportWorker: | 33 | class CodeImportWorker: |
553 | 35 | 34 | ||
554 | 36 | def __init__(self): | 35 | def __init__(self): |
555 | @@ -44,6 +43,9 @@ | |||
556 | 44 | if source_details.rcstype == 'git': | 43 | if source_details.rcstype == 'git': |
557 | 45 | load_optional_plugin('git') | 44 | load_optional_plugin('git') |
558 | 46 | import_worker_cls = GitImportWorker | 45 | import_worker_cls = GitImportWorker |
559 | 46 | elif source_details.rcstype == 'bzr-svn': | ||
560 | 47 | load_optional_plugin('svn') | ||
561 | 48 | import_worker_cls = BzrSvnImportWorker | ||
562 | 47 | else: | 49 | else: |
563 | 48 | if source_details.rcstype not in ['cvs', 'svn']: | 50 | if source_details.rcstype not in ['cvs', 'svn']: |
564 | 49 | raise AssertionError( | 51 | raise AssertionError( |
565 | 50 | 52 | ||
566 | === modified file 'sourcecode/Makefile' | |||
567 | --- sourcecode/Makefile 2009-11-18 15:09:01 +0000 | |||
568 | +++ sourcecode/Makefile 2009-11-23 21:24:23 +0000 | |||
569 | @@ -4,7 +4,7 @@ | |||
570 | 4 | # the ones we test. If we fix them all to have EITHER a good makefile | 4 | # the ones we test. If we fix them all to have EITHER a good makefile |
571 | 5 | # (build and check targets work), or no makefile we can reenable auto | 5 | # (build and check targets work), or no makefile we can reenable auto |
572 | 6 | # detection. | 6 | # detection. |
574 | 7 | build_dirs:=cscvs dulwich pygettextpo pygpgme twisted | 7 | build_dirs:=cscvs dulwich pygettextpo pygpgme twisted subvertpy |
575 | 8 | test_dirs:=cscvs pygettextpo twisted | 8 | test_dirs:=cscvs pygettextpo twisted |
576 | 9 | 9 | ||
577 | 10 | TEST_ENV_VARS = \ | 10 | TEST_ENV_VARS = \ |
This branch adds support for bzr-svn to the code import worker, the lowest level of the code import system.