/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
1
# Copyright (C) 2007 Canonical Ltd
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
25
# NOTE: I was going to call this tags.py, but vim seems to think all files
26
# called tags* are ctags files... mbp 20070220.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
27
2220.2.14 by mbp at sourcefrog
cleanup
28
2220.2.28 by Martin Pool
Integrate tags with Branch6:
29
from warnings import warn
30
3224.5.20 by Andrew Bennetts
Remove or lazyify a couple more imports.
31
from bzrlib.lazy_import import lazy_import
32
lazy_import(globals(), """
33
from bzrlib.util import bencode
34
""")
35
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
36
from bzrlib import (
37
    errors,
2220.2.27 by Martin Pool
Start adding tags to Branch6
38
    trace,
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
39
    )
40
41
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
42
class _Tags(object):
2220.2.28 by Martin Pool
Integrate tags with Branch6:
43
2220.2.14 by mbp at sourcefrog
cleanup
44
    def __init__(self, branch):
45
        self.branch = branch
46
2220.2.42 by Martin Pool
Tag command refuses to replace existing tags unless you force it.
47
    def has_tag(self, tag_name):
48
        return self.get_tag_dict().has_key(tag_name)
49
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
50
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
51
class DisabledTags(_Tags):
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
52
    """Tag storage that refuses to store anything.
53
54
    This is used by older formats that can't store tags.
55
    """
56
57
    def _not_supported(self, *a, **k):
2220.2.14 by mbp at sourcefrog
cleanup
58
        raise errors.TagsNotSupported(self.branch)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
59
60
    set_tag = _not_supported
61
    get_tag_dict = _not_supported
62
    _set_tag_dict = _not_supported
63
    lookup_tag = _not_supported
2220.2.21 by Martin Pool
Add tag --delete command and implementation
64
    delete_tag = _not_supported
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
65
2810.1.1 by Martin Pool
merge push|pull --overwrite and tweak
66
    def merge_to(self, to_tags, overwrite=False):
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
67
        # we never have anything to copy
68
        pass
69
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
70
    def rename_revisions(self, rename_map):
71
        # No tags, so nothing to rename
72
        pass
73
2831.8.1 by James Westby
Fix log against smart server branches that don't support tags. (#140615)
74
    def get_reverse_tag_dict(self):
75
        # There aren't any tags, so the reverse mapping is empty.
76
        return {}
77
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
78
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
79
class BasicTags(_Tags):
2220.2.14 by mbp at sourcefrog
cleanup
80
    """Tag storage in an unversioned branch control file.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
81
    """
82
83
    def set_tag(self, tag_name, tag_target):
2220.2.14 by mbp at sourcefrog
cleanup
84
        """Add a tag definition to the branch.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
85
86
        Behaviour if the tag is already present is not defined (yet).
87
        """
88
        # all done with a write lock held, so this looks atomic
2220.2.14 by mbp at sourcefrog
cleanup
89
        self.branch.lock_write()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
90
        try:
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
91
            master = self.branch.get_master_branch()
92
            if master is not None:
93
                master.tags.set_tag(tag_name, tag_target)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
94
            td = self.get_tag_dict()
95
            td[tag_name] = tag_target
96
            self._set_tag_dict(td)
97
        finally:
2220.2.14 by mbp at sourcefrog
cleanup
98
            self.branch.unlock()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
99
100
    def lookup_tag(self, tag_name):
101
        """Return the referent string of a tag"""
102
        td = self.get_tag_dict()
103
        try:
104
            return td[tag_name]
105
        except KeyError:
106
            raise errors.NoSuchTag(tag_name)
107
108
    def get_tag_dict(self):
2220.2.14 by mbp at sourcefrog
cleanup
109
        self.branch.lock_read()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
110
        try:
2220.2.27 by Martin Pool
Start adding tags to Branch6
111
            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.
112
                tag_content = self.branch._get_tags_bytes()
2220.2.27 by Martin Pool
Start adding tags to Branch6
113
            except errors.NoSuchFile, e:
2220.2.28 by Martin Pool
Integrate tags with Branch6:
114
                # ugly, but only abentley should see this :)
115
                trace.warning('No branch/tags file in %s.  '
2220.2.27 by Martin Pool
Start adding tags to Branch6
116
                     'This branch was probably created by bzr 0.15pre.  '
2220.2.28 by Martin Pool
Integrate tags with Branch6:
117
                     'Create an empty file to silence this message.'
118
                     % (self.branch, ))
2220.2.27 by Martin Pool
Start adding tags to Branch6
119
                return {}
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
120
            return self._deserialize_tag_dict(tag_content)
121
        finally:
2220.2.14 by mbp at sourcefrog
cleanup
122
            self.branch.unlock()
2388.1.11 by Alexander Belchenko
changes after John's review
123
2388.1.1 by Erik Bagfors
created reverse_tag_dict in tags.py
124
    def get_reverse_tag_dict(self):
125
        """Returns a dict with revisions as keys
126
           and a list of tags for that revision as value"""
127
        d = self.get_tag_dict()
128
        rev = {}
129
        for key in d:
130
            try:
131
                rev[d[key]].append(key)
132
            except KeyError:
133
                rev[d[key]] = [key]
134
        return rev
135
2220.2.21 by Martin Pool
Add tag --delete command and implementation
136
    def delete_tag(self, tag_name):
137
        """Delete a tag definition.
138
        """
139
        self.branch.lock_write()
140
        try:
141
            d = self.get_tag_dict()
142
            try:
143
                del d[tag_name]
144
            except KeyError:
145
                raise errors.NoSuchTag(tag_name)
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
146
            master = self.branch.get_master_branch()
147
            if master is not None:
148
                try:
149
                    master.tags.delete_tag(tag_name)
150
                except errors.NoSuchTag:
151
                    pass
2220.2.21 by Martin Pool
Add tag --delete command and implementation
152
            self._set_tag_dict(d)
153
        finally:
154
            self.branch.unlock()
155
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
156
    def _set_tag_dict(self, new_dict):
157
        """Replace all tag definitions
158
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.
159
        WARNING: Calling this on an unlocked branch will lock it, and will
160
        replace the tags without warning on conflicts.
161
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
162
        :param new_dict: Dictionary from tag name to target.
163
        """
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.
164
        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
165
166
    def _serialize_tag_dict(self, tag_dict):
2220.2.21 by Martin Pool
Add tag --delete command and implementation
167
        td = dict((k.encode('utf-8'), v)
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
168
                  for k,v in tag_dict.items())
2220.2.21 by Martin Pool
Add tag --delete command and implementation
169
        return bencode.bencode(td)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
170
171
    def _deserialize_tag_dict(self, tag_content):
172
        """Convert the tag file into a dictionary of tags"""
2220.2.28 by Martin Pool
Integrate tags with Branch6:
173
        # 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
174
        # is an empty dictionary
175
        if tag_content == '':
176
            return {}
177
        try:
2220.2.21 by Martin Pool
Add tag --delete command and implementation
178
            r = {}
179
            for k, v in bencode.bdecode(tag_content).items():
180
                r[k.decode('utf-8')] = v
181
            return r
182
        except ValueError, e:
183
            raise ValueError("failed to deserialize tag dictionary %r: %s"
2220.2.32 by Martin Pool
Slightly smarter tag merge
184
                % (tag_content, e))
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
185
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
186
    def merge_to(self, to_tags, overwrite=False):
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
187
        """Copy tags between repositories if necessary and possible.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
188
189
        This method has common command-line behaviour about handling
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
190
        error cases.
191
2220.2.32 by Martin Pool
Slightly smarter tag merge
192
        All new definitions are copied across, except that tags that already
193
        exist keep their existing definitions.
194
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
195
        :param to_tags: Branch to receive these tags
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
196
        :param overwrite: Overwrite conflicting tags in the target branch
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
197
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
198
        :returns: A list 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.
199
            (tagname, source_target, dest_target), or None if no copying was
200
            done.
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
201
        """
202
        if self.branch == to_tags.branch:
203
            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.
204
        if not self.branch.supports_tags():
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
205
            # obviously nothing to copy
206
            return
2220.2.32 by Martin Pool
Slightly smarter tag merge
207
        source_dict = self.get_tag_dict()
208
        if not source_dict:
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
209
            # no tags in the source, and we don't want to clobber anything
210
            # that's in the destination
211
            return
212
        to_tags.branch.lock_write()
213
        try:
2220.2.32 by Martin Pool
Slightly smarter tag merge
214
            dest_dict = to_tags.get_tag_dict()
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
215
            result, conflicts = self._reconcile_tags(source_dict, dest_dict,
216
                                                     overwrite)
2220.2.32 by Martin Pool
Slightly smarter tag merge
217
            if result != dest_dict:
218
                to_tags._set_tag_dict(result)
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
219
        finally:
220
            to_tags.branch.unlock()
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
221
        return conflicts
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
222
4325.2.1 by Jelmer Vernooij
Add Tags.rename_revisions().
223
    def rename_revisions(self, rename_map):
224
        """Rename revisions in this tags dictionary.
225
        
226
        :param rename_map: Dictionary mapping old revids to new revids
227
        """
228
        reverse_tags = self.get_reverse_tag_dict()
229
        for revid, names in reverse_tags.iteritems():
230
            if revid in rename_map:
231
                for name in names:
232
                    self.set_tag(name, rename_map[revid])
233
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
234
    def _reconcile_tags(self, source_dict, dest_dict, overwrite):
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
235
        """Do a two-way merge of two tag dictionaries.
236
237
        only in source => source value
238
        only in destination => destination value
239
        same definitions => that
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
240
        different definitions => if overwrite is False, keep destination
241
            value and give a warning, otherwise use the source value
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
242
243
        :returns: (result_dict,
244
            [(conflicting_tag, source_target, dest_target)])
245
        """
246
        conflicts = []
247
        result = dict(dest_dict) # copy
248
        for name, target in source_dict.items():
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
249
            if name not in result or overwrite:
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
250
                result[name] = target
251
            elif result[name] == target:
252
                pass
253
            else:
254
                conflicts.append((name, target, result[name]))
255
        return result, conflicts
2220.2.32 by Martin Pool
Slightly smarter tag merge
256
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
257
258
def _merge_tags_if_possible(from_branch, to_branch):
259
    from_branch.tags.merge_to(to_branch.tags)