49
def _reconcile_tags(source_dict, dest_dict, overwrite):
50
"""Do a two-way merge of two tag dictionaries.
52
* only in source => source value
53
* only in destination => destination value
54
* same definitions => that
55
* different definitions => if overwrite is False, keep destination
56
value and add to conflict list, otherwise use the source value
58
:returns: (result_dict, updates,
59
[(conflicting_tag, source_target, dest_target)])
63
result = dict(dest_dict) # copy
64
for name, target in source_dict.items():
65
if result.get(name) == target:
67
elif name not in result or overwrite:
68
updates[name] = target
71
conflicts.append((name, target, result[name]))
72
return result, updates, conflicts
47
75
class _Tags(object):
49
77
def __init__(self, branch):
148
176
Behaviour if the tag is already present is not defined (yet).
150
178
# all done with a write lock held, so this looks atomic
151
self.branch.lock_write()
179
with self.branch.lock_write():
153
180
master = self.branch.get_master_branch()
154
181
if master is not None:
155
182
master.tags.set_tag(tag_name, tag_target)
156
183
td = self.get_tag_dict()
157
184
td[tag_name] = tag_target
158
185
self._set_tag_dict(td)
162
187
def lookup_tag(self, tag_name):
163
188
"""Return the referent string of a tag"""
171
196
with self.branch.lock_read():
173
198
tag_content = self.branch._get_tags_bytes()
174
except errors.NoSuchFile as e:
199
except errors.NoSuchFile:
175
200
# ugly, but only abentley should see this :)
176
201
trace.warning('No branch/tags file in %s. '
177
'This branch was probably created by bzr 0.15pre. '
178
'Create an empty file to silence this message.'
202
'This branch was probably created by bzr 0.15pre. '
203
'Create an empty file to silence this message.'
181
206
return self._deserialize_tag_dict(tag_content)
311
330
def _merge_to(self, to_tags, source_dict, overwrite):
312
331
dest_dict = to_tags.get_tag_dict()
313
result, updates, conflicts = self._reconcile_tags(source_dict,
314
dest_dict, overwrite)
332
result, updates, conflicts = _reconcile_tags(
333
source_dict, dest_dict, overwrite)
315
334
if result != dest_dict:
316
335
to_tags._set_tag_dict(result)
317
336
return updates, conflicts
327
346
for name in names:
328
347
self.set_tag(name, rename_map[revid])
330
def _reconcile_tags(self, source_dict, dest_dict, overwrite):
331
"""Do a two-way merge of two tag dictionaries.
333
* only in source => source value
334
* only in destination => destination value
335
* same definitions => that
336
* different definitions => if overwrite is False, keep destination
337
value and give a warning, otherwise use the source value
339
:returns: (result_dict, updates,
340
[(conflicting_tag, source_target, dest_target)])
344
result = dict(dest_dict) # copy
345
for name, target in source_dict.items():
346
if result.get(name) == target:
348
elif name not in result or overwrite:
349
updates[name] = target
350
result[name] = target
352
conflicts.append((name, target, result[name]))
353
return result, updates, conflicts
350
class MemoryTags(_Tags):
352
def __init__(self, tag_dict):
353
self._tag_dict = tag_dict
355
def get_tag_dict(self):
356
return self._tag_dict
358
def lookup_tag(self, tag_name):
359
"""Return the referent string of a tag"""
360
td = self.get_tag_dict()
364
raise errors.NoSuchTag(tag_name)
366
def get_reverse_tag_dict(self):
367
"""Returns a dict with revisions as keys
368
and a list of tags for that revision as value"""
369
d = self.get_tag_dict()
370
rev = defaultdict(set)
375
def set_tag(self, name, revid):
376
self._tag_dict[name] = revid
378
def delete_tag(self, name):
380
del self._tag_dict[name]
382
raise errors.NoSuchTag(name)
384
def rename_revisions(self, revid_map):
386
name: revid_map.get(revid, revid)
387
for name, revid in self._tag_dict.items()}
389
def _set_tag_dict(self, result):
390
self._tag_dict = dict(result.items())
392
def merge_to(self, to_tags, overwrite=False, ignore_master=False):
393
source_dict = self.get_tag_dict()
394
dest_dict = to_tags.get_tag_dict()
395
result, updates, conflicts = _reconcile_tags(
396
source_dict, dest_dict, overwrite)
397
if result != dest_dict:
398
to_tags._set_tag_dict(result)
399
return updates, conflicts
356
402
def sort_natural(branch, tags):
396
442
tag_sort_methods = Registry()
397
443
tag_sort_methods.register("natural", sort_natural,
398
'Sort numeric substrings as numbers. (default)')
444
'Sort numeric substrings as numbers. (default)')
399
445
tag_sort_methods.register("alpha", sort_alpha, 'Sort tags lexicographically.')
400
446
tag_sort_methods.register("time", sort_time, 'Sort tags chronologically.')
401
447
tag_sort_methods.default_key = "natural"