2592
by Jelmer Vernooij
Move push code to a separate file. |
1 |
# Copyright (C) 2006-2009 Jelmer Vernooij <jelmer@samba.org>
|
2 |
||
3 |
# This program is free software; you can redistribute it and/or modify
|
|
4 |
# it under the terms of the GNU General Public License as published by
|
|
2632
by Jelmer Vernooij
Change license back to GPLv2+. |
5 |
# the Free Software Foundation; either version 2 of the License, or
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
6 |
# (at your option) any later version.
|
7 |
||
8 |
# This program is distributed in the hope that it will be useful,
|
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 |
# GNU General Public License for more details.
|
|
12 |
||
13 |
# You should have received a copy of the GNU General Public License
|
|
14 |
# along with this program; if not, write to the Free Software
|
|
15 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16 |
"""Pushing to Subversion repositories."""
|
|
17 |
||
2761
by Menno Smits
Provide support for Python 2.4. |
18 |
try: |
19 |
from collections import defaultdict |
|
20 |
except ImportError: |
|
21 |
from bzrlib.plugins.svn.pycompat import defaultdict |
|
2743
by Jelmer Vernooij
Return both foreign revid and mapping. |
22 |
|
2747
by Jelmer Vernooij
Move push to push module. |
23 |
import subvertpy |
2700
by Jelmer Vernooij
Reformat imports. |
24 |
from subvertpy import ( |
25 |
ERR_FS_TXN_OUT_OF_DATE, |
|
26 |
SubversionException, |
|
27 |
properties, |
|
28 |
)
|
|
29 |
||
2592
by Jelmer Vernooij
Move push code to a separate file. |
30 |
from bzrlib import ( |
31 |
ui, |
|
32 |
urlutils, |
|
33 |
)
|
|
34 |
from bzrlib.errors import ( |
|
2747
by Jelmer Vernooij
Move push to push module. |
35 |
AlreadyBranchError, |
2592
by Jelmer Vernooij
Move push code to a separate file. |
36 |
BzrError, |
37 |
DivergedBranches, |
|
38 |
NoSuchRevision, |
|
39 |
)
|
|
40 |
from bzrlib.repository import ( |
|
41 |
InterRepository, |
|
42 |
)
|
|
43 |
from bzrlib.revision import ( |
|
44 |
NULL_REVISION, |
|
45 |
)
|
|
46 |
from bzrlib.trace import ( |
|
47 |
mutter, |
|
48 |
)
|
|
49 |
||
50 |
from bzrlib.plugins.svn.commit import ( |
|
51 |
SvnCommitBuilder, |
|
52 |
)
|
|
53 |
from bzrlib.plugins.svn.config import ( |
|
54 |
BranchConfig, |
|
55 |
)
|
|
56 |
from bzrlib.plugins.svn.errors import ( |
|
57 |
ChangesRootLHSHistory, |
|
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
58 |
MissingPrefix, |
2592
by Jelmer Vernooij
Move push code to a separate file. |
59 |
convert_svn_error, |
60 |
)
|
|
3169
by Jelmer Vernooij
Fix import. |
61 |
from bzrlib.plugins.svn.mapping import ( |
62 |
SVN_REVPROP_BZR_SKIP, |
|
63 |
)
|
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
64 |
from bzrlib.plugins.svn.repository import ( |
65 |
SvnRepositoryFormat, |
|
66 |
SvnRepository, |
|
67 |
)
|
|
68 |
from bzrlib.plugins.svn.transport import ( |
|
3040
by Jelmer Vernooij
Support creating prefix. |
69 |
check_dirs_exist, |
3039
by Jelmer Vernooij
Move create_branch_prefix to transport. |
70 |
create_branch_prefix, |
2592
by Jelmer Vernooij
Move push code to a separate file. |
71 |
url_join_unescaped_path, |
72 |
)
|
|
73 |
||
2746
by Jelmer Vernooij
Fix push. |
74 |
def find_push_base_revision(source, target, stop_revision): |
2744
by Jelmer Vernooij
use remembered base revisions. |
75 |
start_revid = stop_revision |
76 |
for revid in source.iter_reverse_revision_history(stop_revision): |
|
2746
by Jelmer Vernooij
Fix push. |
77 |
if target.has_revision(revid): |
2744
by Jelmer Vernooij
use remembered base revisions. |
78 |
break
|
79 |
start_revid = revid |
|
80 |
return start_revid |
|
81 |
||
2592
by Jelmer Vernooij
Move push code to a separate file. |
82 |
|
83 |
def replay_delta(builder, old_trees, new_tree): |
|
84 |
"""Replays a delta to a commit builder.
|
|
85 |
||
86 |
:param builder: The commit builder.
|
|
87 |
:param old_tree: Original tree on top of which the delta should be applied
|
|
88 |
:param new_tree: New tree that should be committed
|
|
89 |
"""
|
|
90 |
for path, ie in new_tree.inventory.iter_entries(): |
|
91 |
builder.record_entry_contents(ie.copy(), |
|
92 |
[old_tree.inventory for old_tree in old_trees], |
|
93 |
path, new_tree, None) |
|
94 |
builder.finish_inventory() |
|
95 |
||
96 |
||
2741
by Jelmer Vernooij
return result foreign revid in a couple more cases. |
97 |
def push_revision_tree(graph, target_repo, branch_path, config, source_repo, |
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
98 |
base_revid, revision_id, rev, |
99 |
base_foreign_revid, base_mapping, |
|
100 |
push_metadata=True, |
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
101 |
append_revisions_only=True, |
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
102 |
override_svn_revprops=None): |
2592
by Jelmer Vernooij
Move push code to a separate file. |
103 |
"""Push a revision tree into a target repository.
|
104 |
||
105 |
:param graph: Repository graph.
|
|
106 |
:param target_repo: Target repository.
|
|
107 |
:param branch_path: Branch path.
|
|
108 |
:param config: Branch configuration.
|
|
109 |
:param source_repo: Source repository.
|
|
110 |
:param base_revid: Base revision id.
|
|
111 |
:param revision_id: Revision id to push.
|
|
112 |
:param rev: Revision object of revision to push.
|
|
113 |
:param push_metadata: Whether to push metadata.
|
|
114 |
:param append_revisions_only: Append revisions only.
|
|
115 |
:return: Revision id of newly created revision.
|
|
116 |
"""
|
|
117 |
assert rev.revision_id in (None, revision_id) |
|
118 |
old_tree = source_repo.revision_tree(revision_id) |
|
119 |
if rev.parent_ids: |
|
120 |
base_tree = source_repo.revision_tree(rev.parent_ids[0]) |
|
121 |
else: |
|
122 |
base_tree = source_repo.revision_tree(NULL_REVISION) |
|
123 |
||
124 |
if push_metadata: |
|
125 |
base_revids = rev.parent_ids |
|
126 |
else: |
|
127 |
base_revids = [base_revid] |
|
128 |
||
129 |
try: |
|
130 |
opt_signature = source_repo.get_signature_text(rev.revision_id) |
|
131 |
except NoSuchRevision: |
|
132 |
opt_signature = None |
|
133 |
||
134 |
builder = SvnCommitBuilder(target_repo, branch_path, base_revids, |
|
135 |
config, rev.timestamp, |
|
136 |
rev.timezone, rev.committer, rev.properties, |
|
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
137 |
revision_id, base_foreign_revid, base_mapping, |
2592
by Jelmer Vernooij
Move push code to a separate file. |
138 |
base_tree.inventory, |
139 |
push_metadata=push_metadata, |
|
140 |
graph=graph, opt_signature=opt_signature, |
|
141 |
texts=source_repo.texts, |
|
142 |
append_revisions_only=append_revisions_only, |
|
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
143 |
override_svn_revprops=override_svn_revprops) |
2592
by Jelmer Vernooij
Move push code to a separate file. |
144 |
parent_trees = [base_tree] |
145 |
for p in rev.parent_ids[1:]: |
|
146 |
try: |
|
147 |
parent_trees.append(source_repo.revision_tree(p)) |
|
148 |
except NoSuchRevision: |
|
149 |
pass # Ghost, ignore |
|
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
150 |
# TODO: Use iter_changes() ?
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
151 |
replay_delta(builder, parent_trees, old_tree) |
152 |
try: |
|
153 |
revid = builder.commit(rev.message) |
|
154 |
except SubversionException, (msg, num): |
|
155 |
if num == ERR_FS_TXN_OUT_OF_DATE: |
|
156 |
raise DivergedBranches(source_repo, target_repo) |
|
157 |
raise
|
|
158 |
except ChangesRootLHSHistory: |
|
159 |
raise BzrError("Unable to push revision %r because it would change the ordering of existing revisions on the Subversion repository root. Use rebase and try again or push to a non-root path" % revision_id) |
|
160 |
||
2743
by Jelmer Vernooij
Return both foreign revid and mapping. |
161 |
return revid, (builder.result_foreign_revid, builder.mapping) |
2592
by Jelmer Vernooij
Move push code to a separate file. |
162 |
|
163 |
||
164 |
class InterToSvnRepository(InterRepository): |
|
165 |
"""Any to Subversion repository actions."""
|
|
166 |
||
167 |
_matching_repo_format = SvnRepositoryFormat() |
|
168 |
||
2601
by Jelmer Vernooij
Use only a single graph object. |
169 |
def __init__(self, source, target, graph=None): |
2594
by Jelmer Vernooij
Use InterToSvnRepository for pushing ancestors. |
170 |
InterRepository.__init__(self, source, target) |
2601
by Jelmer Vernooij
Use only a single graph object. |
171 |
self._graph = graph |
2743
by Jelmer Vernooij
Return both foreign revid and mapping. |
172 |
# Dictionary: revid -> branch_path -> (foreign_revid, mapping)
|
173 |
self._foreign_info = defaultdict(dict) |
|
2594
by Jelmer Vernooij
Use InterToSvnRepository for pushing ancestors. |
174 |
|
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
175 |
def _target_has_revision(self, revid): |
176 |
"""Slightly optimized version of self.target.has_revision()."""
|
|
177 |
if revid in self._foreign_info: |
|
178 |
return True |
|
179 |
return self.target.has_revision(revid) |
|
180 |
||
2744
by Jelmer Vernooij
use remembered base revisions. |
181 |
def _get_base_revision(self, revid, path): |
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
182 |
"""Find the revision info for a revision id."""
|
183 |
if revid == NULL_REVISION: |
|
184 |
return None, None |
|
2744
by Jelmer Vernooij
use remembered base revisions. |
185 |
if not revid in self._foreign_info: |
3087
by Jelmer Vernooij
Try harder to use the same branch. |
186 |
# FIXME: Prefer revisions in path
|
3207
by Jelmer Vernooij
Use standard bzr naming for lookup functions. |
187 |
return self.target.lookup_bzr_revision_id(revid) |
2744
by Jelmer Vernooij
use remembered base revisions. |
188 |
if path in self._foreign_info[revid]: |
189 |
return self._foreign_info[revid][path] |
|
190 |
else: |
|
191 |
return self._foreign_info[revid].values()[0] |
|
192 |
||
3087
by Jelmer Vernooij
Try harder to use the same branch. |
193 |
def add_path_info(self, revid, path, foreign_info): |
194 |
self._foreign_info[revid][path] = foreign_info |
|
195 |
||
2592
by Jelmer Vernooij
Move push code to a separate file. |
196 |
@staticmethod
|
197 |
def _get_repo_format_to_test(): |
|
198 |
"""See InterRepository._get_repo_format_to_test()."""
|
|
199 |
return None |
|
200 |
||
2599
by Jelmer Vernooij
Use proper base revision during dpush rather than whatever is at the tip of the branch. |
201 |
def push_branch(self, todo, layout, project, target_branch, target_config, |
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
202 |
push_merged, overwrite): |
2600
by Jelmer Vernooij
Reformat copy_content_into a bit. |
203 |
"""Push a series of revisions into a Subversion repository.
|
204 |
||
205 |
"""
|
|
2828
by Jelmer Vernooij
Try really hard to avoid retrieving branch tip more than once. |
206 |
assert todo != [] |
207 |
count = 0 |
|
2597
by Jelmer Vernooij
Move push to InterToSvnRepository. |
208 |
pb = ui.ui_factory.nested_progress_bar() |
209 |
try: |
|
210 |
for rev in self.source.get_revisions(todo): |
|
211 |
pb.update("pushing revisions", todo.index(rev.revision_id), |
|
212 |
len(todo)) |
|
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
213 |
if push_merged and len(rev.parent_ids) > 1: |
2597
by Jelmer Vernooij
Move push to InterToSvnRepository. |
214 |
self.push_ancestors(layout, project, |
215 |
rev.parent_ids, create_prefix=True) |
|
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
216 |
last = self.push(target_branch, target_config, rev, |
217 |
overwrite=overwrite) |
|
2828
by Jelmer Vernooij
Try really hard to avoid retrieving branch tip more than once. |
218 |
count += 1 |
2829
by Jelmer Vernooij
Print more info about pushed svn branches. |
219 |
return (count, last) |
2597
by Jelmer Vernooij
Move push to InterToSvnRepository. |
220 |
finally: |
221 |
pb.finished() |
|
222 |
||
3043
by Jelmer Vernooij
Simplify push. |
223 |
def push(self, target_path, target_config, rev, push_metadata=True, |
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
224 |
base_revid=None, overwrite=False): |
3043
by Jelmer Vernooij
Simplify push. |
225 |
if base_revid is None: |
226 |
if rev.parent_ids: |
|
227 |
base_revid = rev.parent_ids[0] |
|
228 |
else: |
|
229 |
base_revid = NULL_REVISION |
|
230 |
base_foreign_revid, base_mapping = self._get_base_revision(base_revid, |
|
231 |
target_path) |
|
232 |
mutter('pushing %r (%r)', rev.revision_id, rev.parent_ids) |
|
233 |
revid, foreign_info = push_revision_tree(self.get_graph(), self.target, |
|
234 |
target_path, target_config, self.source, base_revid, |
|
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
235 |
rev.revision_id, rev, |
236 |
base_foreign_revid, base_mapping, |
|
237 |
push_metadata=push_metadata, |
|
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
238 |
append_revisions_only=self.get_append_revisions_only(target_config, overwrite), |
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
239 |
override_svn_revprops=target_config.get_override_svn_revprops()) |
3043
by Jelmer Vernooij
Simplify push. |
240 |
assert revid == rev.revision_id or not push_metadata |
3087
by Jelmer Vernooij
Try harder to use the same branch. |
241 |
self.add_path_info(target_path, revid, foreign_info) |
2829
by Jelmer Vernooij
Print more info about pushed svn branches. |
242 |
return (revid, foreign_info) |
2742
by Jelmer Vernooij
Pass result foreign revid in a couple more cases. |
243 |
|
2748
by Jelmer Vernooij
Avoid replaces when not necessary. |
244 |
def _get_branch_config(self, branch_path): |
245 |
return BranchConfig(urlutils.join(self.target.base, branch_path), |
|
246 |
self.target.uuid) |
|
247 |
||
2747
by Jelmer Vernooij
Move push to push module. |
248 |
def push_new(self, target_branch_path, |
2742
by Jelmer Vernooij
Pass result foreign revid in a couple more cases. |
249 |
stop_revision, push_metadata=True, append_revisions_only=False, |
2744
by Jelmer Vernooij
use remembered base revisions. |
250 |
override_svn_revprops=None): |
2748
by Jelmer Vernooij
Avoid replaces when not necessary. |
251 |
"""Push a revision into Subversion, creating a new branch.
|
252 |
||
253 |
This will do a new commit in the target branch.
|
|
254 |
||
255 |
:param graph: Repository graph.
|
|
256 |
:param target_repository: Repository to push to
|
|
257 |
:param target_branch_path: Path to create new branch at
|
|
258 |
:param source: Source repository
|
|
259 |
:return: Revision id of the pushed revision, foreign revision id that was
|
|
260 |
pushed
|
|
261 |
"""
|
|
262 |
start_revid = find_push_base_revision(self.source, self.target, |
|
263 |
stop_revision) |
|
264 |
rev = self.source.get_revision(start_revid) |
|
265 |
if rev.parent_ids == []: |
|
266 |
start_revid_parent = NULL_REVISION |
|
267 |
else: |
|
268 |
start_revid_parent = rev.parent_ids[0] |
|
269 |
# If this is just intended to create a new branch
|
|
270 |
mapping = self.target.get_mapping() |
|
271 |
if (start_revid != NULL_REVISION and |
|
272 |
start_revid_parent != NULL_REVISION and |
|
3087
by Jelmer Vernooij
Try harder to use the same branch. |
273 |
stop_revision == start_revid and mapping.supports_hidden and |
274 |
not append_revisions_only): |
|
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
275 |
if (self._target_has_revision(start_revid) or |
2748
by Jelmer Vernooij
Avoid replaces when not necessary. |
276 |
start_revid == NULL_REVISION): |
277 |
revid = start_revid |
|
278 |
else: |
|
279 |
revid = start_revid_parent |
|
280 |
revid, foreign_info = create_branch_with_hidden_commit(self.target, |
|
281 |
target_branch_path, revid, set_metadata=True, deletefirst=None) |
|
282 |
else: |
|
283 |
base_foreign_revid, base_mapping = self._get_base_revision(start_revid_parent, target_branch_path) |
|
284 |
revid, foreign_info = push_revision_tree(self.get_graph(), self.target, target_branch_path, |
|
285 |
self._get_branch_config(target_branch_path), |
|
286 |
self.source, start_revid_parent, start_revid, |
|
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
287 |
rev, base_foreign_revid, base_mapping, |
288 |
push_metadata=push_metadata, |
|
2742
by Jelmer Vernooij
Pass result foreign revid in a couple more cases. |
289 |
append_revisions_only=append_revisions_only, |
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
290 |
override_svn_revprops=override_svn_revprops) |
3087
by Jelmer Vernooij
Try harder to use the same branch. |
291 |
self.add_path_info(target_branch_path, revid, foreign_info) |
2743
by Jelmer Vernooij
Return both foreign revid and mapping. |
292 |
return revid, foreign_info |
2742
by Jelmer Vernooij
Pass result foreign revid in a couple more cases. |
293 |
|
2594
by Jelmer Vernooij
Use InterToSvnRepository for pushing ancestors. |
294 |
def push_ancestors(self, layout, project, parent_revids, |
295 |
create_prefix=False): |
|
296 |
"""Push the ancestors of a revision.
|
|
297 |
||
298 |
:param layout: Subversion layout
|
|
299 |
:param project: Project name
|
|
300 |
:param parent_revids: The revision ids of the basic ancestors to push
|
|
301 |
:param create_prefix: Whether to optionally create the prefix of the branches.
|
|
302 |
"""
|
|
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
303 |
present_rhs_parents = self.target.has_revisions(parent_revids[1:]) |
304 |
unique_ancestors = set() |
|
305 |
for parent_revid in parent_revids[1:]: |
|
306 |
if parent_revid in present_rhs_parents: |
|
307 |
continue
|
|
2594
by Jelmer Vernooij
Use InterToSvnRepository for pushing ancestors. |
308 |
# Push merged revisions
|
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
309 |
unique_ancestors.update(self.get_graph().find_unique_ancestors(parent_revid, [parent_revids[0]])) |
310 |
for x in self.get_graph().iter_topo_order(unique_ancestors): |
|
311 |
if self._target_has_revision(x): |
|
312 |
continue
|
|
313 |
rev = self.source.get_revision(x) |
|
314 |
rhs_branch_path = determine_branch_path(rev, layout, project) |
|
315 |
try: |
|
3081
by Jelmer Vernooij
Improve formatting. |
316 |
self.push_new(rhs_branch_path, x, append_revisions_only=False) |
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
317 |
except MissingPrefix, e: |
318 |
if not create_prefix: |
|
319 |
raise
|
|
320 |
revprops = {properties.PROP_REVISION_LOG: "Add branches directory."} |
|
321 |
if self.target.transport.has_capability("commit-revprops"): |
|
3169
by Jelmer Vernooij
Fix import. |
322 |
revprops[SVN_REVPROP_BZR_SKIP] = "" |
3038
by Jelmer Vernooij
Simplify arguments for create_branch_prefix. |
323 |
create_branch_prefix(self.target.transport, revprops, e.path.split("/")[:-1], filter(lambda x: x != "", e.existing_path.split("/"))) |
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
324 |
self.push_new(rhs_branch_path, x, append_revisions_only=False) |
2594
by Jelmer Vernooij
Use InterToSvnRepository for pushing ancestors. |
325 |
|
2748
by Jelmer Vernooij
Avoid replaces when not necessary. |
326 |
def push_new_branch(self, layout, project, target_branch_path, |
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
327 |
stop_revision, push_merged=None, override_svn_revprops=None, |
328 |
overwrite=False): |
|
2747
by Jelmer Vernooij
Move push to push module. |
329 |
if self.target.transport.check_path(target_branch_path, |
330 |
self.target.get_latest_revnum()) != subvertpy.NODE_NONE: |
|
331 |
raise AlreadyBranchError(target_branch_path) |
|
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
332 |
target_config = self._get_branch_config(target_branch_path) |
333 |
if push_merged is None: |
|
334 |
push_merged = (layout.push_merged_revisions(project) and |
|
335 |
target_config.get_push_merged_revisions()) |
|
2748
by Jelmer Vernooij
Avoid replaces when not necessary. |
336 |
begin_revid, _ = self.push_new(target_branch_path, stop_revision, |
2747
by Jelmer Vernooij
Move push to push module. |
337 |
append_revisions_only=True, |
338 |
override_svn_revprops=override_svn_revprops) |
|
2748
by Jelmer Vernooij
Avoid replaces when not necessary. |
339 |
todo = [] |
340 |
for revid in self.source.iter_reverse_revision_history(stop_revision): |
|
341 |
if revid == begin_revid: |
|
342 |
break
|
|
343 |
todo.append(revid) |
|
344 |
todo.reverse() |
|
2828
by Jelmer Vernooij
Try really hard to avoid retrieving branch tip more than once. |
345 |
if todo != []: |
346 |
self.push_branch(todo, layout, project, target_branch_path, |
|
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
347 |
target_config, push_merged, overwrite) |
2747
by Jelmer Vernooij
Move push to push module. |
348 |
|
2605
by Jelmer Vernooij
Split revision pushing out of copy_content_intO. |
349 |
def push_nonmainline_revision(self, rev, layout): |
350 |
mutter('pushing %r', rev.revision_id) |
|
2651
by Jelmer Vernooij
Fix branch from svn into svn. |
351 |
if rev.parent_ids: |
352 |
parent_revid = rev.parent_ids[0] |
|
353 |
else: |
|
2605
by Jelmer Vernooij
Split revision pushing out of copy_content_intO. |
354 |
parent_revid = NULL_REVISION |
355 |
||
356 |
if parent_revid == NULL_REVISION: |
|
2651
by Jelmer Vernooij
Fix branch from svn into svn. |
357 |
target_project = None |
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
358 |
base_foreign_revid = None |
359 |
base_mapping = None |
|
2605
by Jelmer Vernooij
Split revision pushing out of copy_content_intO. |
360 |
else: |
3207
by Jelmer Vernooij
Use standard bzr naming for lookup functions. |
361 |
base_foreign_revid, base_mapping = self.target.lookup_bzr_revision_id(parent_revid, |
3212
by Jelmer Vernooij
Cope with pushing new non-mainline revisions. |
362 |
foreign_sibling=getattr(rev, "foreign_revid", None)) |
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
363 |
(_, target_project, _, _) = layout.parse(base_foreign_revid[1]) |
2701
by Jelmer Vernooij
Fix concurrent access problems during push/commit. |
364 |
bp = determine_branch_path(rev, layout, target_project) |
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
365 |
target_config = self._get_branch_config(bp) |
2606
by Jelmer Vernooij
Simplify pushing of first revision. |
366 |
if (layout.push_merged_revisions(target_project) and |
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
367 |
target_config.get_push_merged_revisions() and |
368 |
len(rev.parent_ids) > 1): |
|
2606
by Jelmer Vernooij
Simplify pushing of first revision. |
369 |
self.push_ancestors(layout, target_project, |
370 |
rev.parent_ids, create_prefix=True) |
|
2742
by Jelmer Vernooij
Pass result foreign revid in a couple more cases. |
371 |
return push_revision_tree(self.get_graph(), self.target, |
2606
by Jelmer Vernooij
Simplify pushing of first revision. |
372 |
bp, target_config, |
373 |
self.source, parent_revid, rev.revision_id, rev, |
|
3086
by Jelmer Vernooij
Explicitly specify base_foreign_revid / base_mapping everywhere. |
374 |
base_foreign_revid, base_mapping, |
3046
by Jelmer Vernooij
append_revisions_only now defaults to True, to prevent new users from accidently changing their Subversion mainline and upsetting their fellow committers. |
375 |
append_revisions_only=self.get_append_revisions_only(target_config)) |
376 |
||
377 |
def get_append_revisions_only(self, target_config, overwrite=False): |
|
3081
by Jelmer Vernooij
Improve formatting. |
378 |
return target_config.get_append_revisions_only(not overwrite) |
2605
by Jelmer Vernooij
Split revision pushing out of copy_content_intO. |
379 |
|
2737
by Jelmer Vernooij
Fix graph retrieval. |
380 |
def get_graph(self): |
381 |
if self._graph is None: |
|
382 |
self._graph = self.source.get_graph(self.target) |
|
383 |
return self._graph |
|
384 |
||
2592
by Jelmer Vernooij
Move push code to a separate file. |
385 |
def copy_content(self, revision_id=None, pb=None): |
386 |
"""See InterRepository.copy_content."""
|
|
387 |
self.source.lock_read() |
|
388 |
try: |
|
389 |
assert revision_id is not None, "fetching all revisions not supported" |
|
390 |
# Go back over the LHS parent until we reach a revid we know
|
|
391 |
todo = [] |
|
2604
by Jelmer Vernooij
use revision objects rather than revision ids internally in copy_content_into. |
392 |
for revision_id in self.source.iter_reverse_revision_history(revision_id): |
2830
by Jelmer Vernooij
Improve push-merged-revisions support. |
393 |
if self._target_has_revision(revision_id): |
2592
by Jelmer Vernooij
Move push code to a separate file. |
394 |
break
|
395 |
todo.append(revision_id) |
|
396 |
if todo == []: |
|
397 |
# Nothing to do
|
|
398 |
return
|
|
2606
by Jelmer Vernooij
Simplify pushing of first revision. |
399 |
todo.reverse() |
2592
by Jelmer Vernooij
Move push code to a separate file. |
400 |
mutter("pushing %r into svn", todo) |
401 |
layout = self.target.get_layout() |
|
2606
by Jelmer Vernooij
Simplify pushing of first revision. |
402 |
for rev in self.source.get_revisions(todo): |
2592
by Jelmer Vernooij
Move push code to a separate file. |
403 |
if pb is not None: |
2604
by Jelmer Vernooij
use revision objects rather than revision ids internally in copy_content_into. |
404 |
pb.update("pushing revisions", todo.index(rev.revision_id), |
2592
by Jelmer Vernooij
Move push code to a separate file. |
405 |
len(todo)) |
2605
by Jelmer Vernooij
Split revision pushing out of copy_content_intO. |
406 |
self.push_nonmainline_revision(rev, layout) |
2592
by Jelmer Vernooij
Move push code to a separate file. |
407 |
finally: |
408 |
self.source.unlock() |
|
409 |
||
2781.1.8
by Jelmer Vernooij
Support fetch_spec in InterToSvnRepository.fetch. |
410 |
def fetch(self, revision_id=None, pb=None, find_ghosts=False, |
411 |
fetch_spec=None): |
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
412 |
"""Fetch revisions. """
|
2781.1.8
by Jelmer Vernooij
Support fetch_spec in InterToSvnRepository.fetch. |
413 |
if fetch_spec is not None: |
414 |
for revid in fetch_spec.heads: |
|
415 |
self.copy_content(revision_id=revid, pb=pb) |
|
416 |
else: |
|
417 |
self.copy_content(revision_id=revision_id, pb=pb) |
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
418 |
|
419 |
@staticmethod
|
|
420 |
def is_compatible(source, target): |
|
421 |
"""Be compatible with SvnRepository."""
|
|
422 |
return isinstance(target, SvnRepository) |
|
423 |
||
424 |
||
425 |
def determine_branch_path(rev, layout, project=None): |
|
2606
by Jelmer Vernooij
Simplify pushing of first revision. |
426 |
"""Create a sane branch path to use for a revision.
|
427 |
|
|
428 |
:param rev: Revision object
|
|
429 |
:param layout: Subversion layout
|
|
430 |
:param project: Optional project name, as used by the layout
|
|
431 |
:return: Branch path string
|
|
432 |
"""
|
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
433 |
nick = (rev.properties.get('branch-nick') or "merged").encode("utf-8").replace("/","_") |
434 |
if project is None: |
|
435 |
return layout.get_branch_path(nick) |
|
436 |
else: |
|
437 |
return layout.get_branch_path(nick, project) |
|
438 |
||
439 |
||
440 |
def create_branch_with_hidden_commit(repository, branch_path, revid, |
|
441 |
set_metadata=True, |
|
442 |
deletefirst=False): |
|
443 |
"""Create a new branch using a simple "svn cp" operation.
|
|
444 |
||
445 |
:param repository: Repository in which to create the branch.
|
|
446 |
:param branch_path: Branch path
|
|
447 |
:param revid: Revision id to keep as tip.
|
|
448 |
:param deletefirst: Whether to delete an existing branch at this location first.
|
|
2741
by Jelmer Vernooij
return result foreign revid in a couple more cases. |
449 |
:return: Revision id that was pushed and the related foreign revision id.
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
450 |
"""
|
451 |
revprops = {properties.PROP_REVISION_LOG: "Create new branch."} |
|
452 |
revmeta, mapping = repository._get_revmeta(revid) |
|
453 |
fileprops = dict(revmeta.get_fileprops().iteritems()) |
|
454 |
if set_metadata: |
|
455 |
assert mapping.supports_hidden |
|
456 |
(set_custom_revprops, set_custom_fileprops) = repository._properties_to_set(mapping) |
|
457 |
if set_custom_revprops: |
|
458 |
mapping.export_hidden_revprops(branch_path, revprops) |
|
459 |
if (not set_custom_fileprops and |
|
460 |
not repository.transport.has_capability("log-revprops")): |
|
461 |
# Tell clients about first approximate use of revision
|
|
462 |
# properties
|
|
463 |
mapping.export_revprop_redirect( |
|
464 |
repository.get_latest_revnum()+1, fileprops) |
|
465 |
if set_custom_fileprops: |
|
466 |
mapping.export_hidden_fileprops(fileprops) |
|
467 |
parent = urlutils.dirname(branch_path) |
|
468 |
||
469 |
bp_parts = branch_path.split("/") |
|
3040
by Jelmer Vernooij
Support creating prefix. |
470 |
existing_bp_parts = check_dirs_exist(repository.transport, bp_parts, -1) |
2592
by Jelmer Vernooij
Move push code to a separate file. |
471 |
if (len(bp_parts) not in (len(existing_bp_parts), len(existing_bp_parts)+1)): |
472 |
raise MissingPrefix("/".join(bp_parts), "/".join(existing_bp_parts)) |
|
473 |
||
474 |
if deletefirst is None: |
|
475 |
deletefirst = (bp_parts == existing_bp_parts) |
|
2741
by Jelmer Vernooij
return result foreign revid in a couple more cases. |
476 |
|
477 |
foreign_revid = [repository.uuid, branch_path] |
|
478 |
||
479 |
def done(revno, *args): |
|
480 |
foreign_revid.append(revno) |
|
2592
by Jelmer Vernooij
Move push code to a separate file. |
481 |
|
482 |
conn = repository.transport.get_connection(parent) |
|
483 |
try: |
|
2741
by Jelmer Vernooij
return result foreign revid in a couple more cases. |
484 |
ci = convert_svn_error(conn.get_commit_editor)(revprops, done) |
2592
by Jelmer Vernooij
Move push code to a separate file. |
485 |
try: |
486 |
root = ci.open_root() |
|
487 |
if deletefirst: |
|
488 |
root.delete_entry(urlutils.basename(branch_path)) |
|
489 |
branch_dir = root.add_directory(urlutils.basename(branch_path), |
|
490 |
url_join_unescaped_path(repository.base, revmeta.branch_path), revmeta.revnum) |
|
491 |
for k, (ov, nv) in properties.diff(fileprops, revmeta.get_fileprops()).iteritems(): |
|
492 |
branch_dir.change_prop(k, nv) |
|
493 |
branch_dir.close() |
|
494 |
root.close() |
|
495 |
except: |
|
496 |
ci.abort() |
|
497 |
raise
|
|
498 |
ci.close() |
|
2743
by Jelmer Vernooij
Return both foreign revid and mapping. |
499 |
return revid, (tuple(foreign_revid), mapping) |
2592
by Jelmer Vernooij
Move push code to a separate file. |
500 |
finally: |
501 |
repository.transport.add_connection(conn) |