/brz/remove-bazaar

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