Merge lp:~jelmer/bzr/sprout-to-bzrdir into lp:bzr
- sprout-to-bzrdir
- Merge into bzr.dev
Proposed by
Jelmer Vernooij
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Jelmer Vernooij | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 5738 | ||||
Proposed branch: | lp:~jelmer/bzr/sprout-to-bzrdir | ||||
Merge into: | lp:bzr | ||||
Diff against target: |
357 lines (+163/-130) 3 files modified
bzrlib/bzrdir.py (+158/-0) bzrlib/controldir.py (+1/-130) doc/en/release-notes/bzr-2.4.txt (+4/-0) |
||||
To merge this branch: | bzr merge lp:~jelmer/bzr/sprout-to-bzrdir | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Bennetts | Approve | ||
Review via email: mp+54561@code.launchpad.net |
Commit message
Move bzr-specific implementation of ControlDir.sprout to Bzrdir.
Description of the change
Move the implementation of ControlDir.sprout() to BzrDir.sprout(). Instead, simply raise NotImplementedE
The current implementation is too BzrDir-specific, so it makes more sense to just have the foreign plugins provide their own implementation.
To post a comment you must log in.
Revision history for this message
Andrew Bennetts (spiv) wrote : | # |
(Don't forget to mention this in release-notes)
Revision history for this message
Jelmer Vernooij (jelmer) wrote : | # |
sent to pqm by email
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bzrlib/bzrdir.py' |
2 | --- bzrlib/bzrdir.py 2011-03-22 12:11:20 +0000 |
3 | +++ bzrlib/bzrdir.py 2011-03-24 00:18:30 +0000 |
4 | @@ -33,9 +33,11 @@ |
5 | |
6 | import bzrlib |
7 | from bzrlib import ( |
8 | + cleanup, |
9 | config, |
10 | controldir, |
11 | errors, |
12 | + fetch, |
13 | graph, |
14 | lockable_files, |
15 | lockdir, |
16 | @@ -60,6 +62,7 @@ |
17 | """) |
18 | |
19 | from bzrlib.trace import ( |
20 | + mutter, |
21 | note, |
22 | ) |
23 | |
24 | @@ -387,6 +390,161 @@ |
25 | policy = self.determine_repository_policy(force_new_repo) |
26 | return policy.acquire_repository()[0] |
27 | |
28 | + def _find_source_repo(self, add_cleanup, source_branch): |
29 | + """Find the source branch and repo for a sprout operation. |
30 | + |
31 | + This is helper intended for use by _sprout. |
32 | + |
33 | + :returns: (source_branch, source_repository). Either or both may be |
34 | + None. If not None, they will be read-locked (and their unlock(s) |
35 | + scheduled via the add_cleanup param). |
36 | + """ |
37 | + if source_branch is not None: |
38 | + add_cleanup(source_branch.lock_read().unlock) |
39 | + return source_branch, source_branch.repository |
40 | + try: |
41 | + source_branch = self.open_branch() |
42 | + source_repository = source_branch.repository |
43 | + except errors.NotBranchError: |
44 | + source_branch = None |
45 | + try: |
46 | + source_repository = self.open_repository() |
47 | + except errors.NoRepositoryPresent: |
48 | + source_repository = None |
49 | + else: |
50 | + add_cleanup(source_repository.lock_read().unlock) |
51 | + else: |
52 | + add_cleanup(source_branch.lock_read().unlock) |
53 | + return source_branch, source_repository |
54 | + |
55 | + def sprout(self, url, revision_id=None, force_new_repo=False, |
56 | + recurse='down', possible_transports=None, |
57 | + accelerator_tree=None, hardlink=False, stacked=False, |
58 | + source_branch=None, create_tree_if_local=True): |
59 | + """Create a copy of this controldir prepared for use as a new line of |
60 | + development. |
61 | + |
62 | + If url's last component does not exist, it will be created. |
63 | + |
64 | + Attributes related to the identity of the source branch like |
65 | + branch nickname will be cleaned, a working tree is created |
66 | + whether one existed before or not; and a local branch is always |
67 | + created. |
68 | + |
69 | + if revision_id is not None, then the clone operation may tune |
70 | + itself to download less data. |
71 | + :param accelerator_tree: A tree which can be used for retrieving file |
72 | + contents more quickly than the revision tree, i.e. a workingtree. |
73 | + The revision tree will be used for cases where accelerator_tree's |
74 | + content is different. |
75 | + :param hardlink: If true, hard-link files from accelerator_tree, |
76 | + where possible. |
77 | + :param stacked: If true, create a stacked branch referring to the |
78 | + location of this control directory. |
79 | + :param create_tree_if_local: If true, a working-tree will be created |
80 | + when working locally. |
81 | + """ |
82 | + operation = cleanup.OperationWithCleanups(self._sprout) |
83 | + return operation.run(url, revision_id=revision_id, |
84 | + force_new_repo=force_new_repo, recurse=recurse, |
85 | + possible_transports=possible_transports, |
86 | + accelerator_tree=accelerator_tree, hardlink=hardlink, |
87 | + stacked=stacked, source_branch=source_branch, |
88 | + create_tree_if_local=create_tree_if_local) |
89 | + |
90 | + def _sprout(self, op, url, revision_id=None, force_new_repo=False, |
91 | + recurse='down', possible_transports=None, |
92 | + accelerator_tree=None, hardlink=False, stacked=False, |
93 | + source_branch=None, create_tree_if_local=True): |
94 | + add_cleanup = op.add_cleanup |
95 | + fetch_spec_factory = fetch.FetchSpecFactory() |
96 | + if revision_id is not None: |
97 | + fetch_spec_factory.add_revision_ids([revision_id]) |
98 | + fetch_spec_factory.source_branch_stop_revision_id = revision_id |
99 | + target_transport = _mod_transport.get_transport(url, |
100 | + possible_transports) |
101 | + target_transport.ensure_base() |
102 | + cloning_format = self.cloning_metadir(stacked) |
103 | + # Create/update the result branch |
104 | + result = cloning_format.initialize_on_transport(target_transport) |
105 | + source_branch, source_repository = self._find_source_repo( |
106 | + add_cleanup, source_branch) |
107 | + fetch_spec_factory.source_branch = source_branch |
108 | + # if a stacked branch wasn't requested, we don't create one |
109 | + # even if the origin was stacked |
110 | + if stacked and source_branch is not None: |
111 | + stacked_branch_url = self.root_transport.base |
112 | + else: |
113 | + stacked_branch_url = None |
114 | + repository_policy = result.determine_repository_policy( |
115 | + force_new_repo, stacked_branch_url, require_stacking=stacked) |
116 | + result_repo, is_new_repo = repository_policy.acquire_repository() |
117 | + add_cleanup(result_repo.lock_write().unlock) |
118 | + fetch_spec_factory.source_repo = source_repository |
119 | + fetch_spec_factory.target_repo = result_repo |
120 | + if stacked or (len(result_repo._fallback_repositories) != 0): |
121 | + target_repo_kind = fetch.TargetRepoKinds.STACKED |
122 | + elif is_new_repo: |
123 | + target_repo_kind = fetch.TargetRepoKinds.EMPTY |
124 | + else: |
125 | + target_repo_kind = fetch.TargetRepoKinds.PREEXISTING |
126 | + fetch_spec_factory.target_repo_kind = target_repo_kind |
127 | + if source_repository is not None: |
128 | + fetch_spec = fetch_spec_factory.make_fetch_spec() |
129 | + result_repo.fetch(source_repository, fetch_spec=fetch_spec) |
130 | + |
131 | + if source_branch is None: |
132 | + # this is for sprouting a controldir without a branch; is that |
133 | + # actually useful? |
134 | + # Not especially, but it's part of the contract. |
135 | + result_branch = result.create_branch() |
136 | + else: |
137 | + result_branch = source_branch.sprout(result, |
138 | + revision_id=revision_id, repository_policy=repository_policy, |
139 | + repository=result_repo) |
140 | + mutter("created new branch %r" % (result_branch,)) |
141 | + |
142 | + # Create/update the result working tree |
143 | + if (create_tree_if_local and |
144 | + isinstance(target_transport, local.LocalTransport) and |
145 | + (result_repo is None or result_repo.make_working_trees())): |
146 | + wt = result.create_workingtree(accelerator_tree=accelerator_tree, |
147 | + hardlink=hardlink, from_branch=result_branch) |
148 | + wt.lock_write() |
149 | + try: |
150 | + if wt.path2id('') is None: |
151 | + try: |
152 | + wt.set_root_id(self.open_workingtree.get_root_id()) |
153 | + except errors.NoWorkingTree: |
154 | + pass |
155 | + finally: |
156 | + wt.unlock() |
157 | + else: |
158 | + wt = None |
159 | + if recurse == 'down': |
160 | + basis = None |
161 | + if wt is not None: |
162 | + basis = wt.basis_tree() |
163 | + elif result_branch is not None: |
164 | + basis = result_branch.basis_tree() |
165 | + elif source_branch is not None: |
166 | + basis = source_branch.basis_tree() |
167 | + if basis is not None: |
168 | + add_cleanup(basis.lock_read().unlock) |
169 | + subtrees = basis.iter_references() |
170 | + else: |
171 | + subtrees = [] |
172 | + for path, file_id in subtrees: |
173 | + target = urlutils.join(url, urlutils.escape(path)) |
174 | + sublocation = source_branch.reference_parent(file_id, path) |
175 | + sublocation.bzrdir.sprout(target, |
176 | + basis.get_reference_revision(file_id, path), |
177 | + force_new_repo=force_new_repo, recurse=recurse, |
178 | + stacked=stacked) |
179 | + return result |
180 | + |
181 | + |
182 | + |
183 | @staticmethod |
184 | def create_branch_convenience(base, force_new_repo=False, |
185 | force_new_tree=None, format=None, |
186 | |
187 | === modified file 'bzrlib/controldir.py' |
188 | --- bzrlib/controldir.py 2011-03-23 14:31:38 +0000 |
189 | +++ bzrlib/controldir.py 2011-03-24 00:18:30 +0000 |
190 | @@ -27,9 +27,7 @@ |
191 | import textwrap |
192 | |
193 | from bzrlib import ( |
194 | - cleanup, |
195 | errors, |
196 | - fetch, |
197 | revision as _mod_revision, |
198 | transport as _mod_transport, |
199 | ui, |
200 | @@ -38,9 +36,6 @@ |
201 | from bzrlib.push import ( |
202 | PushResult, |
203 | ) |
204 | -from bzrlib.trace import ( |
205 | - mutter, |
206 | - ) |
207 | from bzrlib.transport import ( |
208 | local, |
209 | ) |
210 | @@ -336,131 +331,7 @@ |
211 | :param create_tree_if_local: If true, a working-tree will be created |
212 | when working locally. |
213 | """ |
214 | - operation = cleanup.OperationWithCleanups(self._sprout) |
215 | - return operation.run(url, revision_id=revision_id, |
216 | - force_new_repo=force_new_repo, recurse=recurse, |
217 | - possible_transports=possible_transports, |
218 | - accelerator_tree=accelerator_tree, hardlink=hardlink, |
219 | - stacked=stacked, source_branch=source_branch, |
220 | - create_tree_if_local=create_tree_if_local) |
221 | - |
222 | - def _sprout(self, op, url, revision_id=None, force_new_repo=False, |
223 | - recurse='down', possible_transports=None, |
224 | - accelerator_tree=None, hardlink=False, stacked=False, |
225 | - source_branch=None, create_tree_if_local=True): |
226 | - add_cleanup = op.add_cleanup |
227 | - fetch_spec_factory = fetch.FetchSpecFactory() |
228 | - if revision_id is not None: |
229 | - fetch_spec_factory.add_revision_ids([revision_id]) |
230 | - fetch_spec_factory.source_branch_stop_revision_id = revision_id |
231 | - target_transport = _mod_transport.get_transport(url, |
232 | - possible_transports) |
233 | - target_transport.ensure_base() |
234 | - cloning_format = self.cloning_metadir(stacked) |
235 | - # Create/update the result branch |
236 | - result = cloning_format.initialize_on_transport(target_transport) |
237 | - source_branch, source_repository = self._find_source_repo( |
238 | - add_cleanup, source_branch) |
239 | - fetch_spec_factory.source_branch = source_branch |
240 | - # if a stacked branch wasn't requested, we don't create one |
241 | - # even if the origin was stacked |
242 | - if stacked and source_branch is not None: |
243 | - stacked_branch_url = self.root_transport.base |
244 | - else: |
245 | - stacked_branch_url = None |
246 | - repository_policy = result.determine_repository_policy( |
247 | - force_new_repo, stacked_branch_url, require_stacking=stacked) |
248 | - result_repo, is_new_repo = repository_policy.acquire_repository() |
249 | - add_cleanup(result_repo.lock_write().unlock) |
250 | - fetch_spec_factory.source_repo = source_repository |
251 | - fetch_spec_factory.target_repo = result_repo |
252 | - if stacked or (len(result_repo._fallback_repositories) != 0): |
253 | - target_repo_kind = fetch.TargetRepoKinds.STACKED |
254 | - elif is_new_repo: |
255 | - target_repo_kind = fetch.TargetRepoKinds.EMPTY |
256 | - else: |
257 | - target_repo_kind = fetch.TargetRepoKinds.PREEXISTING |
258 | - fetch_spec_factory.target_repo_kind = target_repo_kind |
259 | - if source_repository is not None: |
260 | - fetch_spec = fetch_spec_factory.make_fetch_spec() |
261 | - result_repo.fetch(source_repository, fetch_spec=fetch_spec) |
262 | - |
263 | - if source_branch is None: |
264 | - # this is for sprouting a controldir without a branch; is that |
265 | - # actually useful? |
266 | - # Not especially, but it's part of the contract. |
267 | - result_branch = result.create_branch() |
268 | - else: |
269 | - result_branch = source_branch.sprout(result, |
270 | - revision_id=revision_id, repository_policy=repository_policy, |
271 | - repository=result_repo) |
272 | - mutter("created new branch %r" % (result_branch,)) |
273 | - |
274 | - # Create/update the result working tree |
275 | - if (create_tree_if_local and |
276 | - isinstance(target_transport, local.LocalTransport) and |
277 | - (result_repo is None or result_repo.make_working_trees())): |
278 | - wt = result.create_workingtree(accelerator_tree=accelerator_tree, |
279 | - hardlink=hardlink, from_branch=result_branch) |
280 | - wt.lock_write() |
281 | - try: |
282 | - if wt.path2id('') is None: |
283 | - try: |
284 | - wt.set_root_id(self.open_workingtree.get_root_id()) |
285 | - except errors.NoWorkingTree: |
286 | - pass |
287 | - finally: |
288 | - wt.unlock() |
289 | - else: |
290 | - wt = None |
291 | - if recurse == 'down': |
292 | - basis = None |
293 | - if wt is not None: |
294 | - basis = wt.basis_tree() |
295 | - elif result_branch is not None: |
296 | - basis = result_branch.basis_tree() |
297 | - elif source_branch is not None: |
298 | - basis = source_branch.basis_tree() |
299 | - if basis is not None: |
300 | - add_cleanup(basis.lock_read().unlock) |
301 | - subtrees = basis.iter_references() |
302 | - else: |
303 | - subtrees = [] |
304 | - for path, file_id in subtrees: |
305 | - target = urlutils.join(url, urlutils.escape(path)) |
306 | - sublocation = source_branch.reference_parent(file_id, path) |
307 | - sublocation.bzrdir.sprout(target, |
308 | - basis.get_reference_revision(file_id, path), |
309 | - force_new_repo=force_new_repo, recurse=recurse, |
310 | - stacked=stacked) |
311 | - return result |
312 | - |
313 | - def _find_source_repo(self, add_cleanup, source_branch): |
314 | - """Find the source branch and repo for a sprout operation. |
315 | - |
316 | - This is helper intended for use by _sprout. |
317 | - |
318 | - :returns: (source_branch, source_repository). Either or both may be |
319 | - None. If not None, they will be read-locked (and their unlock(s) |
320 | - scheduled via the add_cleanup param). |
321 | - """ |
322 | - if source_branch is not None: |
323 | - add_cleanup(source_branch.lock_read().unlock) |
324 | - return source_branch, source_branch.repository |
325 | - try: |
326 | - source_branch = self.open_branch() |
327 | - source_repository = source_branch.repository |
328 | - except errors.NotBranchError: |
329 | - source_branch = None |
330 | - try: |
331 | - source_repository = self.open_repository() |
332 | - except errors.NoRepositoryPresent: |
333 | - source_repository = None |
334 | - else: |
335 | - add_cleanup(source_repository.lock_read().unlock) |
336 | - else: |
337 | - add_cleanup(source_branch.lock_read().unlock) |
338 | - return source_branch, source_repository |
339 | + raise NotImplementedError(self.sprout) |
340 | |
341 | def push_branch(self, source, revision_id=None, overwrite=False, |
342 | remember=False, create_prefix=False): |
343 | |
344 | === modified file 'doc/en/release-notes/bzr-2.4.txt' |
345 | --- doc/en/release-notes/bzr-2.4.txt 2011-03-23 12:56:01 +0000 |
346 | +++ doc/en/release-notes/bzr-2.4.txt 2011-03-24 00:18:30 +0000 |
347 | @@ -230,6 +230,10 @@ |
348 | ``import_last_revision_info_and_tags`` method instead. |
349 | (Andrew Bennetts) |
350 | |
351 | +* Because it was too specific to BzrDir implementations, |
352 | + ``ControlDir.sprout`` no longer has a default implementation; it now |
353 | + raises ``NotImplementedError``. (Jelmer Vernooij, #717937) |
354 | + |
355 | * ``ControlDirFormat.register_format`` has been removed. Instead, |
356 | ``Prober`` implementations should now implement a ``known_formats`` |
357 | method. (Jelmer Vernooij) |
This seems like a reasonable change to me.
It'd be nice to slowly converge on having foreign formats and BzrDir do as much in common as possible, but as a first step acknowledging that sprout is currently quite BzrDir-specific is fair enough.