/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.252 by Jelmer Vernooij
Clarify history, copyright.
1
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
0.200.228 by Jelmer Vernooij
Split out map.
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
"""Map from Git sha's to Bazaar objects."""
18
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
19
from dulwich.objects import (
20
    Blob,
0.200.586 by Jelmer Vernooij
Fix issues pointed out by pyflakes.
21
    sha_to_hex,
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
22
    )
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
23
from dulwich.object_store import (
0.200.457 by Jelmer Vernooij
Use BaseObjectStore.
24
    BaseObjectStore,
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
25
    )
0.200.249 by Jelmer Vernooij
Implement Tree.
26
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
27
from bzrlib import (
0.200.440 by Jelmer Vernooij
Remove silly mapping of timezones; dulwich uses offsets now as well.
28
    debug,
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
29
    errors,
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
30
    trace,
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
31
    ui,
32
    )
0.200.541 by Jelmer Vernooij
Cope with NULL_REVISION.
33
from bzrlib.revision import (
34
    NULL_REVISION,
35
    )
0.200.228 by Jelmer Vernooij
Split out map.
36
0.200.229 by Jelmer Vernooij
More work on converter.
37
from bzrlib.plugins.git.mapping import (
0.200.463 by Jelmer Vernooij
Support remote dpush (except for references).
38
    default_mapping,
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
39
    directory_to_tree,
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
40
    extract_unusual_modes,
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
41
    mapping_registry,
0.200.229 by Jelmer Vernooij
More work on converter.
42
    )
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
43
from bzrlib.plugins.git.shamap import (
44
    SqliteGitShaMap,
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
45
    TdbGitShaMap,
0.200.231 by Jelmer Vernooij
Partially fix pull.
46
    )
47
0.200.228 by Jelmer Vernooij
Split out map.
48
0.200.452 by Jelmer Vernooij
Rename converter -> object_store, provide utility function for getting ObjectStore's.
49
def get_object_store(repo, mapping=None):
50
    git = getattr(repo, "_git", None)
51
    if git is not None:
52
        return git.object_store
53
    return BazaarObjectStore(repo, mapping)
54
55
0.200.457 by Jelmer Vernooij
Use BaseObjectStore.
56
class BazaarObjectStore(BaseObjectStore):
0.200.320 by Jelmer Vernooij
Handle lightweight checkouts.
57
    """A Git-style object store backed onto a Bazaar repository."""
0.200.228 by Jelmer Vernooij
Split out map.
58
59
    def __init__(self, repository, mapping=None):
60
        self.repository = repository
61
        if mapping is None:
0.200.463 by Jelmer Vernooij
Support remote dpush (except for references).
62
            self.mapping = default_mapping
0.200.228 by Jelmer Vernooij
Split out map.
63
        else:
64
            self.mapping = mapping
0.200.476 by Jelmer Vernooij
Fix Tdb backend, use tdb if possible by default.
65
        try:
66
            self._idmap = TdbGitShaMap.from_repository(repository)
67
        except ImportError:
68
            self._idmap = SqliteGitShaMap.from_repository(repository)
0.200.228 by Jelmer Vernooij
Split out map.
69
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
70
    def _update_sha_map(self, stop_revision=None):
71
        if stop_revision is None:
72
            all_revids = self.repository.all_revision_ids()
73
        else:
74
            all_revids = self.repository.get_ancestry(stop_revision)
75
            first = all_revids.pop(0) # Pop leading None
76
            assert first is None
0.200.231 by Jelmer Vernooij
Partially fix pull.
77
        graph = self.repository.get_graph()
0.200.230 by Jelmer Vernooij
Implement sha cache.
78
        present_revids = set(self._idmap.revids())
0.200.347 by Jelmer Vernooij
Simplify converter a bit.
79
        missing_revids = [revid for revid in graph.iter_topo_order(all_revids) if revid not in present_revids]
0.200.231 by Jelmer Vernooij
Partially fix pull.
80
        pb = ui.ui_factory.nested_progress_bar()
81
        try:
0.200.347 by Jelmer Vernooij
Simplify converter a bit.
82
            for i, revid in enumerate(missing_revids):
83
                pb.update("updating git map", i, len(missing_revids))
0.200.231 by Jelmer Vernooij
Partially fix pull.
84
                self._update_sha_map_revision(revid)
85
        finally:
0.200.232 by Jelmer Vernooij
Fix pull from remote branches.
86
            self._idmap.commit()
0.200.231 by Jelmer Vernooij
Partially fix pull.
87
            pb.finished()
0.200.229 by Jelmer Vernooij
More work on converter.
88
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
89
    def __iter__(self):
90
        self._update_sha_map()
91
        return iter(self._idmap.sha1s())
92
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
93
    def _revision_to_commit(self, rev, tree_sha):
94
        def parent_lookup(revid):
95
            try:
96
                return self._lookup_revision_sha1(revid)
97
            except errors.NoSuchRevision:
98
                trace.warning("Ignoring ghost parent %s", revid)
99
                return None
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
100
        return self.mapping.export_commit(rev, tree_sha, parent_lookup)
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
101
0.200.229 by Jelmer Vernooij
More work on converter.
102
    def _update_sha_map_revision(self, revid):
103
        inv = self.repository.get_inventory(revid)
104
        rev = self.repository.get_revision(revid)
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
105
        unusual_modes = extract_unusual_modes(rev)
106
        tree_sha = self._get_ie_sha1(inv.root, inv, unusual_modes)
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
107
        commit_obj = self._revision_to_commit(rev, tree_sha)
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
108
        try:
109
            foreign_revid, mapping = mapping_registry.parse_revision_id(revid)
110
        except errors.InvalidRevisionId:
111
            pass
112
        else:
113
            if foreign_revid != commit_obj.id:
0.200.440 by Jelmer Vernooij
Remove silly mapping of timezones; dulwich uses offsets now as well.
114
                if not "fix-shamap" in debug.debug_flags:
115
                    raise AssertionError("recreated git commit had different sha1: expected %s, got %s" % (foreign_revid, commit_obj.id))
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
116
        self._idmap.add_entry(commit_obj.id, "commit", (revid, tree_sha))
0.200.229 by Jelmer Vernooij
More work on converter.
117
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
118
    def _check_expected_sha(self, expected_sha, object):
119
        if expected_sha is None:
120
            return
0.200.565 by Jelmer Vernooij
Cope with 'binary' shas.
121
        if len(expected_sha) == 40:
122
            if expected_sha != object.sha().hexdigest():
123
                raise AssertionError("Invalid sha for %r: %s" % (object, expected_sha))
124
        elif len(expected_sha) == 20:
125
            if expected_sha != object.sha().digest():
126
                raise AssertionError("Invalid sha for %r: %s" % (object, sha_to_hex(expected_sha)))
127
        else:
128
            raise AssertionError("Unknown length %d for %r" % (len(expected_sha), expected_sha))
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
129
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
130
    def _get_ie_object(self, entry, inv, unusual_modes):  
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
131
        if entry.kind == "directory":
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
132
            return self._get_tree(entry.file_id, inv.revision_id, inv, unusual_modes)
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
133
        else:
134
            return self._get_blob(entry.file_id, entry.revision)
135
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
136
    def _get_ie_object_or_sha1(self, entry, inv, unusual_modes):
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
137
        if entry.kind == "directory":
138
            try:
139
                return self._idmap.lookup_tree(entry.file_id, inv.revision_id), None
140
            except KeyError:
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
141
                ret = self._get_ie_object(entry, inv, unusual_modes)
0.200.593 by Jelmer Vernooij
Avoid writing empty trees.
142
                if ret is None:
143
                    hexsha = None
144
                else:
145
                    hexsha = ret.id
146
                self._idmap.add_entry(hexsha, "tree", (entry.file_id, inv.revision_id))
147
                return hexsha, ret
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
148
        else:
149
            try:
150
                return self._idmap.lookup_blob(entry.file_id, entry.revision), None
151
            except KeyError:
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
152
                ret = self._get_ie_object(entry, inv, unusual_modes)
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
153
                self._idmap.add_entry(ret.id, "blob", (entry.file_id, entry.revision))
154
                return ret.id, ret
155
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
156
    def _get_ie_sha1(self, entry, inv, unusual_modes):
157
        return self._get_ie_object_or_sha1(entry, inv, unusual_modes)[0]
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
158
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
159
    def _get_blob(self, fileid, revision, expected_sha=None):
0.200.236 by Jelmer Vernooij
require bzr 1.13.
160
        """Return a Git Blob object from a fileid and revision stored in bzr.
161
        
162
        :param fileid: File id of the text
163
        :param revision: Revision of the text
164
        """
0.200.632 by Jelmer Vernooij
Avoid accessing Repository.texts directly.
165
        chunks = self.repository.iter_files_bytes([(fileid, revision, None)]).next()[1]
0.200.229 by Jelmer Vernooij
More work on converter.
166
        blob = Blob()
0.200.632 by Jelmer Vernooij
Avoid accessing Repository.texts directly.
167
        blob._text = "".join(chunks)
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
168
        self._check_expected_sha(expected_sha, blob)
0.200.229 by Jelmer Vernooij
More work on converter.
169
        return blob
170
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
171
    def _get_tree(self, fileid, revid, inv, unusual_modes, expected_sha=None):
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
172
        """Return a Git Tree object from a file id and a revision stored in bzr.
0.200.249 by Jelmer Vernooij
Implement Tree.
173
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
174
        :param fileid: fileid in the tree.
0.200.249 by Jelmer Vernooij
Implement Tree.
175
        :param revision: Revision of the tree.
176
        """
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
177
        tree = directory_to_tree(inv[fileid], 
178
            lambda ie: self._get_ie_sha1(ie, inv, unusual_modes),
179
            unusual_modes)
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
180
        self._check_expected_sha(expected_sha, tree)
0.200.249 by Jelmer Vernooij
Implement Tree.
181
        return tree
0.200.229 by Jelmer Vernooij
More work on converter.
182
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
183
    def _get_commit(self, rev, tree_sha, expected_sha=None):
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
184
        commit = self._revision_to_commit(rev, tree_sha)
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
185
        self._check_expected_sha(expected_sha, commit)
186
        return commit
0.200.228 by Jelmer Vernooij
Split out map.
187
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
188
    def get_parents(self, sha):
0.200.454 by Jelmer Vernooij
Use ObjectStore.find_missing_objects in server.
189
        """Retrieve the parents of a Git commit by SHA1.
190
191
        :param sha: SHA1 of the commit
192
        :raises: KeyError, NotCommitError
193
        """
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
194
        return self[sha].parents
195
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
196
    def _lookup_revision_sha1(self, revid):
0.200.449 by Jelmer Vernooij
Use BazaarObjectStore to find matching SHA1s for bzr revisions.
197
        """Return the SHA1 matching a Bazaar revision."""
0.200.541 by Jelmer Vernooij
Cope with NULL_REVISION.
198
        if revid == NULL_REVISION:
199
            return "0" * 40
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
200
        try:
0.200.487 by Jelmer Vernooij
Prevent deep recursion if the shamap is out of date.
201
            return self._idmap.lookup_commit(revid)
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
202
        except KeyError:
0.200.487 by Jelmer Vernooij
Prevent deep recursion if the shamap is out of date.
203
            self._update_sha_map(revid)
204
            return self._idmap.lookup_commit(revid)
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
205
0.200.310 by Jelmer Vernooij
Fix pull from remote branches.
206
    def get_raw(self, sha):
0.200.454 by Jelmer Vernooij
Use ObjectStore.find_missing_objects in server.
207
        """Get the raw representation of a Git object by SHA1.
208
209
        :param sha: SHA1 of the git object
210
        """
0.200.566 by Jelmer Vernooij
Fix ObjectStore.get_raw() .
211
        obj = self[sha]
212
        return (obj.type, obj.as_raw_string())
0.200.310 by Jelmer Vernooij
Fix pull from remote branches.
213
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
214
    def __contains__(self, sha):
215
        # See if sha is in map
216
        try:
0.200.568 by Jelmer Vernooij
Properly check that matching bzr objects exist.
217
            (type, type_data) = self._lookup_git_sha(sha)
218
            if type == "commit":
219
                return self.repository.has_revision(type_data[0])
220
            elif type == "blob":
221
                return self.repository.texts.has_version(type_data)
222
            elif type == "tree":
223
                return self.repository.has_revision(type_data[1])
224
            else:
225
                raise AssertionError("Unknown object type '%s'" % type)
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
226
        except KeyError:
227
            return False
228
        else:
229
            return True
230
231
    def _lookup_git_sha(self, sha):
232
        # See if sha is in map
233
        try:
234
            return self._idmap.lookup_git_sha(sha)
0.200.228 by Jelmer Vernooij
Split out map.
235
        except KeyError:
236
            # if not, see if there are any unconverted revisions and add them 
237
            # to the map, search for sha in map again
238
            self._update_sha_map()
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
239
            return self._idmap.lookup_git_sha(sha)
240
241
    def __getitem__(self, sha):
242
        (type, type_data) = self._lookup_git_sha(sha)
0.200.228 by Jelmer Vernooij
Split out map.
243
        # convert object to git object
0.200.229 by Jelmer Vernooij
More work on converter.
244
        if type == "commit":
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
245
            try:
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
246
                rev = self.repository.get_revision(type_data[0])
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
247
            except errors.NoSuchRevision:
248
                trace.mutter('entry for %s %s in shamap: %r, but not found in repository', type, sha, type_data)
249
                raise KeyError(sha)
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
250
            return self._get_commit(rev, type_data[1], expected_sha=sha)
0.200.229 by Jelmer Vernooij
More work on converter.
251
        elif type == "blob":
0.200.353 by Jelmer Vernooij
fileids/revids are plain strings, not unicode
252
            return self._get_blob(type_data[0], type_data[1], expected_sha=sha)
0.200.229 by Jelmer Vernooij
More work on converter.
253
        elif type == "tree":
0.200.561 by Jelmer Vernooij
Cope with revisions pointed to by trees in the shamap disappearing.
254
            try:
255
                inv = self.repository.get_inventory(type_data[1])
256
                rev = self.repository.get_revision(type_data[1])
257
            except errors.NoSuchRevision:
258
                trace.mutter('entry for %s %s in shamap: %r, but not found in repository', type, sha, type_data)
259
                raise KeyError(sha)
0.200.556 by Jelmer Vernooij
Fix syntax error.
260
            unusual_modes = extract_unusual_modes(rev)
0.200.491 by Jelmer Vernooij
Cope with map for Tree objects becoming invalid.
261
            try:
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
262
                return self._get_tree(type_data[0], type_data[1], inv, unusual_modes,
0.200.491 by Jelmer Vernooij
Cope with map for Tree objects becoming invalid.
263
                                      expected_sha=sha)
264
            except errors.NoSuchRevision:
265
                raise KeyError(sha)
0.200.228 by Jelmer Vernooij
Split out map.
266
        else:
267
            raise AssertionError("Unknown object type '%s'" % type)