/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
        """
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
286
        operation = cleanup.OperationWithCleanups(self._merge_to_operation)
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
287
        return operation.run(to_tags, overwrite, ignore_master)
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
288
5050.53.4 by Andrew Bennetts
Don't propagate tags to the master branch during cmd_merge.
289
    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.
290
        add_cleanup = operation.add_cleanup
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
291
        if self.branch == to_tags.branch:
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
292
            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.
293
        if not self.branch.supports_tags():
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
294
            # obviously nothing to copy
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
295
            return {}, []
2220.2.32 by Martin Pool
Slightly smarter tag merge
296
        source_dict = self.get_tag_dict()
297
        if not source_dict:
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
298
            # no tags in the source, and we don't want to clobber anything
299
            # that's in the destination
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
300
            return {}, []
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
301
        # 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.
302
        #
303
        # 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.
304
        # tags, in which case it's possible to have different sets of
305
        # conflicts.  We report the union of both conflict sets.  In
306
        # 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.
307
        # different tags from the source, which may be a surprising result, but
308
        # the best we can do in the circumstances.
309
        #
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
310
        # Ideally we'd improve this API to report the different conflicts
311
        # more clearly to the caller, but we don't want to break plugins
312
        # such as bzr-builddeb that use this API.
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
313
        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.
314
        if ignore_master:
315
            master = None
316
        else:
317
            master = to_tags.branch.get_master_branch()
5050.53.3 by Andrew Bennetts
Use add_cleanup for simpler and more correct unlocking.
318
        if master is not None:
319
            add_cleanup(master.lock_write().unlock)
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
320
        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.
321
        if master is not None:
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
322
            extra_updates, extra_conflicts = self._merge_to(master.tags,
7143.15.2 by Jelmer Vernooij
Run autopep8.
323
                                                            source_dict, overwrite)
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
324
            updates.update(extra_updates)
325
            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.
326
        # 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.
327
        # branch.
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
328
        return updates, set(conflicts)
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
329
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
330
    def _merge_to(self, to_tags, source_dict, overwrite):
331
        dest_dict = to_tags.get_tag_dict()
7260.3.3 by Jelmer Vernooij
Add merge_to support.
332
        result, updates, conflicts = _reconcile_tags(
333
            source_dict, dest_dict, overwrite)
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
334
        if result != dest_dict:
335
            to_tags._set_tag_dict(result)
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
336
        return updates, conflicts
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
337
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
338
    def rename_revisions(self, rename_map):
339
        """Rename revisions in this tags dictionary.
6123.4.1 by Jelmer Vernooij
Add stubs.
340
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
341
        :param rename_map: Dictionary mapping old revids to new revids
342
        """
343
        reverse_tags = self.get_reverse_tag_dict()
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
344
        for revid, names in reverse_tags.items():
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
345
            if revid in rename_map:
346
                for name in names:
347
                    self.set_tag(name, rename_map[revid])
348
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
349
7260.3.2 by Jelmer Vernooij
Add a MemoryTag object.
350
class MemoryTags(_Tags):
351
352
    def __init__(self, tag_dict):
353
        self._tag_dict = tag_dict
354
355
    def get_tag_dict(self):
356
        return self._tag_dict
357
358
    def lookup_tag(self, tag_name):
359
        """Return the referent string of a tag"""
360
        td = self.get_tag_dict()
361
        try:
362
            return td[tag_name]
363
        except KeyError:
364
            raise errors.NoSuchTag(tag_name)
365
366
    def get_reverse_tag_dict(self):
367
        """Returns a dict with revisions as keys
368
           and a list of tags for that revision as value"""
369
        d = self.get_tag_dict()
7260.3.4 by Jelmer Vernooij
Use defaultdict.
370
        rev = defaultdict(set)
7260.3.2 by Jelmer Vernooij
Add a MemoryTag object.
371
        for key in d:
7260.3.4 by Jelmer Vernooij
Use defaultdict.
372
            rev[d[key]].add(key)
7260.3.2 by Jelmer Vernooij
Add a MemoryTag object.
373
        return rev
374
375
    def set_tag(self, name, revid):
376
        self._tag_dict[name] = revid
377
378
    def delete_tag(self, name):
379
        try:
380
            del self._tag_dict[name]
381
        except KeyError:
382
            raise errors.NoSuchTag(name)
383
384
    def rename_revisions(self, revid_map):
385
        self._tag_dict = {
386
            name: revid_map.get(revid, revid)
387
            for name, revid in self._tag_dict.items()}
388
7260.3.3 by Jelmer Vernooij
Add merge_to support.
389
    def _set_tag_dict(self, result):
390
        self._tag_dict = dict(result.items())
391
392
    def merge_to(self, to_tags, overwrite=False, ignore_master=False):
393
        source_dict = self.get_tag_dict()
394
        dest_dict = to_tags.get_tag_dict()
395
        result, updates, conflicts = _reconcile_tags(
396
            source_dict, dest_dict, overwrite)
397
        if result != dest_dict:
398
            to_tags._set_tag_dict(result)
399
        return updates, conflicts
400
7260.3.2 by Jelmer Vernooij
Add a MemoryTag object.
401
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
402
def sort_natural(branch, tags):
403
    """Sort tags, with numeric substrings as numbers.
404
405
    :param branch: Branch
406
    :param tags: List of tuples with tag name and revision id.
407
    """
408
    def natural_sort_key(tag):
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
409
        return [f(s) for f, s in
6973.6.2 by Jelmer Vernooij
Fix more tests.
410
                zip(itertools.cycle((text_type.lower, int)),
7143.15.2 by Jelmer Vernooij
Run autopep8.
411
                    re.split('([0-9]+)', tag[0]))]
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
412
    tags.sort(key=natural_sort_key)
413
414
415
def sort_alpha(branch, tags):
416
    """Sort tags lexicographically, in place.
417
418
    :param branch: Branch
419
    :param tags: List of tuples with tag name and revision id.
420
    """
421
    tags.sort()
422
423
424
def sort_time(branch, tags):
425
    """Sort tags by time inline.
426
427
    :param branch: Branch
428
    :param tags: List of tuples with tag name and revision id.
429
    """
430
    timestamps = {}
431
    for tag, revid in tags:
432
        try:
433
            revobj = branch.repository.get_revision(revid)
434
        except errors.NoSuchRevision:
7143.15.2 by Jelmer Vernooij
Run autopep8.
435
            timestamp = sys.maxsize  # place them at the end
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
436
        else:
437
            timestamp = revobj.timestamp
438
        timestamps[revid] = timestamp
439
    tags.sort(key=lambda x: timestamps[x[1]])
440
441
442
tag_sort_methods = Registry()
443
tag_sort_methods.register("natural", sort_natural,
7143.15.2 by Jelmer Vernooij
Run autopep8.
444
                          'Sort numeric substrings as numbers. (default)')
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
445
tag_sort_methods.register("alpha", sort_alpha, 'Sort tags lexicographically.')
446
tag_sort_methods.register("time", sort_time, 'Sort tags chronologically.')
447
tag_sort_methods.default_key = "natural"