bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15
by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt |
1 |
# Copyright (C) 2007-2011 Canonical Ltd
|
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
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
|
|
5 |
# the Free Software Foundation; either version 2 of the License, or
|
|
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
|
|
4183.7.1
by Sabin Iacob
update FSF mailing address |
15 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
16 |
|
2220.2.20
by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc |
17 |
"""Tag strategies.
|
18 |
||
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
19 |
These are contained within a branch and normally constructed
|
20 |
when the branch is opened. Clients should typically do
|
|
2220.2.20
by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc |
21 |
|
22 |
Branch.tags.add('name', 'value')
|
|
23 |
"""
|
|
24 |
||
7260.3.4
by Jelmer Vernooij
Use defaultdict. |
25 |
from collections import defaultdict |
7479.2.1
by Jelmer Vernooij
Drop python2 support. |
26 |
import contextlib |
7489.3.3
by Jelmer Vernooij
Move bzr-specific tag code to breezy.bzr.tag. |
27 |
import itertools |
28 |
import re |
|
29 |
import sys |
|
7260.3.4
by Jelmer Vernooij
Use defaultdict. |
30 |
|
2220.2.20
by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc |
31 |
# NOTE: I was going to call this tags.py, but vim seems to think all files
|
32 |
# called tags* are ctags files... mbp 20070220.
|
|
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
33 |
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
34 |
from .inter import InterObject |
6624
by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes') |
35 |
from .registry import Registry |
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
36 |
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
37 |
from . import ( |
7413.8.12
by Jelmer Vernooij
Fix hg plugin. |
38 |
errors, |
39 |
)
|
|
40 |
||
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
41 |
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
42 |
def _reconcile_tags(source_dict, dest_dict, overwrite, selector): |
7260.3.3
by Jelmer Vernooij
Add merge_to support. |
43 |
"""Do a two-way merge of two tag dictionaries. |
44 |
||
45 |
* only in source => source value
|
|
46 |
* only in destination => destination value
|
|
47 |
* same definitions => that
|
|
48 |
* different definitions => if overwrite is False, keep destination
|
|
7260.3.4
by Jelmer Vernooij
Use defaultdict. |
49 |
value and add to conflict list, otherwise use the source value
|
7260.3.3
by Jelmer Vernooij
Add merge_to support. |
50 |
|
51 |
:returns: (result_dict, updates,
|
|
52 |
[(conflicting_tag, source_target, dest_target)])
|
|
53 |
"""
|
|
54 |
conflicts = [] |
|
55 |
updates = {} |
|
56 |
result = dict(dest_dict) # copy |
|
57 |
for name, target in source_dict.items(): |
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
58 |
if selector and not selector(name): |
59 |
continue
|
|
7260.3.3
by Jelmer Vernooij
Add merge_to support. |
60 |
if result.get(name) == target: |
61 |
pass
|
|
62 |
elif name not in result or overwrite: |
|
63 |
updates[name] = target |
|
64 |
result[name] = target |
|
65 |
else: |
|
66 |
conflicts.append((name, target, result[name])) |
|
67 |
return result, updates, conflicts |
|
68 |
||
69 |
||
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
70 |
class Tags(object): |
2220.2.28
by Martin Pool
Integrate tags with Branch6: |
71 |
|
2220.2.14
by mbp at sourcefrog
cleanup |
72 |
def __init__(self, branch): |
73 |
self.branch = branch |
|
74 |
||
6123.4.1
by Jelmer Vernooij
Add stubs. |
75 |
def get_tag_dict(self): |
76 |
"""Return a dictionary mapping tags to revision ids. |
|
77 |
"""
|
|
78 |
raise NotImplementedError(self.get_tag_dict) |
|
79 |
||
80 |
def get_reverse_tag_dict(self): |
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
81 |
"""Returns a dict with revisions as keys |
82 |
and a list of tags for that revision as value"""
|
|
83 |
d = self.get_tag_dict() |
|
84 |
rev = defaultdict(set) |
|
85 |
for key in d: |
|
86 |
rev[d[key]].add(key) |
|
87 |
return rev |
|
6123.4.1
by Jelmer Vernooij
Add stubs. |
88 |
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
89 |
def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None): |
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
90 |
"""Copy tags between repositories if necessary and possible. |
91 |
||
92 |
This method has common command-line behaviour about handling
|
|
93 |
error cases.
|
|
94 |
||
95 |
All new definitions are copied across, except that tags that already
|
|
96 |
exist keep their existing definitions.
|
|
97 |
||
98 |
:param to_tags: Branch to receive these tags
|
|
99 |
:param overwrite: Overwrite conflicting tags in the target branch
|
|
6123.4.1
by Jelmer Vernooij
Add stubs. |
100 |
:param ignore_master: Do not modify the tags in the target's master
|
101 |
branch (if any). Default is false (so the master will be updated).
|
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
102 |
|
103 |
:returns: Tuple with tag_updates and tag_conflicts.
|
|
104 |
tag_updates is a dictionary with new tags, None is used for
|
|
105 |
removed tags
|
|
106 |
tag_conflicts is a set of tags that conflicted, each of which is
|
|
107 |
(tagname, source_target, dest_target), or None if no copying was
|
|
108 |
done.
|
|
6123.4.1
by Jelmer Vernooij
Add stubs. |
109 |
"""
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
110 |
intertags = InterTags.get(self, to_tags) |
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
111 |
return intertags.merge( |
112 |
overwrite=overwrite, ignore_master=ignore_master, |
|
113 |
selector=selector) |
|
6123.4.1
by Jelmer Vernooij
Add stubs. |
114 |
|
115 |
def set_tag(self, tag_name, revision): |
|
116 |
"""Set a tag. |
|
117 |
||
118 |
:param tag_name: Tag name
|
|
119 |
:param revision: Revision id
|
|
6123.4.2
by Jelmer Vernooij
Tags containers can indicate whether they support ghost tags. |
120 |
:raise GhostTagsNotSupported: if revision is not present in
|
121 |
the branch repository
|
|
6123.4.1
by Jelmer Vernooij
Add stubs. |
122 |
"""
|
123 |
raise NotImplementedError(self.set_tag) |
|
124 |
||
125 |
def lookup_tag(self, tag_name): |
|
126 |
"""Look up a tag. |
|
127 |
||
128 |
:param tag_name: Tag to look up
|
|
129 |
:raise NoSuchTag: Raised when tag does not exist
|
|
130 |
:return: Matching revision id
|
|
131 |
"""
|
|
132 |
raise NotImplementedError(self.lookup_tag) |
|
133 |
||
134 |
def delete_tag(self, tag_name): |
|
135 |
"""Delete a tag. |
|
136 |
||
137 |
:param tag_name: Tag to delete
|
|
138 |
:raise NoSuchTag: Raised when tag does not exist
|
|
139 |
"""
|
|
140 |
raise NotImplementedError(self.delete_tag) |
|
141 |
||
142 |
def rename_revisions(self, rename_map): |
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
143 |
"""Rename revisions in this tags dictionary. |
6123.4.1
by Jelmer Vernooij
Add stubs. |
144 |
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
145 |
:param rename_map: Dictionary mapping old revids to new revids
|
6123.4.1
by Jelmer Vernooij
Add stubs. |
146 |
"""
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
147 |
reverse_tags = self.get_reverse_tag_dict() |
148 |
for revid, names in reverse_tags.items(): |
|
149 |
if revid in rename_map: |
|
150 |
for name in names: |
|
151 |
self.set_tag(name, rename_map[revid]) |
|
6123.4.1
by Jelmer Vernooij
Add stubs. |
152 |
|
2220.2.42
by Martin Pool
Tag command refuses to replace existing tags unless you force it. |
153 |
def has_tag(self, tag_name): |
6619.3.1
by Jelmer Vernooij
Apply 2to3 has_key fix. |
154 |
return tag_name in self.get_tag_dict() |
2220.2.42
by Martin Pool
Tag command refuses to replace existing tags unless you force it. |
155 |
|
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
156 |
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
157 |
class DisabledTags(Tags): |
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
158 |
"""Tag storage that refuses to store anything. |
159 |
||
160 |
This is used by older formats that can't store tags.
|
|
161 |
"""
|
|
162 |
||
163 |
def _not_supported(self, *a, **k): |
|
2220.2.14
by mbp at sourcefrog
cleanup |
164 |
raise errors.TagsNotSupported(self.branch) |
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
165 |
|
166 |
set_tag = _not_supported |
|
167 |
get_tag_dict = _not_supported |
|
168 |
_set_tag_dict = _not_supported |
|
169 |
lookup_tag = _not_supported |
|
2220.2.21
by Martin Pool
Add tag --delete command and implementation |
170 |
delete_tag = _not_supported |
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
171 |
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
172 |
def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None): |
2220.2.30
by Martin Pool
split out tag-merging code and add some tests |
173 |
# we never have anything to copy
|
6112.4.1
by Jelmer Vernooij
Show how many tags have been updated in bzr pull. |
174 |
return {}, [] |
2220.2.30
by Martin Pool
split out tag-merging code and add some tests |
175 |
|
4325.2.1
by Jelmer Vernooij
Add Tags.rename_revisions(). |
176 |
def rename_revisions(self, rename_map): |
177 |
# No tags, so nothing to rename
|
|
178 |
pass
|
|
179 |
||
2831.8.1
by James Westby
Fix log against smart server branches that don't support tags. (#140615) |
180 |
def get_reverse_tag_dict(self): |
181 |
# There aren't any tags, so the reverse mapping is empty.
|
|
182 |
return {} |
|
183 |
||
2220.2.11
by mbp at sourcefrog
Get tag tests working again, stored in the Branch |
184 |
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
185 |
class InterTags(InterObject): |
186 |
"""Operations between sets of tags. |
|
187 |
"""
|
|
188 |
||
189 |
_optimisers = [] |
|
190 |
"""The available optimised InterTags types.""" |
|
191 |
||
192 |
@classmethod
|
|
193 |
def is_compatible(klass, source, target): |
|
194 |
# This is the default implementation
|
|
195 |
return True |
|
196 |
||
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
197 |
def merge(self, overwrite=False, ignore_master=False, selector=None): |
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
198 |
"""Copy tags between repositories if necessary and possible. |
199 |
||
200 |
This method has common command-line behaviour about handling
|
|
201 |
error cases.
|
|
202 |
||
203 |
All new definitions are copied across, except that tags that already
|
|
204 |
exist keep their existing definitions.
|
|
205 |
||
206 |
:param to_tags: Branch to receive these tags
|
|
207 |
:param overwrite: Overwrite conflicting tags in the target branch
|
|
208 |
:param ignore_master: Do not modify the tags in the target's master
|
|
209 |
branch (if any). Default is false (so the master will be updated).
|
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
210 |
:param selector: Callback that determines whether a tag should be
|
211 |
copied. It should take a tag name and as argument and return a
|
|
212 |
boolean.
|
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
213 |
|
214 |
:returns: Tuple with tag_updates and tag_conflicts.
|
|
215 |
tag_updates is a dictionary with new tags, None is used for
|
|
216 |
removed tags
|
|
217 |
tag_conflicts is a set of tags that conflicted, each of which is
|
|
218 |
(tagname, source_target, dest_target), or None if no copying was
|
|
219 |
done.
|
|
220 |
"""
|
|
7479.2.1
by Jelmer Vernooij
Drop python2 support. |
221 |
with contextlib.ExitStack() as stack: |
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
222 |
if self.source.branch == self.target.branch: |
7356.1.1
by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup. |
223 |
return {}, [] |
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
224 |
if not self.source.branch.supports_tags(): |
7356.1.1
by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup. |
225 |
# obviously nothing to copy
|
226 |
return {}, [] |
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
227 |
source_dict = self.source.get_tag_dict() |
7356.1.1
by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup. |
228 |
if not source_dict: |
229 |
# no tags in the source, and we don't want to clobber anything
|
|
230 |
# that's in the destination
|
|
231 |
return {}, [] |
|
232 |
# We merge_to both master and child individually.
|
|
233 |
#
|
|
234 |
# It's possible for master and child to have differing sets of
|
|
235 |
# tags, in which case it's possible to have different sets of
|
|
236 |
# conflicts. We report the union of both conflict sets. In
|
|
237 |
# that case it's likely the child and master have accepted
|
|
238 |
# different tags from the source, which may be a surprising result, but
|
|
239 |
# the best we can do in the circumstances.
|
|
240 |
#
|
|
241 |
# Ideally we'd improve this API to report the different conflicts
|
|
242 |
# more clearly to the caller, but we don't want to break plugins
|
|
243 |
# such as bzr-builddeb that use this API.
|
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
244 |
stack.enter_context(self.target.branch.lock_write()) |
7356.1.1
by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup. |
245 |
if ignore_master: |
246 |
master = None |
|
247 |
else: |
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
248 |
master = self.target.branch.get_master_branch() |
7356.1.1
by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup. |
249 |
if master is not None: |
250 |
stack.enter_context(master.lock_write()) |
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
251 |
updates, conflicts = self._merge_to( |
252 |
self.target, source_dict, overwrite, selector=selector) |
|
7356.1.1
by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup. |
253 |
if master is not None: |
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
254 |
extra_updates, extra_conflicts = self._merge_to( |
255 |
master.tags, source_dict, overwrite, selector=selector) |
|
7356.1.1
by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup. |
256 |
updates.update(extra_updates) |
257 |
conflicts += extra_conflicts |
|
258 |
# We use set() to remove any duplicate conflicts from the master
|
|
259 |
# branch.
|
|
260 |
return updates, set(conflicts) |
|
2220.2.30
by Martin Pool
split out tag-merging code and add some tests |
261 |
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
262 |
@classmethod
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
263 |
def _merge_to(cls, to_tags, source_dict, overwrite, selector): |
5050.53.1
by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any. |
264 |
dest_dict = to_tags.get_tag_dict() |
7260.3.3
by Jelmer Vernooij
Add merge_to support. |
265 |
result, updates, conflicts = _reconcile_tags( |
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
266 |
source_dict, dest_dict, overwrite, selector) |
5050.53.1
by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any. |
267 |
if result != dest_dict: |
268 |
to_tags._set_tag_dict(result) |
|
6112.4.1
by Jelmer Vernooij
Show how many tags have been updated in bzr pull. |
269 |
return updates, conflicts |
5050.53.1
by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any. |
270 |
|
2220.2.30
by Martin Pool
split out tag-merging code and add some tests |
271 |
|
7489.3.2
by Jelmer Vernooij
Use InterTags in anger. |
272 |
class MemoryTags(Tags): |
7260.3.2
by Jelmer Vernooij
Add a MemoryTag object. |
273 |
|
274 |
def __init__(self, tag_dict): |
|
275 |
self._tag_dict = tag_dict |
|
276 |
||
277 |
def get_tag_dict(self): |
|
278 |
return self._tag_dict |
|
279 |
||
280 |
def lookup_tag(self, tag_name): |
|
281 |
"""Return the referent string of a tag""" |
|
282 |
td = self.get_tag_dict() |
|
283 |
try: |
|
284 |
return td[tag_name] |
|
285 |
except KeyError: |
|
286 |
raise errors.NoSuchTag(tag_name) |
|
287 |
||
288 |
def set_tag(self, name, revid): |
|
289 |
self._tag_dict[name] = revid |
|
290 |
||
291 |
def delete_tag(self, name): |
|
292 |
try: |
|
293 |
del self._tag_dict[name] |
|
294 |
except KeyError: |
|
295 |
raise errors.NoSuchTag(name) |
|
296 |
||
297 |
def rename_revisions(self, revid_map): |
|
298 |
self._tag_dict = { |
|
299 |
name: revid_map.get(revid, revid) |
|
300 |
for name, revid in self._tag_dict.items()} |
|
301 |
||
7260.3.3
by Jelmer Vernooij
Add merge_to support. |
302 |
def _set_tag_dict(self, result): |
303 |
self._tag_dict = dict(result.items()) |
|
304 |
||
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
305 |
def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None): |
7260.3.3
by Jelmer Vernooij
Add merge_to support. |
306 |
source_dict = self.get_tag_dict() |
307 |
dest_dict = to_tags.get_tag_dict() |
|
308 |
result, updates, conflicts = _reconcile_tags( |
|
7489.4.1
by Jelmer Vernooij
Add tag selecting callback. |
309 |
source_dict, dest_dict, overwrite, selector) |
7260.3.3
by Jelmer Vernooij
Add merge_to support. |
310 |
if result != dest_dict: |
311 |
to_tags._set_tag_dict(result) |
|
312 |
return updates, conflicts |
|
313 |
||
7260.3.2
by Jelmer Vernooij
Add a MemoryTag object. |
314 |
|
5582.2.1
by Jelmer Vernooij
support extending --sort argument to 'bzr tags'. |
315 |
def sort_natural(branch, tags): |
316 |
"""Sort tags, with numeric substrings as numbers. |
|
317 |
||
318 |
:param branch: Branch
|
|
319 |
:param tags: List of tuples with tag name and revision id.
|
|
320 |
"""
|
|
321 |
def natural_sort_key(tag): |
|
6809.1.1
by Martin
Apply 2to3 ws_comma fixer |
322 |
return [f(s) for f, s in |
7479.2.1
by Jelmer Vernooij
Drop python2 support. |
323 |
zip(itertools.cycle((str.lower, int)), |
7143.15.2
by Jelmer Vernooij
Run autopep8. |
324 |
re.split('([0-9]+)', tag[0]))] |
5582.2.1
by Jelmer Vernooij
support extending --sort argument to 'bzr tags'. |
325 |
tags.sort(key=natural_sort_key) |
326 |
||
327 |
||
328 |
def sort_alpha(branch, tags): |
|
329 |
"""Sort tags lexicographically, in place. |
|
330 |
||
331 |
:param branch: Branch
|
|
332 |
:param tags: List of tuples with tag name and revision id.
|
|
333 |
"""
|
|
334 |
tags.sort() |
|
335 |
||
336 |
||
337 |
def sort_time(branch, tags): |
|
338 |
"""Sort tags by time inline. |
|
339 |
||
340 |
:param branch: Branch
|
|
341 |
:param tags: List of tuples with tag name and revision id.
|
|
342 |
"""
|
|
343 |
timestamps = {} |
|
344 |
for tag, revid in tags: |
|
345 |
try: |
|
346 |
revobj = branch.repository.get_revision(revid) |
|
347 |
except errors.NoSuchRevision: |
|
7143.15.2
by Jelmer Vernooij
Run autopep8. |
348 |
timestamp = sys.maxsize # place them at the end |
5582.2.1
by Jelmer Vernooij
support extending --sort argument to 'bzr tags'. |
349 |
else: |
350 |
timestamp = revobj.timestamp |
|
351 |
timestamps[revid] = timestamp |
|
352 |
tags.sort(key=lambda x: timestamps[x[1]]) |
|
353 |
||
354 |
||
355 |
tag_sort_methods = Registry() |
|
356 |
tag_sort_methods.register("natural", sort_natural, |
|
7143.15.2
by Jelmer Vernooij
Run autopep8. |
357 |
'Sort numeric substrings as numbers. (default)') |
5582.2.1
by Jelmer Vernooij
support extending --sort argument to 'bzr tags'. |
358 |
tag_sort_methods.register("alpha", sort_alpha, 'Sort tags lexicographically.') |
359 |
tag_sort_methods.register("time", sort_time, 'Sort tags chronologically.') |
|
360 |
tag_sort_methods.default_key = "natural" |
|
7489.3.1
by Jelmer Vernooij
Add InterTags object. |
361 |
|
362 |
||
363 |
InterTags.register_optimiser(InterTags) |