/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
1
# Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
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
17
"""Conversion between refs and Bazaar revision pointers."""
18
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
19
from collections import defaultdict
0.200.1065 by Jelmer Vernooij
Don't peel tags automatically when pushing back.
20
from cStringIO import StringIO
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
21
0.200.873 by Jelmer Vernooij
Add convenience command for accessing virtual git refs.
22
from dulwich.repo import (
23
    RefsContainer,
24
    )
25
26
from bzrlib import (
27
    errors,
0.200.1065 by Jelmer Vernooij
Don't peel tags automatically when pushing back.
28
    trace,
0.200.873 by Jelmer Vernooij
Add convenience command for accessing virtual git refs.
29
    )
30
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
31
is_tag = lambda x: x.startswith("refs/tags/")
32
0.200.873 by Jelmer Vernooij
Add convenience command for accessing virtual git refs.
33
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
34
def extract_tags(refs):
35
    """Extract the tags from a refs dictionary.
36
37
    :param refs: Refs to extract the tags from.
0.200.1060 by Jelmer Vernooij
Return unpeeled tags in extract_tags.
38
    :return: Dictionary mapping tag names to SHA1s of the actual object
39
        and unpeeled object SHA1s.
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
40
    """
41
    ret = {}
0.200.1060 by Jelmer Vernooij
Return unpeeled tags in extract_tags.
42
    for k, v in refs.iteritems():
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
43
        if is_tag(k) and not k.endswith("^{}"):
0.200.1060 by Jelmer Vernooij
Return unpeeled tags in extract_tags.
44
            try:
45
                peeled = refs[k+"^{}"]
46
                unpeeled = v
47
            except KeyError:
48
                peeled = v
49
                unpeeled = None
0.200.1008 by Jelmer Vernooij
Cope with utf8 invalid data.
50
            try:
51
                tagname = ref_to_tag_name(k)
52
            except UnicodeDecodeError:
53
                pass
54
            else:
0.200.1060 by Jelmer Vernooij
Return unpeeled tags in extract_tags.
55
                ret[tagname] = (peeled, unpeeled)
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
56
    return ret
57
58
59
def branch_name_to_ref(name, default=None):
60
    """Map a branch name to a ref.
61
62
    :param name: Branch name
63
    :return: ref string
64
    """
65
    if name is None:
66
        return default
67
    if name == "HEAD":
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
68
        return name
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
69
    if not name.startswith("refs/"):
70
        return "refs/heads/%s" % name
71
    else:
72
        return name
73
74
0.200.874 by Jelmer Vernooij
Support tag refs.
75
def tag_name_to_ref(name):
76
    """Map a tag name to a ref.
77
78
    :param name: Tag name
79
    :return: ref string
80
    """
81
    return "refs/tags/%s" % name
82
83
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
84
def ref_to_branch_name(ref):
85
    """Map a ref to a branch name
86
87
    :param ref: Ref
88
    :return: A branch name
89
    """
0.200.916 by Jelmer Vernooij
Set refs/heads/master if no ref is set yet.
90
    if ref in (None, "HEAD"):
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
91
        return ref
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
92
    if ref.startswith("refs/heads/"):
93
        return ref[len("refs/heads/"):]
0.200.874 by Jelmer Vernooij
Support tag refs.
94
    raise ValueError("unable to map ref %s back to branch name" % ref)
95
96
97
def ref_to_tag_name(ref):
98
    if ref.startswith("refs/tags/"):
0.200.1008 by Jelmer Vernooij
Cope with utf8 invalid data.
99
        return ref[len('refs/tags/'):].decode("utf-8")
0.200.1051 by Jelmer Vernooij
Fix typo.
100
    raise ValueError("unable to map ref %s back to tag name" % ref)
0.200.872 by Jelmer Vernooij
Move refs code to separate module.
101
0.200.873 by Jelmer Vernooij
Add convenience command for accessing virtual git refs.
102
103
class BazaarRefsContainer(RefsContainer):
104
105
    def __init__(self, dir, object_store):
106
        self.dir = dir
107
        self.object_store = object_store
108
109
    def set_symbolic_ref(self, name, other):
110
        if name == "HEAD":
111
            pass # FIXME: Switch default branch
112
        else:
113
            raise NotImplementedError(
114
                "Symbolic references not supported for anything other than "
115
                "HEAD")
116
0.200.874 by Jelmer Vernooij
Support tag refs.
117
    def _get_revid_by_tag_name(self, tag_name):
118
        for branch in self.dir.list_branches():
119
            try:
120
                # FIXME: This is ambiguous!
121
                return branch.tags.lookup_tag(tag_name)
122
            except errors.NoSuchTag:
123
                pass
124
        return None
125
126
    def _get_revid_by_branch_name(self, branch_name):
0.200.873 by Jelmer Vernooij
Add convenience command for accessing virtual git refs.
127
        try:
128
            branch = self.dir.open_branch(branch_name)
129
        except errors.NoColocatedBranchSupport:
0.252.47 by Jelmer Vernooij
Fix handling of HEAD refs.
130
            if branch_name in ("HEAD", "master"):
0.252.45 by Jelmer Vernooij
Finish fetching roundtripped revisions back into bzr.
131
                branch = self.dir.open_branch()
132
            else:
133
                raise
0.200.874 by Jelmer Vernooij
Support tag refs.
134
        return branch.last_revision()
135
136
    def read_loose_ref(self, ref):
137
        try:
138
            branch_name = ref_to_branch_name(ref)
139
        except ValueError:
140
            tag_name = ref_to_tag_name(ref)
141
            revid = self._get_revid_by_tag_name(tag_name)
142
        else:
143
            revid = self._get_revid_by_branch_name(branch_name)
144
        return self.object_store._lookup_revision_sha1(revid)
0.200.873 by Jelmer Vernooij
Add convenience command for accessing virtual git refs.
145
146
    def allkeys(self):
147
        keys = set()
148
        for branch in self.dir.list_branches():
0.200.876 by Jelmer Vernooij
Filter out objects that aren't actually present locally.
149
            repo = branch.repository
150
            if repo.has_revision(branch.last_revision()):
0.252.47 by Jelmer Vernooij
Fix handling of HEAD refs.
151
                ref = branch_name_to_ref(branch.name, "refs/heads/master")
152
                keys.add(ref)
153
                if branch.name is None:
154
                    keys.add("HEAD")
0.200.876 by Jelmer Vernooij
Filter out objects that aren't actually present locally.
155
            for tag_name, revid in branch.tags.get_tag_dict().iteritems():
156
                if repo.has_revision(revid):
157
                    keys.add(tag_name_to_ref(tag_name))
0.200.873 by Jelmer Vernooij
Add convenience command for accessing virtual git refs.
158
        return keys
159
160
    def __delitem__(self, ref):
161
        try:
162
            branch_name = ref_to_branch_name(ref)
163
        except ValueError:
164
            return # FIXME: Cope with tags!
165
        self.dir.destroy_branch(branch_name)
166
167
    def __setitem__(self, ref, sha):
168
        try:
169
            branch_name = ref_to_branch_name(ref)
170
        except ValueError:
171
            # FIXME: Cope with tags!
172
            return
173
        try:
174
            target_branch = self.repo_dir.open_branch(branch_name)
175
        except errors.NotBranchError:
176
            target_branch = self.repo.create_branch(branch_name)
177
178
        rev_id = self.mapping.revision_id_foreign_to_bzr(sha)
179
        target_branch.lock_write()
180
        try:
181
            target_branch.generate_revision_history(rev_id)
182
        finally:
183
            target_branch.unlock()
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
184
185
186
class UnpeelMap(object):
187
    """Unpeel map.
188
189
    Keeps track of the unpeeled object id of tags.
190
    """
191
192
    def __init__(self):
193
        self._map = defaultdict(set)
194
195
    def update(self, m):
196
        for k, v in m.iteritems():
197
            self._map[k].update(v)
198
199
    def load(self, f):
0.200.1146 by Jelmer Vernooij
Avoid doing IO in assert.
200
        firstline = f.readline()
201
        if firstline != "unpeel map version 1\n":
202
            raise AssertionError("invalid format for unpeel map: %r" % firstline)
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
203
        for l in f.readlines():
204
            (k, v) = l.split(":", 1)
205
            self._map[k.strip()].add(v.strip())
206
207
    def save(self, f):
208
        f.write("unpeel map version 1\n")
209
        for k, vs in self._map.iteritems():
210
            for v in vs:
211
                f.write("%s: %s\n" % (k, v))
212
0.200.1065 by Jelmer Vernooij
Don't peel tags automatically when pushing back.
213
    def save_in_repository(self, repository):
214
        f = StringIO()
215
        try:
216
            self.save(f)
217
            f.seek(0)
218
            repository.control_transport.put_file("git-unpeel-map", f)
219
        finally:
220
            f.close()
221
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
222
    def re_unpeel_tag(self, new_git_sha, old_git_sha):
223
        """Re-unpeel tags.
224
225
        Bazaar can't store unpeeled refs so in order to prevent peeling
226
        existing tags when pushing they are "re-peeled" here.
227
        """
0.200.1065 by Jelmer Vernooij
Don't peel tags automatically when pushing back.
228
        if old_git_sha is not None and old_git_sha in self._map[new_git_sha]:
229
            trace.mutter("re-unpeeling %r to %r", new_git_sha, old_git_sha)
0.200.1061 by Jelmer Vernooij
Add support for using unpeel map.
230
            return old_git_sha
231
        return new_git_sha
232
0.200.1065 by Jelmer Vernooij
Don't peel tags automatically when pushing back.
233
    @classmethod
234
    def from_repository(cls, repository):
235
        """Load the unpeel map for a repository.
236
        """
237
        m = UnpeelMap()
238
        try:
239
            m.load(repository.control_transport.get("git-unpeel-map"))
240
        except errors.NoSuchFile:
241
            pass
242
        return m