/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
7260.3.4 by Jelmer Vernooij
Use defaultdict.
25
from collections import defaultdict
7479.2.1 by Jelmer Vernooij
Drop python2 support.
26
import contextlib
7489.3.3 by Jelmer Vernooij
Move bzr-specific tag code to breezy.bzr.tag.
27
import itertools
28
import re
29
import sys
7260.3.4 by Jelmer Vernooij
Use defaultdict.
30
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
31
# NOTE: I was going to call this tags.py, but vim seems to think all files
32
# called tags* are ctags files... mbp 20070220.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
33
7489.3.1 by Jelmer Vernooij
Add InterTags object.
34
from .inter import InterObject
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
35
from .registry import Registry
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
36
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
37
from . import (
7413.8.12 by Jelmer Vernooij
Fix hg plugin.
38
    errors,
39
    )
40
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
41
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
42
def _reconcile_tags(source_dict, dest_dict, overwrite, selector):
7260.3.3 by Jelmer Vernooij
Add merge_to support.
43
    """Do a two-way merge of two tag dictionaries.
44
45
    * only in source => source value
46
    * only in destination => destination value
47
    * same definitions => that
48
    * different definitions => if overwrite is False, keep destination
7260.3.4 by Jelmer Vernooij
Use defaultdict.
49
      value and add to conflict list, otherwise use the source value
7260.3.3 by Jelmer Vernooij
Add merge_to support.
50
51
    :returns: (result_dict, updates,
52
        [(conflicting_tag, source_target, dest_target)])
53
    """
54
    conflicts = []
55
    updates = {}
56
    result = dict(dest_dict)  # copy
57
    for name, target in source_dict.items():
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
58
        if selector and not selector(name):
59
            continue
7260.3.3 by Jelmer Vernooij
Add merge_to support.
60
        if result.get(name) == target:
61
            pass
62
        elif name not in result or overwrite:
63
            updates[name] = target
64
            result[name] = target
65
        else:
66
            conflicts.append((name, target, result[name]))
67
    return result, updates, conflicts
68
69
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
70
class Tags(object):
2220.2.28 by Martin Pool
Integrate tags with Branch6:
71
2220.2.14 by mbp at sourcefrog
cleanup
72
    def __init__(self, branch):
73
        self.branch = branch
74
6123.4.1 by Jelmer Vernooij
Add stubs.
75
    def get_tag_dict(self):
76
        """Return a dictionary mapping tags to revision ids.
77
        """
78
        raise NotImplementedError(self.get_tag_dict)
79
80
    def get_reverse_tag_dict(self):
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
81
        """Returns a dict with revisions as keys
82
           and a list of tags for that revision as value"""
83
        d = self.get_tag_dict()
84
        rev = defaultdict(set)
85
        for key in d:
86
            rev[d[key]].add(key)
87
        return rev
6123.4.1 by Jelmer Vernooij
Add stubs.
88
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
89
    def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None):
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
90
        """Copy tags between repositories if necessary and possible.
91
92
        This method has common command-line behaviour about handling
93
        error cases.
94
95
        All new definitions are copied across, except that tags that already
96
        exist keep their existing definitions.
97
98
        :param to_tags: Branch to receive these tags
99
        :param overwrite: Overwrite conflicting tags in the target branch
6123.4.1 by Jelmer Vernooij
Add stubs.
100
        :param ignore_master: Do not modify the tags in the target's master
101
            branch (if any).  Default is false (so the master will be updated).
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
102
103
        :returns: Tuple with tag_updates and tag_conflicts.
104
            tag_updates is a dictionary with new tags, None is used for
105
            removed tags
106
            tag_conflicts is a set of tags that conflicted, each of which is
107
            (tagname, source_target, dest_target), or None if no copying was
108
            done.
6123.4.1 by Jelmer Vernooij
Add stubs.
109
        """
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
110
        intertags = InterTags.get(self, to_tags)
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
111
        return intertags.merge(
112
            overwrite=overwrite, ignore_master=ignore_master,
113
            selector=selector)
6123.4.1 by Jelmer Vernooij
Add stubs.
114
115
    def set_tag(self, tag_name, revision):
116
        """Set a tag.
117
118
        :param tag_name: Tag name
119
        :param revision: Revision id
6123.4.2 by Jelmer Vernooij
Tags containers can indicate whether they support ghost tags.
120
        :raise GhostTagsNotSupported: if revision is not present in
121
            the branch repository
6123.4.1 by Jelmer Vernooij
Add stubs.
122
        """
123
        raise NotImplementedError(self.set_tag)
124
125
    def lookup_tag(self, tag_name):
126
        """Look up a tag.
127
128
        :param tag_name: Tag to look up
129
        :raise NoSuchTag: Raised when tag does not exist
130
        :return: Matching revision id
131
        """
132
        raise NotImplementedError(self.lookup_tag)
133
134
    def delete_tag(self, tag_name):
135
        """Delete a tag.
136
137
        :param tag_name: Tag to delete
138
        :raise NoSuchTag: Raised when tag does not exist
139
        """
140
        raise NotImplementedError(self.delete_tag)
141
142
    def rename_revisions(self, rename_map):
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
143
        """Rename revisions in this tags dictionary.
6123.4.1 by Jelmer Vernooij
Add stubs.
144
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
145
        :param rename_map: Dictionary mapping old revids to new revids
6123.4.1 by Jelmer Vernooij
Add stubs.
146
        """
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
147
        reverse_tags = self.get_reverse_tag_dict()
148
        for revid, names in reverse_tags.items():
149
            if revid in rename_map:
150
                for name in names:
151
                    self.set_tag(name, rename_map[revid])
6123.4.1 by Jelmer Vernooij
Add stubs.
152
2220.2.42 by Martin Pool
Tag command refuses to replace existing tags unless you force it.
153
    def has_tag(self, tag_name):
6619.3.1 by Jelmer Vernooij
Apply 2to3 has_key fix.
154
        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.
155
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
156
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
157
class DisabledTags(Tags):
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
158
    """Tag storage that refuses to store anything.
159
160
    This is used by older formats that can't store tags.
161
    """
162
163
    def _not_supported(self, *a, **k):
2220.2.14 by mbp at sourcefrog
cleanup
164
        raise errors.TagsNotSupported(self.branch)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
165
166
    set_tag = _not_supported
167
    get_tag_dict = _not_supported
168
    _set_tag_dict = _not_supported
169
    lookup_tag = _not_supported
2220.2.21 by Martin Pool
Add tag --delete command and implementation
170
    delete_tag = _not_supported
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
171
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
172
    def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None):
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
173
        # we never have anything to copy
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
174
        return {}, []
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
175
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
176
    def rename_revisions(self, rename_map):
177
        # No tags, so nothing to rename
178
        pass
179
2831.8.1 by James Westby
Fix log against smart server branches that don't support tags. (#140615)
180
    def get_reverse_tag_dict(self):
181
        # There aren't any tags, so the reverse mapping is empty.
182
        return {}
183
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
184
7489.3.1 by Jelmer Vernooij
Add InterTags object.
185
class InterTags(InterObject):
186
    """Operations between sets of tags.
187
    """
188
189
    _optimisers = []
190
    """The available optimised InterTags types."""
191
192
    @classmethod
193
    def is_compatible(klass, source, target):
194
        # This is the default implementation
195
        return True
196
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
197
    def merge(self, overwrite=False, ignore_master=False, selector=None):
7489.3.1 by Jelmer Vernooij
Add InterTags object.
198
        """Copy tags between repositories if necessary and possible.
199
200
        This method has common command-line behaviour about handling
201
        error cases.
202
203
        All new definitions are copied across, except that tags that already
204
        exist keep their existing definitions.
205
206
        :param to_tags: Branch to receive these tags
207
        :param overwrite: Overwrite conflicting tags in the target branch
208
        :param ignore_master: Do not modify the tags in the target's master
209
            branch (if any).  Default is false (so the master will be updated).
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
210
        :param selector: Callback that determines whether a tag should be
211
            copied. It should take a tag name and as argument and return a
212
            boolean.
7489.3.1 by Jelmer Vernooij
Add InterTags object.
213
214
        :returns: Tuple with tag_updates and tag_conflicts.
215
            tag_updates is a dictionary with new tags, None is used for
216
            removed tags
217
            tag_conflicts is a set of tags that conflicted, each of which is
218
            (tagname, source_target, dest_target), or None if no copying was
219
            done.
220
        """
7479.2.1 by Jelmer Vernooij
Drop python2 support.
221
        with contextlib.ExitStack() as stack:
7489.3.1 by Jelmer Vernooij
Add InterTags object.
222
            if self.source.branch == self.target.branch:
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
223
                return {}, []
7489.3.1 by Jelmer Vernooij
Add InterTags object.
224
            if not self.source.branch.supports_tags():
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
225
                # obviously nothing to copy
226
                return {}, []
7489.3.1 by Jelmer Vernooij
Add InterTags object.
227
            source_dict = self.source.get_tag_dict()
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
228
            if not source_dict:
229
                # no tags in the source, and we don't want to clobber anything
230
                # that's in the destination
231
                return {}, []
232
            # We merge_to both master and child individually.
233
            #
234
            # It's possible for master and child to have differing sets of
235
            # tags, in which case it's possible to have different sets of
236
            # conflicts.  We report the union of both conflict sets.  In
237
            # that case it's likely the child and master have accepted
238
            # different tags from the source, which may be a surprising result, but
239
            # the best we can do in the circumstances.
240
            #
241
            # Ideally we'd improve this API to report the different conflicts
242
            # more clearly to the caller, but we don't want to break plugins
243
            # such as bzr-builddeb that use this API.
7489.3.1 by Jelmer Vernooij
Add InterTags object.
244
            stack.enter_context(self.target.branch.lock_write())
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
245
            if ignore_master:
246
                master = None
247
            else:
7489.3.1 by Jelmer Vernooij
Add InterTags object.
248
                master = self.target.branch.get_master_branch()
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
249
            if master is not None:
250
                stack.enter_context(master.lock_write())
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
251
            updates, conflicts = self._merge_to(
252
                self.target, source_dict, overwrite, selector=selector)
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
253
            if master is not None:
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
254
                extra_updates, extra_conflicts = self._merge_to(
255
                    master.tags, source_dict, overwrite, selector=selector)
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
256
                updates.update(extra_updates)
257
                conflicts += extra_conflicts
258
            # We use set() to remove any duplicate conflicts from the master
259
            # branch.
260
            return updates, set(conflicts)
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
261
7489.3.1 by Jelmer Vernooij
Add InterTags object.
262
    @classmethod
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
263
    def _merge_to(cls, to_tags, source_dict, overwrite, selector):
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
264
        dest_dict = to_tags.get_tag_dict()
7260.3.3 by Jelmer Vernooij
Add merge_to support.
265
        result, updates, conflicts = _reconcile_tags(
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
266
            source_dict, dest_dict, overwrite, selector)
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
267
        if result != dest_dict:
268
            to_tags._set_tag_dict(result)
6112.4.1 by Jelmer Vernooij
Show how many tags have been updated in bzr pull.
269
        return updates, conflicts
5050.53.1 by Andrew Bennetts
Tags.merge_to now updates the master branch as well, if any.
270
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
271
7489.3.2 by Jelmer Vernooij
Use InterTags in anger.
272
class MemoryTags(Tags):
7260.3.2 by Jelmer Vernooij
Add a MemoryTag object.
273
274
    def __init__(self, tag_dict):
275
        self._tag_dict = tag_dict
276
277
    def get_tag_dict(self):
278
        return self._tag_dict
279
280
    def lookup_tag(self, tag_name):
281
        """Return the referent string of a tag"""
282
        td = self.get_tag_dict()
283
        try:
284
            return td[tag_name]
285
        except KeyError:
286
            raise errors.NoSuchTag(tag_name)
287
288
    def set_tag(self, name, revid):
289
        self._tag_dict[name] = revid
290
291
    def delete_tag(self, name):
292
        try:
293
            del self._tag_dict[name]
294
        except KeyError:
295
            raise errors.NoSuchTag(name)
296
297
    def rename_revisions(self, revid_map):
298
        self._tag_dict = {
299
            name: revid_map.get(revid, revid)
300
            for name, revid in self._tag_dict.items()}
301
7260.3.3 by Jelmer Vernooij
Add merge_to support.
302
    def _set_tag_dict(self, result):
303
        self._tag_dict = dict(result.items())
304
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
305
    def merge_to(self, to_tags, overwrite=False, ignore_master=False, selector=None):
7260.3.3 by Jelmer Vernooij
Add merge_to support.
306
        source_dict = self.get_tag_dict()
307
        dest_dict = to_tags.get_tag_dict()
308
        result, updates, conflicts = _reconcile_tags(
7489.4.1 by Jelmer Vernooij
Add tag selecting callback.
309
            source_dict, dest_dict, overwrite, selector)
7260.3.3 by Jelmer Vernooij
Add merge_to support.
310
        if result != dest_dict:
311
            to_tags._set_tag_dict(result)
312
        return updates, conflicts
313
7260.3.2 by Jelmer Vernooij
Add a MemoryTag object.
314
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
315
def sort_natural(branch, tags):
316
    """Sort tags, with numeric substrings as numbers.
317
318
    :param branch: Branch
319
    :param tags: List of tuples with tag name and revision id.
320
    """
321
    def natural_sort_key(tag):
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
322
        return [f(s) for f, s in
7479.2.1 by Jelmer Vernooij
Drop python2 support.
323
                zip(itertools.cycle((str.lower, int)),
7143.15.2 by Jelmer Vernooij
Run autopep8.
324
                    re.split('([0-9]+)', tag[0]))]
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
325
    tags.sort(key=natural_sort_key)
326
327
328
def sort_alpha(branch, tags):
329
    """Sort tags lexicographically, in place.
330
331
    :param branch: Branch
332
    :param tags: List of tuples with tag name and revision id.
333
    """
334
    tags.sort()
335
336
337
def sort_time(branch, tags):
338
    """Sort tags by time inline.
339
340
    :param branch: Branch
341
    :param tags: List of tuples with tag name and revision id.
342
    """
343
    timestamps = {}
344
    for tag, revid in tags:
345
        try:
346
            revobj = branch.repository.get_revision(revid)
347
        except errors.NoSuchRevision:
7143.15.2 by Jelmer Vernooij
Run autopep8.
348
            timestamp = sys.maxsize  # place them at the end
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
349
        else:
350
            timestamp = revobj.timestamp
351
        timestamps[revid] = timestamp
352
    tags.sort(key=lambda x: timestamps[x[1]])
353
354
355
tag_sort_methods = Registry()
356
tag_sort_methods.register("natural", sort_natural,
7143.15.2 by Jelmer Vernooij
Run autopep8.
357
                          'Sort numeric substrings as numbers. (default)')
5582.2.1 by Jelmer Vernooij
support extending --sort argument to 'bzr tags'.
358
tag_sort_methods.register("alpha", sort_alpha, 'Sort tags lexicographically.')
359
tag_sort_methods.register("time", sort_time, 'Sort tags chronologically.')
360
tag_sort_methods.default_key = "natural"
7489.3.1 by Jelmer Vernooij
Add InterTags object.
361
362
363
InterTags.register_optimiser(InterTags)