189
198
:param to_tags: Branch to receive these tags
190
199
:param overwrite: Overwrite conflicting tags in the target branch
200
:param ignore_master: Do not modify the tags in the target's master
201
branch (if any). Default is false (so the master will be updated).
192
:returns: A list of tags that conflicted, each of which is
204
:returns: A set of tags that conflicted, each of which is
193
205
(tagname, source_target, dest_target), or None if no copying was
208
operation = cleanup.OperationWithCleanups(self._merge_to_operation)
209
return operation.run(to_tags, overwrite, ignore_master)
211
def _merge_to_operation(self, operation, to_tags, overwrite, ignore_master):
212
add_cleanup = operation.add_cleanup
196
213
if self.branch == to_tags.branch:
198
215
if not self.branch.supports_tags():
203
220
# no tags in the source, and we don't want to clobber anything
204
221
# that's in the destination
206
to_tags.branch.lock_write()
208
dest_dict = to_tags.get_tag_dict()
209
result, conflicts = self._reconcile_tags(source_dict, dest_dict,
211
if result != dest_dict:
212
to_tags._set_tag_dict(result)
214
to_tags.branch.unlock()
223
# We merge_to both master and child individually.
225
# It's possible for master and child to have differing sets of
226
# tags, in which case it's possible to have different sets of
227
# conflicts. We report the union of both conflict sets. In
228
# that case it's likely the child and master have accepted
229
# different tags from the source, which may be a surprising result, but
230
# the best we can do in the circumstances.
232
# Ideally we'd improve this API to report the different conflicts
233
# more clearly to the caller, but we don't want to break plugins
234
# such as bzr-builddeb that use this API.
235
add_cleanup(to_tags.branch.lock_write().unlock)
239
master = to_tags.branch.get_master_branch()
240
if master is not None:
241
add_cleanup(master.lock_write().unlock)
242
conflicts = self._merge_to(to_tags, source_dict, overwrite)
243
if master is not None:
244
conflicts += self._merge_to(master.tags, source_dict,
246
# We use set() to remove any duplicate conflicts from the master
248
return set(conflicts)
250
def _merge_to(self, to_tags, source_dict, overwrite):
251
dest_dict = to_tags.get_tag_dict()
252
result, conflicts = self._reconcile_tags(source_dict, dest_dict,
254
if result != dest_dict:
255
to_tags._set_tag_dict(result)
217
258
def rename_revisions(self, rename_map):
249
290
return result, conflicts
252
def _merge_tags_if_possible(from_branch, to_branch):
253
from_branch.tags.merge_to(to_branch.tags)
293
def _merge_tags_if_possible(from_branch, to_branch, ignore_master=False):
294
# Try hard to support merge_to implementations that don't expect
295
# 'ignore_master' (new in bzr 2.3). First, if the flag isn't set then we
296
# can safely avoid passing ignore_master at all.
297
if not ignore_master:
298
from_branch.tags.merge_to(to_branch.tags)
300
# If the flag is set, try to pass it, but be ready to catch TypeError.
302
from_branch.tags.merge_to(to_branch.tags, ignore_master=ignore_master)
304
# Probably this implementation of 'merge_to' is from a plugin that
305
# doesn't expect the 'ignore_master' keyword argument (e.g. bzr-svn
306
# 1.0.4). There's a small risk that the TypeError is actually caused
307
# by a completely different problem (which is why we don't catch it for
308
# the ignore_master=False case), but even then there's probably no harm
309
# in calling a second time.
310
symbol_versioning.warn(
311
symbol_versioning.deprecated_in((2,3)) % (
312
"Tags.merge_to (of %r) that doesn't accept ignore_master kwarg"
313
% (from_branch.tags,),),
315
from_branch.tags.merge_to(to_branch.tags)
318
def sort_natural(branch, tags):
319
"""Sort tags, with numeric substrings as numbers.
321
:param branch: Branch
322
:param tags: List of tuples with tag name and revision id.
324
def natural_sort_key(tag):
325
return [f(s) for f,s in
326
zip(itertools.cycle((unicode.lower,int)),
327
re.split('([0-9]+)', tag[0]))]
328
tags.sort(key=natural_sort_key)
331
def sort_alpha(branch, tags):
332
"""Sort tags lexicographically, in place.
334
:param branch: Branch
335
:param tags: List of tuples with tag name and revision id.
340
def sort_time(branch, tags):
341
"""Sort tags by time inline.
343
:param branch: Branch
344
:param tags: List of tuples with tag name and revision id.
347
for tag, revid in tags:
349
revobj = branch.repository.get_revision(revid)
350
except errors.NoSuchRevision:
351
timestamp = sys.maxint # place them at the end
353
timestamp = revobj.timestamp
354
timestamps[revid] = timestamp
355
tags.sort(key=lambda x: timestamps[x[1]])
358
tag_sort_methods = Registry()
359
tag_sort_methods.register("natural", sort_natural,
360
'Sort numeric substrings as numbers. (default)')
361
tag_sort_methods.register("alpha", sort_alpha, 'Sort tags lexicographically.')
362
tag_sort_methods.register("time", sort_time, 'Sort tags chronologically.')
363
tag_sort_methods.default_key = "natural"