/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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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
    def supports_tags(self):
61
        return False
62
63
    set_tag = _not_supported
64
    get_tag_dict = _not_supported
65
    _set_tag_dict = _not_supported
66
    lookup_tag = _not_supported
2220.2.21 by Martin Pool
Add tag --delete command and implementation
67
    delete_tag = _not_supported
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
68
2810.1.1 by Martin Pool
merge push|pull --overwrite and tweak
69
    def merge_to(self, to_tags, overwrite=False):
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
70
        # we never have anything to copy
71
        pass
72
2831.8.1 by James Westby
Fix log against smart server branches that don't support tags. (#140615)
73
    def get_reverse_tag_dict(self):
74
        # There aren't any tags, so the reverse mapping is empty.
75
        return {}
76
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
77
2220.2.20 by Martin Pool
Tag methods now available through Branch.tags.add_tag, etc
78
class BasicTags(_Tags):
2220.2.14 by mbp at sourcefrog
cleanup
79
    """Tag storage in an unversioned branch control file.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
80
    """
81
82
    def supports_tags(self):
83
        return True
84
85
    def set_tag(self, tag_name, tag_target):
2220.2.14 by mbp at sourcefrog
cleanup
86
        """Add a tag definition to the branch.
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
87
88
        Behaviour if the tag is already present is not defined (yet).
89
        """
90
        # all done with a write lock held, so this looks atomic
2220.2.14 by mbp at sourcefrog
cleanup
91
        self.branch.lock_write()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
92
        try:
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
93
            master = self.branch.get_master_branch()
94
            if master is not None:
95
                master.tags.set_tag(tag_name, tag_target)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
96
            td = self.get_tag_dict()
97
            td[tag_name] = tag_target
98
            self._set_tag_dict(td)
99
        finally:
2220.2.14 by mbp at sourcefrog
cleanup
100
            self.branch.unlock()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
101
102
    def lookup_tag(self, tag_name):
103
        """Return the referent string of a tag"""
104
        td = self.get_tag_dict()
105
        try:
106
            return td[tag_name]
107
        except KeyError:
108
            raise errors.NoSuchTag(tag_name)
109
110
    def get_tag_dict(self):
2220.2.14 by mbp at sourcefrog
cleanup
111
        self.branch.lock_read()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
112
        try:
2220.2.27 by Martin Pool
Start adding tags to Branch6
113
            try:
114
                tag_content = self.branch._transport.get_bytes('tags')
115
            except errors.NoSuchFile, e:
2220.2.28 by Martin Pool
Integrate tags with Branch6:
116
                # ugly, but only abentley should see this :)
117
                trace.warning('No branch/tags file in %s.  '
2220.2.27 by Martin Pool
Start adding tags to Branch6
118
                     'This branch was probably created by bzr 0.15pre.  '
2220.2.28 by Martin Pool
Integrate tags with Branch6:
119
                     'Create an empty file to silence this message.'
120
                     % (self.branch, ))
2220.2.27 by Martin Pool
Start adding tags to Branch6
121
                return {}
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
122
            return self._deserialize_tag_dict(tag_content)
123
        finally:
2220.2.14 by mbp at sourcefrog
cleanup
124
            self.branch.unlock()
2388.1.11 by Alexander Belchenko
changes after John's review
125
2388.1.1 by Erik Bagfors
created reverse_tag_dict in tags.py
126
    def get_reverse_tag_dict(self):
127
        """Returns a dict with revisions as keys
128
           and a list of tags for that revision as value"""
129
        d = self.get_tag_dict()
130
        rev = {}
131
        for key in d:
132
            try:
133
                rev[d[key]].append(key)
134
            except KeyError:
135
                rev[d[key]] = [key]
136
        return rev
137
2220.2.21 by Martin Pool
Add tag --delete command and implementation
138
    def delete_tag(self, tag_name):
139
        """Delete a tag definition.
140
        """
141
        self.branch.lock_write()
142
        try:
143
            d = self.get_tag_dict()
144
            try:
145
                del d[tag_name]
146
            except KeyError:
147
                raise errors.NoSuchTag(tag_name)
2805.5.2 by Martin Pool
Setting and deleting tags should also update the master branch, if any.
148
            master = self.branch.get_master_branch()
149
            if master is not None:
150
                try:
151
                    master.tags.delete_tag(tag_name)
152
                except errors.NoSuchTag:
153
                    pass
2220.2.21 by Martin Pool
Add tag --delete command and implementation
154
            self._set_tag_dict(d)
155
        finally:
156
            self.branch.unlock()
157
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
158
    def _set_tag_dict(self, new_dict):
159
        """Replace all tag definitions
160
161
        :param new_dict: Dictionary from tag name to target.
162
        """
2805.4.1 by Martin Pool
Old fix from Alexander: set_tag_dict should lock the branch
163
        self.branch.lock_write()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
164
        try:
2220.2.16 by mbp at sourcefrog
Make Branch._transport be the branch's control file transport
165
            self.branch._transport.put_bytes('tags',
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
166
                self._serialize_tag_dict(new_dict))
167
        finally:
2220.2.14 by mbp at sourcefrog
cleanup
168
            self.branch.unlock()
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
169
170
    def _serialize_tag_dict(self, tag_dict):
2220.2.21 by Martin Pool
Add tag --delete command and implementation
171
        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.
172
                  for k,v in tag_dict.items())
2220.2.21 by Martin Pool
Add tag --delete command and implementation
173
        return bencode.bencode(td)
2220.2.11 by mbp at sourcefrog
Get tag tests working again, stored in the Branch
174
175
    def _deserialize_tag_dict(self, tag_content):
176
        """Convert the tag file into a dictionary of tags"""
2220.2.28 by Martin Pool
Integrate tags with Branch6:
177
        # 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
178
        # is an empty dictionary
179
        if tag_content == '':
180
            return {}
181
        try:
2220.2.21 by Martin Pool
Add tag --delete command and implementation
182
            r = {}
183
            for k, v in bencode.bdecode(tag_content).items():
184
                r[k.decode('utf-8')] = v
185
            return r
186
        except ValueError, e:
187
            raise ValueError("failed to deserialize tag dictionary %r: %s"
2220.2.32 by Martin Pool
Slightly smarter tag merge
188
                % (tag_content, e))
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
189
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
190
    def merge_to(self, to_tags, overwrite=False):
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
191
        """Copy tags between repositories if necessary and possible.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
192
193
        This method has common command-line behaviour about handling
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
194
        error cases.
195
2220.2.32 by Martin Pool
Slightly smarter tag merge
196
        All new definitions are copied across, except that tags that already
197
        exist keep their existing definitions.
198
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
199
        :param to_tags: Branch to receive these tags
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
200
        :param overwrite: Overwrite conflicting tags in the target branch
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
201
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
202
        :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.
203
            (tagname, source_target, dest_target), or None if no copying was
204
            done.
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
205
        """
206
        if self.branch == to_tags.branch:
207
            return
208
        if not self.supports_tags():
209
            # obviously nothing to copy
210
            return
2220.2.32 by Martin Pool
Slightly smarter tag merge
211
        source_dict = self.get_tag_dict()
212
        if not source_dict:
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
213
            # no tags in the source, and we don't want to clobber anything
214
            # that's in the destination
215
            return
216
        to_tags.branch.lock_write()
217
        try:
2220.2.32 by Martin Pool
Slightly smarter tag merge
218
            dest_dict = to_tags.get_tag_dict()
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
219
            result, conflicts = self._reconcile_tags(source_dict, dest_dict,
220
                                                     overwrite)
2220.2.32 by Martin Pool
Slightly smarter tag merge
221
            if result != dest_dict:
222
                to_tags._set_tag_dict(result)
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
223
        finally:
224
            to_tags.branch.unlock()
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
225
        return conflicts
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
226
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
227
    def _reconcile_tags(self, source_dict, dest_dict, overwrite):
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
228
        """Do a two-way merge of two tag dictionaries.
229
230
        only in source => source value
231
        only in destination => destination value
232
        same definitions => that
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
233
        different definitions => if overwrite is False, keep destination
234
            value and give a warning, otherwise use the source value
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
235
236
        :returns: (result_dict,
237
            [(conflicting_tag, source_target, dest_target)])
238
        """
239
        conflicts = []
240
        result = dict(dest_dict) # copy
241
        for name, target in source_dict.items():
2804.3.1 by Lukáš Lalinský
Overwrite conflicting tags by push|pull --overwrite.
242
            if name not in result or overwrite:
2220.2.33 by Martin Pool
Start support for flagging tag conflicts
243
                result[name] = target
244
            elif result[name] == target:
245
                pass
246
            else:
247
                conflicts.append((name, target, result[name]))
248
        return result, conflicts
2220.2.32 by Martin Pool
Slightly smarter tag merge
249
2220.2.30 by Martin Pool
split out tag-merging code and add some tests
250
251
def _merge_tags_if_possible(from_branch, to_branch):
252
    from_branch.tags.merge_to(to_branch.tags)