~bzr-pqm/bzr/bzr.dev

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