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