~bzr-pqm/bzr/bzr.dev

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
25
# NOTE: I was going to call this tags.py, but vim seems to think all files
26
# called tags* are ctags files... mbp 20070220.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
27
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
28
from bzrlib.registry import Registry
29
from bzrlib.lazy_import import lazy_import
30
lazy_import(globals(), """
31
import itertools
32
import re
33
import sys
2220.2.14 by mbp at sourcefrog
cleanup
34
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
35
from bzrlib import (
2694.5.4 by Jelmer Vernooij
Move bzrlib.util.bencode to bzrlib._bencode_py.
36
    bencode,
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
37
    cleanup,
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
38
    errors,
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
39
    symbol_versioning,
2220.2.27 by Martin Pool
Start adding tags to Branch6
40
    trace,
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
41
    )
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
42
""")
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
43
44
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
45
class _Tags(object):
2220.2.28 by Martin Pool
Integrate tags with Branch6:
46
2220.2.14 by mbp at sourcefrog
cleanup
47
    def __init__(self, branch):
48
        self.branch = branch
49
6123.4.1 by Jelmer Vernooij
Add stubs.
50
    def get_tag_dict(self):
51
        """Return a dictionary mapping tags to revision ids.
52
        """
53
        raise NotImplementedError(self.get_tag_dict)
54
55
    def get_reverse_tag_dict(self):
56
        """Return a dictionary mapping revision ids to list of tags.
57
        """
58
        raise NotImplementedError(self.get_reverse_tag_dict)
59
60
    def merge_to(self, to_tags, overwrite=False, ignore_master=False):
61
        """Merge new tags from this tags container into another.
62
63
        :param to_tags: Tags container to merge into
64
        :param overwrite: Whether to overwrite existing, divergent, tags.
65
        :param ignore_master: Do not modify the tags in the target's master
66
            branch (if any).  Default is false (so the master will be updated).
67
            New in bzr 2.3.
68
        :return: Tuple with tag updates as dictionary and tag conflicts
69
        """
70
        raise NotImplementedError(self.merge_to)
71
72
    def set_tag(self, tag_name, revision):
73
        """Set a tag.
74
75
        :param tag_name: Tag name
76
        :param revision: Revision id
6123.4.2 by Jelmer Vernooij
Tags containers can indicate whether they support ghost tags.
77
        :raise GhostTagsNotSupported: if revision is not present in
78
            the branch repository
6123.4.1 by Jelmer Vernooij
Add stubs.
79
        """
80
        raise NotImplementedError(self.set_tag)
81
82
    def lookup_tag(self, tag_name):
83
        """Look up a tag.
84
85
        :param tag_name: Tag to look up
86
        :raise NoSuchTag: Raised when tag does not exist
87
        :return: Matching revision id
88
        """
89
        raise NotImplementedError(self.lookup_tag)
90
91
    def delete_tag(self, tag_name):
92
        """Delete a tag.
93
94
        :param tag_name: Tag to delete
95
        :raise NoSuchTag: Raised when tag does not exist
96
        """
97
        raise NotImplementedError(self.delete_tag)
98
99
    def rename_revisions(self, rename_map):
100
        """Replace revision ids according to a rename map.
101
102
        :param rename_map: Dictionary mapping old revision ids to
103
            new revision ids.
104
        """
105
        raise NotImplementedError(self.rename_revisions)
106
2220.2.42 by Martin Pool
Tag command refuses to replace existing tags unless you force it.
107
    def has_tag(self, tag_name):
108
        return self.get_tag_dict().has_key(tag_name)
109
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
110
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
111
class DisabledTags(_Tags):
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
112
    """Tag storage that refuses to store anything.
113
114
    This is used by older formats that can't store tags.
115
    """
116
117
    def _not_supported(self, *a, **k):
2220.2.14 by mbp at sourcefrog
cleanup
118
        raise errors.TagsNotSupported(self.branch)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
119
120
    set_tag = _not_supported
121
    get_tag_dict = _not_supported
122
    _set_tag_dict = _not_supported
123
    lookup_tag = _not_supported
2220.2.21 by Martin Pool
Add tag --delete command and implementation
124
    delete_tag = _not_supported
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
125
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
126
    def merge_to(self, to_tags, overwrite=False, ignore_master=False):
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
127
        # we never have anything to copy
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
128
        return {}, []
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
129
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
130
    def rename_revisions(self, rename_map):
131
        # No tags, so nothing to rename
132
        pass
133
2831.8.1 by James Westby
Fix log against smart server branches that don't support tags. (#140615)
134
    def get_reverse_tag_dict(self):
135
        # There aren't any tags, so the reverse mapping is empty.
136
        return {}
137
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
138
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
139
class BasicTags(_Tags):
2220.2.14 by mbp at sourcefrog
cleanup
140
    """Tag storage in an unversioned branch control file.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
141
    """
142
143
    def set_tag(self, tag_name, tag_target):
2220.2.14 by mbp at sourcefrog
cleanup
144
        """Add a tag definition to the branch.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
145
146
        Behaviour if the tag is already present is not defined (yet).
147
        """
148
        # all done with a write lock held, so this looks atomic
2220.2.14 by mbp at sourcefrog
cleanup
149
        self.branch.lock_write()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
150
        try:
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
151
            master = self.branch.get_master_branch()
152
            if master is not None:
153
                master.tags.set_tag(tag_name, tag_target)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
154
            td = self.get_tag_dict()
155
            td[tag_name] = tag_target
156
            self._set_tag_dict(td)
157
        finally:
2220.2.14 by mbp at sourcefrog
cleanup
158
            self.branch.unlock()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
159
160
    def lookup_tag(self, tag_name):
161
        """Return the referent string of a tag"""
162
        td = self.get_tag_dict()
163
        try:
164
            return td[tag_name]
165
        except KeyError:
166
            raise errors.NoSuchTag(tag_name)
167
168
    def get_tag_dict(self):
2220.2.14 by mbp at sourcefrog
cleanup
169
        self.branch.lock_read()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
170
        try:
2220.2.27 by Martin Pool
Start adding tags to Branch6
171
            try:
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
172
                tag_content = self.branch._get_tags_bytes()
2220.2.27 by Martin Pool
Start adding tags to Branch6
173
            except errors.NoSuchFile, e:
2220.2.28 by Martin Pool
Integrate tags with Branch6:
174
                # ugly, but only abentley should see this :)
175
                trace.warning('No branch/tags file in %s.  '
2220.2.27 by Martin Pool
Start adding tags to Branch6
176
                     'This branch was probably created by bzr 0.15pre.  '
2220.2.28 by Martin Pool
Integrate tags with Branch6:
177
                     'Create an empty file to silence this message.'
178
                     % (self.branch, ))
2220.2.27 by Martin Pool
Start adding tags to Branch6
179
                return {}
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
180
            return self._deserialize_tag_dict(tag_content)
181
        finally:
2220.2.14 by mbp at sourcefrog
cleanup
182
            self.branch.unlock()
2388.1.11 by Alexander Belchenko
changes after John's review
183
2388.1.1 by Erik Bagfors
created reverse_tag_dict in tags.py
184
    def get_reverse_tag_dict(self):
185
        """Returns a dict with revisions as keys
186
           and a list of tags for that revision as value"""
187
        d = self.get_tag_dict()
188
        rev = {}
189
        for key in d:
190
            try:
191
                rev[d[key]].append(key)
192
            except KeyError:
193
                rev[d[key]] = [key]
194
        return rev
195
2220.2.21 by Martin Pool
Add tag --delete command and implementation
196
    def delete_tag(self, tag_name):
197
        """Delete a tag definition.
198
        """
199
        self.branch.lock_write()
200
        try:
201
            d = self.get_tag_dict()
202
            try:
203
                del d[tag_name]
204
            except KeyError:
205
                raise errors.NoSuchTag(tag_name)
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
206
            master = self.branch.get_master_branch()
207
            if master is not None:
208
                try:
209
                    master.tags.delete_tag(tag_name)
210
                except errors.NoSuchTag:
211
                    pass
2220.2.21 by Martin Pool
Add tag --delete command and implementation
212
            self._set_tag_dict(d)
213
        finally:
214
            self.branch.unlock()
215
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
216
    def _set_tag_dict(self, new_dict):
217
        """Replace all tag definitions
218
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
219
        WARNING: Calling this on an unlocked branch will lock it, and will
220
        replace the tags without warning on conflicts.
221
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
222
        :param new_dict: Dictionary from tag name to target.
223
        """
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
224
        return self.branch._set_tags_bytes(self._serialize_tag_dict(new_dict))
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
225
226
    def _serialize_tag_dict(self, tag_dict):
2220.2.21 by Martin Pool
Add tag --delete command and implementation
227
        td = dict((k.encode('utf-8'), v)
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
228
                  for k,v in tag_dict.items())
2220.2.21 by Martin Pool
Add tag --delete command and implementation
229
        return bencode.bencode(td)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
230
231
    def _deserialize_tag_dict(self, tag_content):
232
        """Convert the tag file into a dictionary of tags"""
2220.2.28 by Martin Pool
Integrate tags with Branch6:
233
        # was a special case to make initialization easy, an empty definition
2220.2.15 by mbp at sourcefrog
Store tag dictionary in bencode and accomodate non-ascii tags
234
        # is an empty dictionary
235
        if tag_content == '':
236
            return {}
237
        try:
2220.2.21 by Martin Pool
Add tag --delete command and implementation
238
            r = {}
239
            for k, v in bencode.bdecode(tag_content).items():
240
                r[k.decode('utf-8')] = v
241
            return r
242
        except ValueError, e:
243
            raise ValueError("failed to deserialize tag dictionary %r: %s"
2220.2.32 by Martin Pool
Slightly smarter tag merge
244
                % (tag_content, e))
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
245
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
246
    def merge_to(self, to_tags, overwrite=False, ignore_master=False):
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
247
        """Copy tags between repositories if necessary and possible.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
248
249
        This method has common command-line behaviour about handling
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
250
        error cases.
251
2220.2.32 by Martin Pool
Slightly smarter tag merge
252
        All new definitions are copied across, except that tags that already
253
        exist keep their existing definitions.
254
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
255
        :param to_tags: Branch to receive these tags
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
256
        :param overwrite: Overwrite conflicting tags in the target branch
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
257
        :param ignore_master: Do not modify the tags in the target's master
258
            branch (if any).  Default is false (so the master will be updated).
5540.4.2 by Andrew Bennetts
Remove references to 2.2.2 in comments and warnings: this patch was not accepted for 2.2.
259
            New in bzr 2.3.
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
260
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
261
        :returns: Tuple with tag_updates and tag_conflicts.
262
            tag_updates is a dictionary with new tags, None is used for
263
            removed tags
264
            tag_conflicts is a set of tags that conflicted, each of which is
3482.1.1 by John Arbash Meinel
Fix bug #238149, RemoteBranch.pull needs to return the _real_branch's pull result.
265
            (tagname, source_target, dest_target), or None if no copying was
266
            done.
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
267
        """
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
268
        operation = cleanup.OperationWithCleanups(self._merge_to_operation)
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
269
        return operation.run(to_tags, overwrite, ignore_master)
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
270
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
271
    def _merge_to_operation(self, operation, to_tags, overwrite, ignore_master):
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
272
        add_cleanup = operation.add_cleanup
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
273
        if self.branch == to_tags.branch:
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
274
            return {}, []
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
275
        if not self.branch.supports_tags():
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
276
            # obviously nothing to copy
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
277
            return {}, []
2220.2.32 by Martin Pool
Slightly smarter tag merge
278
        source_dict = self.get_tag_dict()
279
        if not source_dict:
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
280
            # no tags in the source, and we don't want to clobber anything
281
            # that's in the destination
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
282
            return {}, []
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
283
        # We merge_to both master and child individually.
5050.53.2 by Andrew Bennetts
More tests, more description of test intent, and specify exactly what happens with duplicate vs. different conflicts.
284
        #
285
        # It's possible for master and child to have differing sets of
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
286
        # tags, in which case it's possible to have different sets of
287
        # conflicts.  We report the union of both conflict sets.  In
288
        # that case it's likely the child and master have accepted
5050.53.2 by Andrew Bennetts
More tests, more description of test intent, and specify exactly what happens with duplicate vs. different conflicts.
289
        # different tags from the source, which may be a surprising result, but
290
        # the best we can do in the circumstances.
291
        #
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
292
        # Ideally we'd improve this API to report the different conflicts
293
        # more clearly to the caller, but we don't want to break plugins
294
        # such as bzr-builddeb that use this API.
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
295
        add_cleanup(to_tags.branch.lock_write().unlock)
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
296
        if ignore_master:
297
            master = None
298
        else:
299
            master = to_tags.branch.get_master_branch()
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
300
        if master is not None:
301
            add_cleanup(master.lock_write().unlock)
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
302
        updates, conflicts = self._merge_to(to_tags, source_dict, overwrite)
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
303
        if master is not None:
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
304
            extra_updates, extra_conflicts = self._merge_to(master.tags,
305
                source_dict, overwrite)
306
            updates.update(extra_updates)
307
            conflicts += extra_conflicts
5050.53.2 by Andrew Bennetts
More tests, more description of test intent, and specify exactly what happens with duplicate vs. different conflicts.
308
        # We use set() to remove any duplicate conflicts from the master
5540.4.3 by Andrew Bennetts
Simplify slightly, we don't need to be quite so paranoid about API breakage in the development branch.
309
        # branch.
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
310
        return updates, set(conflicts)
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
311
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
312
    def _merge_to(self, to_tags, source_dict, overwrite):
313
        dest_dict = to_tags.get_tag_dict()
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
314
        result, updates, conflicts = self._reconcile_tags(source_dict,
315
            dest_dict, overwrite)
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
316
        if result != dest_dict:
317
            to_tags._set_tag_dict(result)
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
318
        return updates, conflicts
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
319
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
320
    def rename_revisions(self, rename_map):
321
        """Rename revisions in this tags dictionary.
6123.4.1 by Jelmer Vernooij
Add stubs.
322
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
323
        :param rename_map: Dictionary mapping old revids to new revids
324
        """
325
        reverse_tags = self.get_reverse_tag_dict()
326
        for revid, names in reverse_tags.iteritems():
327
            if revid in rename_map:
328
                for name in names:
329
                    self.set_tag(name, rename_map[revid])
330
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
331
    def _reconcile_tags(self, source_dict, dest_dict, overwrite):
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
332
        """Do a two-way merge of two tag dictionaries.
333
5891.1.2 by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier.
334
        * only in source => source value
335
        * only in destination => destination value
336
        * same definitions => that
337
        * different definitions => if overwrite is False, keep destination
338
          value and give a warning, otherwise use the source value
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
339
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
340
        :returns: (result_dict, updates,
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
341
            [(conflicting_tag, source_target, dest_target)])
342
        """
343
        conflicts = []
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
344
        updates = {}
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
345
        result = dict(dest_dict) # copy
346
        for name, target in source_dict.items():
6156.1.2 by Jelmer Vernooij
Fix tests.
347
            if result.get(name) == target:
348
                pass
349
            elif name not in result or overwrite:
350
                updates[name] = target
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
351
                result[name] = target
352
            else:
353
                conflicts.append((name, target, result[name]))
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
354
        return result, updates, conflicts
2220.2.32 by Martin Pool
Slightly smarter tag merge
355
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
356
5609.25.3 by Andrew Bennetts
Alternative fix: cache the result of get_master_branch for the lifetime of the branch lock.
357
def _merge_tags_if_possible(from_branch, to_branch, ignore_master=False):
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
358
    # Try hard to support merge_to implementations that don't expect
5540.4.2 by Andrew Bennetts
Remove references to 2.2.2 in comments and warnings: this patch was not accepted for 2.2.
359
    # 'ignore_master' (new in bzr 2.3).  First, if the flag isn't set then we
360
    # can safely avoid passing ignore_master at all.
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
361
    if not ignore_master:
5609.25.3 by Andrew Bennetts
Alternative fix: cache the result of get_master_branch for the lifetime of the branch lock.
362
        from_branch.tags.merge_to(to_branch.tags)
363
        return
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
364
    # If the flag is set, try to pass it, but be ready to catch TypeError.
365
    try:
5609.25.3 by Andrew Bennetts
Alternative fix: cache the result of get_master_branch for the lifetime of the branch lock.
366
        from_branch.tags.merge_to(to_branch.tags, ignore_master=ignore_master)
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
367
    except TypeError:
368
        # Probably this implementation of 'merge_to' is from a plugin that
369
        # doesn't expect the 'ignore_master' keyword argument (e.g. bzr-svn
370
        # 1.0.4).  There's a small risk that the TypeError is actually caused
371
        # by a completely different problem (which is why we don't catch it for
372
        # the ignore_master=False case), but even then there's probably no harm
373
        # in calling a second time.
374
        symbol_versioning.warn(
5540.4.2 by Andrew Bennetts
Remove references to 2.2.2 in comments and warnings: this patch was not accepted for 2.2.
375
            symbol_versioning.deprecated_in((2,3)) % (
5050.53.9 by Andrew Bennetts
Cosmetic tweak to deprecation.
376
                "Tags.merge_to (of %r) that doesn't accept ignore_master kwarg"
377
                % (from_branch.tags,),),
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
378
            DeprecationWarning)
5609.25.3 by Andrew Bennetts
Alternative fix: cache the result of get_master_branch for the lifetime of the branch lock.
379
        from_branch.tags.merge_to(to_branch.tags)
5086.4.1 by Jelmer Vernooij
New function ``determine_tag_name`` that can be used to find a
380
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
381
382
def sort_natural(branch, tags):
383
    """Sort tags, with numeric substrings as numbers.
384
385
    :param branch: Branch
386
    :param tags: List of tuples with tag name and revision id.
387
    """
388
    def natural_sort_key(tag):
389
        return [f(s) for f,s in
390
                zip(itertools.cycle((unicode.lower,int)),
391
                                    re.split('([0-9]+)', tag[0]))]
392
    tags.sort(key=natural_sort_key)
393
394
395
def sort_alpha(branch, tags):
396
    """Sort tags lexicographically, in place.
397
398
    :param branch: Branch
399
    :param tags: List of tuples with tag name and revision id.
400
    """
401
    tags.sort()
402
403
404
def sort_time(branch, tags):
405
    """Sort tags by time inline.
406
407
    :param branch: Branch
408
    :param tags: List of tuples with tag name and revision id.
409
    """
410
    timestamps = {}
411
    for tag, revid in tags:
412
        try:
413
            revobj = branch.repository.get_revision(revid)
414
        except errors.NoSuchRevision:
415
            timestamp = sys.maxint # place them at the end
416
        else:
417
            timestamp = revobj.timestamp
418
        timestamps[revid] = timestamp
419
    tags.sort(key=lambda x: timestamps[x[1]])
420
421
422
tag_sort_methods = Registry()
423
tag_sort_methods.register("natural", sort_natural,
424
    'Sort numeric substrings as numbers. (default)')
425
tag_sort_methods.register("alpha", sort_alpha, 'Sort tags lexicographically.')
426
tag_sort_methods.register("time", sort_time, 'Sort tags chronologically.')
427
tag_sort_methods.default_key = "natural"