/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to repository.py

Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
17
 
"""An adapter between a Git Repository and a Bazaar Branch"""
18
 
 
19
 
import os
20
 
import time
21
 
 
22
 
import bzrlib
23
 
from bzrlib import (
24
 
    deprecated_graph,
25
 
    errors,
26
 
    inventory,
27
 
    osutils,
28
 
    repository,
29
 
    revision,
30
 
    revisiontree,
31
 
    urlutils,
32
 
    versionedfile,
33
 
    )
34
 
from bzrlib.foreign import (
35
 
        ForeignRevision,
36
 
        )
37
 
from bzrlib.transport import get_transport
38
 
 
39
 
from bzrlib.plugins.git.foreign import (
40
 
    ForeignRepository,
41
 
    versionedfiles,
42
 
    )
43
 
from bzrlib.plugins.git.mapping import default_mapping
44
 
 
45
 
from bzrlib.plugins.git import git
46
 
 
47
 
 
48
 
class GitTags(object):
49
 
 
50
 
    def __init__(self, tags):
51
 
        self._tags = tags
52
 
 
53
 
    def __iter__(self):
54
 
        return iter(self._tags)
55
 
 
56
 
 
57
 
class GitRepository(ForeignRepository):
58
 
    """An adapter to git repositories for bzr."""
59
 
 
60
 
    _serializer = None
61
 
 
62
 
    def __init__(self, gitdir, lockfiles):
63
 
        self.base = gitdir.root_transport.base
64
 
        self.bzrdir = gitdir
65
 
        self.control_files = lockfiles
66
 
        self._git = gitdir._git
67
 
        self.texts = None
68
 
        self.signatures = versionedfiles.VirtualSignatureTexts(self)
69
 
        self.revisions = versionedfiles.VirtualRevisionTexts(self)
70
 
        self._format = GitFormat()
71
 
        self._fallback_repositories = []
72
 
        self.tags = GitTags(self._git.get_tags())
73
 
 
74
 
    def _all_revision_ids(self):
75
 
        if self._git.heads == []:
76
 
            return set()
77
 
        ret = set()
78
 
        skip = 0
79
 
        max_count = 1000
80
 
        cms = None
81
 
        while cms != []:
82
 
            cms = self._git.commits("--all", max_count=max_count, skip=skip)
83
 
            skip += max_count
84
 
            ret.update([self.get_mapping().revision_id_foreign_to_bzr(cm.id) for cm in cms])
85
 
        return ret
86
 
 
87
 
    def is_shared(self):
88
 
        return True
89
 
 
90
 
    def supports_rich_root(self):
91
 
        return False
92
 
 
93
 
    #def get_revision_delta(self, revision_id):
94
 
    #    parent_revid = self.get_revision(revision_id).parent_ids[0]
95
 
    #    diff = self._git.diff(ids.convert_revision_id_bzr_to_git(parent_revid),
96
 
    #                   ids.convert_revision_id_bzr_to_git(revision_id))
97
 
 
98
 
    def get_ancestry(self, revision_id):
99
 
        revision_id = revision.ensure_null(revision_id)
100
 
        ret = []
101
 
        if revision_id != revision.NULL_REVISION:
102
 
            skip = 0
103
 
            max_count = 1000
104
 
            cms = None
105
 
            while cms != []:
106
 
                cms = self._git.commits(self.lookup_git_revid(revision_id, self.get_mapping()), max_count=max_count, skip=skip)
107
 
                skip += max_count
108
 
                ret += [self.get_mapping().revision_id_foreign_to_bzr(cm.id) for cm in cms]
109
 
        return [None] + ret
110
 
 
111
 
    def get_signature_text(self, revision_id):
112
 
        raise errors.NoSuchRevision(self, revision_id)
113
 
 
114
 
    def lookup_revision_id(self, revid):
115
 
        """Lookup a revision id.
116
 
        
117
 
        :param revid: Bazaar revision id.
118
 
        :return: Tuple with git revisionid and mapping.
119
 
        """
120
 
        # Yes, this doesn't really work, but good enough as a stub
121
 
        return osutils.sha(rev_id).hexdigest(), self.get_mapping()
122
 
 
123
 
    def has_signature_for_revision_id(self, revision_id):
124
 
        return False
125
 
 
126
 
    def get_mapping(self):
127
 
        return default_mapping
128
 
 
129
 
    def get_parent_map(self, revision_ids):
130
 
        ret = {}
131
 
        for revid in revision_ids:
132
 
            if revid == revision.NULL_REVISION:
133
 
                ret[revid] = ()
134
 
            else:
135
 
                git_commit_id = self.lookup_git_revid(revid, self.get_mapping())
136
 
                commit = self._git.commit(git_commit_id)
137
 
                ret[revid] = tuple([self.get_mapping().revision_id_foreign_to_bzr(p.id) for p in commit.parents])
138
 
        return ret
139
 
 
140
 
    def lookup_git_revid(self, bzr_revid, mapping):
141
 
        try:
142
 
            return mapping.revision_id_bzr_to_foreign(bzr_revid)
143
 
        except errors.InvalidRevisionId:
144
 
            raise errors.NoSuchRevision(bzr_revid, self)
145
 
 
146
 
    def get_revision(self, revision_id):
147
 
        git_commit_id = self.lookup_git_revid(revision_id, self.get_mapping())
148
 
        commit = self._git.commit(git_commit_id)
149
 
        # print "fetched revision:", git_commit_id
150
 
        revision = self._parse_rev(commit, self.get_mapping())
151
 
        return revision
152
 
 
153
 
    def has_revision(self, revision_id):
154
 
        try:
155
 
            self.get_revision(revision_id)
156
 
        except NoSuchRevision:
157
 
            return False
158
 
        else:
159
 
            return True
160
 
 
161
 
    def get_revisions(self, revisions):
162
 
        return [self.get_revision(r) for r in revisions]
163
 
 
164
 
    @classmethod
165
 
    def _parse_rev(klass, commit, mapping):
166
 
        """Convert a git commit to a bzr revision.
167
 
 
168
 
        :return: a `bzrlib.revision.Revision` object.
169
 
        """
170
 
        if commit is None:
171
 
            raise AssertionError("Commit object can't be None")
172
 
        rev = ForeignRevision(commit.id, mapping, mapping.revision_id_foreign_to_bzr(commit.id))
173
 
        rev.parent_ids = tuple([mapping.revision_id_foreign_to_bzr(p.id) for p in commit.parents])
174
 
        rev.message = commit.message.decode("utf-8", "replace")
175
 
        rev.committer = str(commit.committer).decode("utf-8", "replace")
176
 
        rev.properties['author'] = str(commit.author).decode("utf-8", "replace")
177
 
        rev.timestamp = time.mktime(commit.committed_date)
178
 
        rev.timezone = 0
179
 
        return rev
180
 
 
181
 
    def revision_trees(self, revids):
182
 
        for revid in revids:
183
 
            yield self.revision_tree(revid)
184
 
 
185
 
    def revision_tree(self, revision_id):
186
 
        revision_id = revision.ensure_null(revision_id)
187
 
 
188
 
        if revision_id == revision.NULL_REVISION:
189
 
            inv = inventory.Inventory(root_id=None)
190
 
            inv.revision_id = revision_id
191
 
            return revisiontree.RevisionTree(self, inv, revision_id)
192
 
 
193
 
        return GitRevisionTree(self, revision_id)
194
 
 
195
 
    def get_inventory(self, revision_id):
196
 
        assert revision_id != None
197
 
        return self.revision_tree(revision_id).inventory
198
 
 
199
 
    def set_make_working_trees(self, trees):
200
 
        pass
201
 
 
202
 
 
203
 
def escape_file_id(file_id):
204
 
    return file_id.replace('_', '__').replace(' ', '_s')
205
 
 
206
 
 
207
 
def unescape_file_id(file_id):
208
 
    return file_id.replace("_s", " ").replace("__", "_")
209
 
 
210
 
 
211
 
class GitRevisionTree(revisiontree.RevisionTree):
212
 
 
213
 
    def __init__(self, repository, revision_id):
214
 
        self._repository = repository
215
 
        self.revision_id = revision_id
216
 
        git_id = repository.lookup_git_revid(revision_id, repository.get_mapping())
217
 
        self.tree = repository._git.commit(git_id).tree
218
 
        self._inventory = inventory.Inventory(revision_id=revision_id)
219
 
        self._inventory.root.revision = revision_id
220
 
        self._build_inventory(self.tree, self._inventory.root, "")
221
 
 
222
 
    def get_revision_id(self):
223
 
        return self.revision_id
224
 
 
225
 
    def get_file_text(self, file_id):
226
 
        entry = self._inventory[file_id]
227
 
        if entry.kind == 'directory': return ""
228
 
        return self._repository._git.blob(entry.text_id).data
229
 
 
230
 
    def _build_inventory(self, tree, ie, path):
231
 
        assert isinstance(path, str)
232
 
        for name, mode, hexsha in tree.entries():
233
 
            basename = name.decode("utf-8")
234
 
            if path == "":
235
 
                child_path = name
236
 
            else:
237
 
                child_path = urlutils.join(path, name)
238
 
            file_id = escape_file_id(child_path.encode('utf-8'))
239
 
            if mode[0] == '0':
240
 
                child_ie = inventory.InventoryDirectory(file_id, basename, ie.file_id)
241
 
            elif mode[0] == '1':
242
 
                if mode[1] == '0':
243
 
                    child_ie = inventory.InventoryFile(file_id, basename, ie.file_id)
244
 
                    child_ie.text_sha1 = osutils.sha_string(b.data)
245
 
                elif mode[1] == '2':
246
 
                    child_ie = inventory.InventoryLink(file_id, basename, ie.file_id)
247
 
                    child_ie.text_sha1 = osutils.sha_string("")
248
 
                else:
249
 
                    raise AssertionError(
250
 
                        "Unknown file kind, perms=%r." % (mode,))
251
 
                child_ie.text_id = b.id
252
 
                child_ie.text_size = b.size
253
 
            else:
254
 
                raise AssertionError(
255
 
                    "Unknown blob kind, perms=%r." % (mode,))
256
 
            child_ie.executable = bool(int(mode[3:], 8) & 0111)
257
 
            child_ie.revision = self.revision_id
258
 
            self._inventory.add(child_ie)
259
 
            if mode[0] == '0':
260
 
                self._build_inventory(b, child_ie, child_path)
261
 
 
262
 
 
263
 
class GitFormat(object):
264
 
 
265
 
    supports_tree_reference = False
266
 
 
267
 
    def get_format_description(self):
268
 
        return "Git Repository"