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