/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.784 by Jelmer Vernooij
Use common object generation code in push.
21
    Tree,
0.200.586 by Jelmer Vernooij
Fix issues pointed out by pyflakes.
22
    sha_to_hex,
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
23
    )
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
24
from dulwich.object_store import (
0.200.457 by Jelmer Vernooij
Use BaseObjectStore.
25
    BaseObjectStore,
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
26
    )
0.200.249 by Jelmer Vernooij
Implement Tree.
27
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
28
from bzrlib import (
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
29
    errors,
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
30
    lru_cache,
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
31
    trace,
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
32
    ui,
0.200.773 by Jelmer Vernooij
Implement inventory_to_objects
33
    urlutils,
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
34
    )
0.200.541 by Jelmer Vernooij
Cope with NULL_REVISION.
35
from bzrlib.revision import (
36
    NULL_REVISION,
37
    )
0.200.228 by Jelmer Vernooij
Split out map.
38
0.200.229 by Jelmer Vernooij
More work on converter.
39
from bzrlib.plugins.git.mapping import (
0.200.463 by Jelmer Vernooij
Support remote dpush (except for references).
40
    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.
41
    directory_to_tree,
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
42
    extract_unusual_modes,
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
43
    mapping_registry,
0.200.795 by Jelmer Vernooij
simplify sha extraction for blobs, process multiple blobs at once.
44
    symlink_to_blob,
0.200.229 by Jelmer Vernooij
More work on converter.
45
    )
0.200.260 by Jelmer Vernooij
Add DictGitShaMap, useful for testing.
46
from bzrlib.plugins.git.shamap import (
0.200.750 by Jelmer Vernooij
Remove unused tree code, add mechanism for migrating between sha maps.
47
    from_repository as idmap_from_repository,
0.200.231 by Jelmer Vernooij
Partially fix pull.
48
    )
49
0.200.228 by Jelmer Vernooij
Split out map.
50
0.200.452 by Jelmer Vernooij
Rename converter -> object_store, provide utility function for getting ObjectStore's.
51
def get_object_store(repo, mapping=None):
52
    git = getattr(repo, "_git", None)
53
    if git is not None:
54
        return git.object_store
55
    return BazaarObjectStore(repo, mapping)
56
57
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
58
MAX_INV_CACHE_SIZE = 50 * 1024 * 1024
59
60
61
class LRUInventoryCache(object):
62
63
    def __init__(self, repository):
64
        def approx_inv_size(inv):
65
            # Very rough estimate, 1k per inventory entry
66
            return len(inv) * 1024
67
        self.repository = repository
68
        self._cache = lru_cache.LRUSizeCache(max_size=MAX_INV_CACHE_SIZE,
69
            after_cleanup_size=None, compute_size=approx_inv_size)
70
71
    def get_inventory(self, revid):            
72
        try:
73
            return self._cache[revid] 
74
        except KeyError:
75
            inv = self.repository.get_inventory(revid)
76
            self._cache.add(revid, inv)
77
            return inv
78
0.200.791 by Jelmer Vernooij
Implement iter_inventories on inventory cache.
79
    def iter_inventories(self, revids):
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
80
        invs = dict([(k, self._cache.get(k)) for k in revids]) 
0.200.791 by Jelmer Vernooij
Implement iter_inventories on inventory cache.
81
        for inv in self.repository.iter_inventories(
82
                [r for r, v in invs.iteritems() if v is None]):
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
83
            invs[inv.revision_id] = inv
84
            self._cache.add(inv.revision_id, inv)
0.200.791 by Jelmer Vernooij
Implement iter_inventories on inventory cache.
85
        return (invs[r] for r in revids)
86
87
    def get_inventories(self, revids):
88
        return list(self.iter_inventories(revids))
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
89
90
    def add(self, revid, inv):
91
        self._cache.add(revid, inv)
92
93
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
94
def _check_expected_sha(expected_sha, object):
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
95
    """Check whether an object matches an expected SHA.
96
97
    :param expected_sha: None or expected SHA as either binary or as hex digest
98
    :param object: Object to verify
99
    """
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
100
    if expected_sha is None:
101
        return
102
    if len(expected_sha) == 40:
103
        if expected_sha != object.sha().hexdigest():
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
104
            raise AssertionError("Invalid sha for %r: %s" % (object,
105
                expected_sha))
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
106
    elif len(expected_sha) == 20:
107
        if expected_sha != object.sha().digest():
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
108
            raise AssertionError("Invalid sha for %r: %s" % (object,
109
                sha_to_hex(expected_sha)))
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
110
    else:
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
111
        raise AssertionError("Unknown length %d for %r" % (len(expected_sha),
112
            expected_sha))
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
113
114
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
115
def _inventory_to_objects(inv, parent_invs, parent_invshamaps,
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
116
        unusual_modes, iter_files_bytes, has_ghost_parents):
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
117
    """Iterate over the objects that were introduced in a revision.
118
119
    :param inv: Inventory to process
120
    :param parent_invs: parent inventory SHA maps
121
    :param parent_invshamaps: parent inventory SHA Map
122
    :param unusual_modes: Unusual file modes
123
    :param iter_files_bytes: Repository.iter_files_bytes-like callback
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
124
    :return: Yields (path, object, ie) entries
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
125
    """
126
    new_trees = {}
127
    new_blobs = []
128
    shamap = {}
129
    for path, ie in inv.entries():
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
130
        if ie.kind == "file":
0.200.800 by Jelmer Vernooij
Simplify object generation code a bit.
131
            if ie.revision != inv.revision_id:
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
132
                for (pinv, pinvshamap) in zip(parent_invs, parent_invshamaps):
133
                    try:
134
                        pie = pinv[ie.file_id]
135
                    except errors.NoSuchId:
136
                        pass
137
                    else:
0.200.800 by Jelmer Vernooij
Simplify object generation code a bit.
138
                        if (pie.text_sha1 == ie.text_sha1 and 
139
                            pie.kind == ie.kind):
0.200.836 by Jelmer Vernooij
Allow content cache.
140
                            shamap[ie.file_id] = pinvshamap.lookup_blob_id(
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
141
                                pie.file_id, pie.revision)
142
                            break
0.200.800 by Jelmer Vernooij
Simplify object generation code a bit.
143
            if not ie.file_id in shamap:
144
                new_blobs.append((path, ie))
145
                new_trees[urlutils.dirname(path)] = ie.parent_id
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
146
        elif ie.kind == "symlink":
147
            blob = symlink_to_blob(ie)
148
            for pinv in parent_invs:
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
149
                try:
150
                    pie = pinv[ie.file_id]
151
                except errors.NoSuchId:
152
                    pass
153
                else:
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
154
                    if (ie.kind == pie.kind and
155
                        ie.symlink_target == pie.symlink_target):
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
156
                        break
157
            else:
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
158
                yield path, blob, ie
0.200.801 by Jelmer Vernooij
Avoid creating trees again when they contain unchanged symlinks.
159
                new_trees[urlutils.dirname(path)] = ie.parent_id
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
160
            shamap[ie.file_id] = blob.id
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
161
        elif ie.kind == "directory":
162
            for (pinv, pinvshamap) in zip(parent_invs, parent_invshamaps):
163
                try:
164
                    pie = pinv[ie.file_id]
165
                except errors.NoSuchId:
166
                    pass
167
                else:
168
                    if (pie.kind == ie.kind and 
169
                        pie.children.keys() == ie.children.keys()):
170
                        try:
0.200.836 by Jelmer Vernooij
Allow content cache.
171
                            shamap[ie.file_id] = pinvshamap.lookup_tree_id(
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
172
                                ie.file_id)
0.200.812 by Jelmer Vernooij
Catch KeyError from lookup_tree as well - some caches (such as sqlite) don't store all trees, only some.
173
                        except (NotImplementedError, KeyError):
0.200.804 by Jelmer Vernooij
Remove overly optimistic optimization.
174
                            pass
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
175
                        else:
176
                            break
177
            else:
178
                new_trees[path] = ie.file_id
179
        else:
180
            raise AssertionError(ie.kind)
181
    
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
182
    for (path, ie), chunks in iter_files_bytes(
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
183
        [(ie.file_id, ie.revision, (path, ie.file_id))
184
            for (path, ie) in new_blobs]):
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
185
        obj = Blob()
186
        obj.data = "".join(chunks)
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
187
        yield path, obj, ie
188
        shamap[ie.file_id] = obj.id
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
189
190
    for fid in unusual_modes:
191
        new_trees[inv.id2path(fid)] = inv[fid].parent_id
192
    
193
    trees = {}
194
    while new_trees:
195
        items = new_trees.items()
196
        new_trees = {}
197
        for path, file_id in items:
198
            parent_id = inv[file_id].parent_id
199
            if parent_id is not None:
200
                parent_path = urlutils.dirname(path)
201
                new_trees[parent_path] = parent_id
202
            trees[path] = file_id
203
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
204
    def ie_to_hexsha(ie):
205
        try:
206
            return shamap[ie.file_id]
207
        except KeyError:
208
            # Not all cache backends store the tree information, 
209
            # calculate again from scratch
210
            ret = directory_to_tree(ie, ie_to_hexsha, unusual_modes)
211
            if ret is None:
212
                return ret
213
            return ret.id
214
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
215
    for path in sorted(trees.keys(), reverse=True):
216
        ie = inv[trees[path]]
217
        assert ie.kind == "directory"
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
218
        obj = directory_to_tree(ie, ie_to_hexsha, unusual_modes)
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
219
        if obj is not None:
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
220
            yield path, obj, ie
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
221
            shamap[ie.file_id] = obj.id
222
223
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
224
class ObjectStoreUpdater(object):
225
226
    def __init__(self, store, rev):
227
        self.store = store
228
        self.revid = rev.revision_id
229
        self.parent_revids = rev.parent_ids
230
        self._commit = None
231
        self._entries = []
232
233
    def add_object(self, obj, ie):
234
        if obj.type_name == "commit":
235
            self._commit = obj
0.200.839 by Jelmer Vernooij
Add convenience object for updating the object store caching layer.
236
            assert ie is None
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
237
        elif obj.type_name in ("blob", "tree"):
238
            if obj.type_name == "blob":
239
                revision = ie.revision
240
            else:
241
                revision = self.revid
242
            self._entries.append((ie.file_id, obj.type_name, obj.id, revision))
243
        else:
244
            raise AssertionError
245
246
    def finish(self):
247
        if self._commit is None:
248
            raise AssertionError("No commit object added")
249
        self.store._idmap.add_entries(self.revid, self.parent_revids,
250
            self._commit.id, self._commit.tree, self._entries)
251
        return self._commit
252
253
0.200.457 by Jelmer Vernooij
Use BaseObjectStore.
254
class BazaarObjectStore(BaseObjectStore):
0.200.320 by Jelmer Vernooij
Handle lightweight checkouts.
255
    """A Git-style object store backed onto a Bazaar repository."""
0.200.228 by Jelmer Vernooij
Split out map.
256
257
    def __init__(self, repository, mapping=None):
258
        self.repository = repository
259
        if mapping is None:
0.200.463 by Jelmer Vernooij
Support remote dpush (except for references).
260
            self.mapping = default_mapping
0.200.228 by Jelmer Vernooij
Split out map.
261
        else:
262
            self.mapping = mapping
0.200.750 by Jelmer Vernooij
Remove unused tree code, add mechanism for migrating between sha maps.
263
        self._idmap = idmap_from_repository(repository)
0.200.836 by Jelmer Vernooij
Allow content cache.
264
        self._content_cache = None
0.200.735 by Jelmer Vernooij
Use convenience functions for start/stop write groups.
265
        self.start_write_group = self._idmap.start_write_group
266
        self.abort_write_group = self._idmap.abort_write_group
267
        self.commit_write_group = self._idmap.commit_write_group
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
268
        self.parent_invs_cache = LRUInventoryCache(self.repository)
0.200.228 by Jelmer Vernooij
Split out map.
269
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
270
    def _update_sha_map(self, stop_revision=None):
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
271
        graph = self.repository.get_graph()
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
272
        if stop_revision is None:
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
273
            heads = graph.heads(self.repository.all_revision_ids())
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
274
        else:
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
275
            heads = set([stop_revision])
0.200.689 by Jelmer Vernooij
Also consider todo heads.
276
        missing_revids = self._idmap.missing_revisions(heads)
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
277
        while heads:
278
            parents = graph.get_parent_map(heads)
279
            todo = set()
280
            for p in parents.values():
0.200.684 by Jelmer Vernooij
Properly close write groups.
281
                todo.update([x for x in p if x not in missing_revids])
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
282
            heads = self._idmap.missing_revisions(todo)
0.200.684 by Jelmer Vernooij
Properly close write groups.
283
            missing_revids.update(heads)
0.200.694 by Jelmer Vernooij
Avoid processing NULL_REVISION.
284
        if NULL_REVISION in missing_revids:
285
            missing_revids.remove(NULL_REVISION)
0.200.750 by Jelmer Vernooij
Remove unused tree code, add mechanism for migrating between sha maps.
286
        missing_revids = self.repository.has_revisions(missing_revids)
287
        if not missing_revids:
288
            return
0.200.735 by Jelmer Vernooij
Use convenience functions for start/stop write groups.
289
        self.start_write_group()
0.200.231 by Jelmer Vernooij
Partially fix pull.
290
        try:
0.200.733 by Jelmer Vernooij
Use start/stop commit write group.
291
            pb = ui.ui_factory.nested_progress_bar()
292
            try:
293
                for i, revid in enumerate(graph.iter_topo_order(missing_revids)):
0.200.750 by Jelmer Vernooij
Remove unused tree code, add mechanism for migrating between sha maps.
294
                    trace.mutter('processing %r', revid)
0.200.733 by Jelmer Vernooij
Use start/stop commit write group.
295
                    pb.update("updating git map", i, len(missing_revids))
296
                    self._update_sha_map_revision(revid)
297
            finally:
298
                pb.finished()
0.200.735 by Jelmer Vernooij
Use convenience functions for start/stop write groups.
299
        except:
300
            self.abort_write_group()
301
            raise
302
        else:
303
            self.commit_write_group()
0.200.229 by Jelmer Vernooij
More work on converter.
304
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
305
    def __iter__(self):
306
        self._update_sha_map()
307
        return iter(self._idmap.sha1s())
308
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
309
    def _revision_to_commit(self, rev, tree_sha):
310
        def parent_lookup(revid):
311
            try:
312
                return self._lookup_revision_sha1(revid)
313
            except errors.NoSuchRevision:
314
                trace.warning("Ignoring ghost parent %s", revid)
315
                return None
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
316
        return self.mapping.export_commit(rev, tree_sha, parent_lookup)
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
317
0.200.783 by Jelmer Vernooij
Move object generation into a separate function.
318
    def _revision_to_objects(self, rev, inv):
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
319
        unusual_modes = extract_unusual_modes(rev)
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
320
        present_parents = self.repository.has_revisions(rev.parent_ids)
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
321
        has_ghost_parents = (len(rev.parent_ids) < len(present_parents))
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
322
        parent_invs = self.parent_invs_cache.get_inventories(
323
            [p for p in rev.parent_ids if p in present_parents])
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
324
        parent_invshamaps = [self._idmap.get_inventory_sha_map(r) for r in rev.parent_ids if r in present_parents]
0.200.773 by Jelmer Vernooij
Implement inventory_to_objects
325
        tree_sha = None
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
326
        for path, obj, ie in _inventory_to_objects(inv, parent_invs,
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
327
                parent_invshamaps, unusual_modes,
0.200.799 by Jelmer Vernooij
Add trivial object store tests.
328
                self.repository.iter_files_bytes, has_ghost_parents):
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
329
            yield path, obj, ie
0.200.773 by Jelmer Vernooij
Implement inventory_to_objects
330
            if path == "":
331
                tree_sha = obj.id
0.200.784 by Jelmer Vernooij
Use common object generation code in push.
332
        if tree_sha is None:
333
            if not rev.parent_ids:
334
                tree_sha = Tree().id
335
            else:
336
                tree_sha = parent_invshamaps[0][inv.root.file_id]
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
337
        commit_obj = self._revision_to_commit(rev, tree_sha)
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
338
        try:
0.200.784 by Jelmer Vernooij
Use common object generation code in push.
339
            foreign_revid, mapping = mapping_registry.parse_revision_id(rev.revision_id)
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
340
        except errors.InvalidRevisionId:
341
            pass
342
        else:
0.200.794 by Jelmer Vernooij
Use _check_expected_sha rather than custom checks.
343
            _check_expected_sha(foreign_revid, commit_obj)
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
344
        yield None, commit_obj, None
0.200.783 by Jelmer Vernooij
Move object generation into a separate function.
345
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
346
    def _get_updater(self, rev):
347
        return ObjectStoreUpdater(self, rev)
348
0.200.783 by Jelmer Vernooij
Move object generation into a separate function.
349
    def _update_sha_map_revision(self, revid):
350
        rev = self.repository.get_revision(revid)
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
351
        inv = self.parent_invs_cache.get_inventory(rev.revision_id)
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
352
        updater = self._get_updater(rev)
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
353
        for path, obj, ie in self._revision_to_objects(rev, inv):
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
354
            updater.add(obj, ie)
355
        commit_obj = updater.finish()
0.200.781 by Jelmer Vernooij
Return commit id after converting a revision.
356
        return commit_obj.id
0.200.229 by Jelmer Vernooij
More work on converter.
357
0.200.796 by Jelmer Vernooij
Avoid doing get_inventory calls if they can be avoided.
358
    def _get_blob(self, fileid, revision, expected_sha):
0.200.236 by Jelmer Vernooij
require bzr 1.13.
359
        """Return a Git Blob object from a fileid and revision stored in bzr.
0.200.670 by Jelmer Vernooij
Fix symlinks.
360
0.200.236 by Jelmer Vernooij
require bzr 1.13.
361
        :param fileid: File id of the text
362
        :param revision: Revision of the text
363
        """
0.200.796 by Jelmer Vernooij
Avoid doing get_inventory calls if they can be avoided.
364
        blob = Blob()
365
        chunks = self.repository.iter_files_bytes([(fileid, revision, None)]).next()[1]
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
366
        blob.data = "".join(chunks)
0.200.796 by Jelmer Vernooij
Avoid doing get_inventory calls if they can be avoided.
367
        if blob.id != expected_sha:
368
            # Perhaps it's a symlink ?
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
369
            inv = self.parent_invs_cache.get_inventory(revision)
0.200.796 by Jelmer Vernooij
Avoid doing get_inventory calls if they can be avoided.
370
            entry = inv[fileid]
371
            assert entry.kind == 'symlink'
0.200.795 by Jelmer Vernooij
simplify sha extraction for blobs, process multiple blobs at once.
372
            blob = symlink_to_blob(entry)
373
        _check_expected_sha(expected_sha, blob)
374
        return blob
0.200.229 by Jelmer Vernooij
More work on converter.
375
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
376
    def _get_tree(self, fileid, revid, inv, unusual_modes, expected_sha=None):
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
377
        """Return a Git Tree object from a file id and a revision stored in bzr.
0.200.249 by Jelmer Vernooij
Implement Tree.
378
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
379
        :param fileid: fileid in the tree.
0.200.249 by Jelmer Vernooij
Implement Tree.
380
        :param revision: Revision of the tree.
381
        """
0.200.761 by Jelmer Vernooij
Defer invshamap calls.
382
        invshamap = self._idmap.get_inventory_sha_map(inv.revision_id)
0.200.776 by Jelmer Vernooij
Remove unnecessary lookups.
383
        def get_ie_sha1(entry):
384
            if entry.kind == "directory":
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
385
                try:
0.200.836 by Jelmer Vernooij
Allow content cache.
386
                    return invshamap.lookup_tree_id(entry.file_id)
0.200.812 by Jelmer Vernooij
Catch KeyError from lookup_tree as well - some caches (such as sqlite) don't store all trees, only some.
387
                except (NotImplementedError, KeyError):
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
388
                    obj = self._get_tree(entry.file_id, revid, inv,
389
                        unusual_modes)
390
                    if obj is None:
391
                        return None
392
                    else:
393
                        return obj.id
0.200.776 by Jelmer Vernooij
Remove unnecessary lookups.
394
            elif entry.kind in ("file", "symlink"):
0.200.836 by Jelmer Vernooij
Allow content cache.
395
                return invshamap.lookup_blob_id(entry.file_id, entry.revision)
0.200.776 by Jelmer Vernooij
Remove unnecessary lookups.
396
            else:
397
                raise AssertionError("unknown entry kind '%s'" % entry.kind)
398
        tree = directory_to_tree(inv[fileid], get_ie_sha1, unusual_modes)
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
399
        _check_expected_sha(expected_sha, tree)
0.200.249 by Jelmer Vernooij
Implement Tree.
400
        return tree
0.200.229 by Jelmer Vernooij
More work on converter.
401
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
402
    def get_parents(self, sha):
0.200.454 by Jelmer Vernooij
Use ObjectStore.find_missing_objects in server.
403
        """Retrieve the parents of a Git commit by SHA1.
404
405
        :param sha: SHA1 of the commit
406
        :raises: KeyError, NotCommitError
407
        """
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
408
        return self[sha].parents
409
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
410
    def _lookup_revision_sha1(self, revid):
0.200.449 by Jelmer Vernooij
Use BazaarObjectStore to find matching SHA1s for bzr revisions.
411
        """Return the SHA1 matching a Bazaar revision."""
0.200.541 by Jelmer Vernooij
Cope with NULL_REVISION.
412
        if revid == NULL_REVISION:
413
            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.
414
        try:
0.200.487 by Jelmer Vernooij
Prevent deep recursion if the shamap is out of date.
415
            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.
416
        except KeyError:
0.200.682 by Jelmer Vernooij
Avoid doing a full sha map update if we already know the SHA1.
417
            try:
418
                return mapping_registry.parse_revision_id(revid)[0]
419
            except errors.InvalidRevisionId:
420
                self._update_sha_map(revid)
421
                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.
422
0.200.310 by Jelmer Vernooij
Fix pull from remote branches.
423
    def get_raw(self, sha):
0.200.454 by Jelmer Vernooij
Use ObjectStore.find_missing_objects in server.
424
        """Get the raw representation of a Git object by SHA1.
425
426
        :param sha: SHA1 of the git object
427
        """
0.200.566 by Jelmer Vernooij
Fix ObjectStore.get_raw() .
428
        obj = self[sha]
429
        return (obj.type, obj.as_raw_string())
0.200.310 by Jelmer Vernooij
Fix pull from remote branches.
430
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
431
    def __contains__(self, sha):
432
        # See if sha is in map
433
        try:
0.200.568 by Jelmer Vernooij
Properly check that matching bzr objects exist.
434
            (type, type_data) = self._lookup_git_sha(sha)
435
            if type == "commit":
436
                return self.repository.has_revision(type_data[0])
437
            elif type == "blob":
438
                return self.repository.texts.has_version(type_data)
439
            elif type == "tree":
440
                return self.repository.has_revision(type_data[1])
441
            else:
442
                raise AssertionError("Unknown object type '%s'" % type)
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
443
        except KeyError:
444
            return False
445
446
    def _lookup_git_sha(self, sha):
447
        # See if sha is in map
448
        try:
449
            return self._idmap.lookup_git_sha(sha)
0.200.228 by Jelmer Vernooij
Split out map.
450
        except KeyError:
0.200.670 by Jelmer Vernooij
Fix symlinks.
451
            # if not, see if there are any unconverted revisions and add them
0.200.228 by Jelmer Vernooij
Split out map.
452
            # to the map, search for sha in map again
453
            self._update_sha_map()
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
454
            return self._idmap.lookup_git_sha(sha)
455
456
    def __getitem__(self, sha):
457
        (type, type_data) = self._lookup_git_sha(sha)
0.200.228 by Jelmer Vernooij
Split out map.
458
        # convert object to git object
0.200.229 by Jelmer Vernooij
More work on converter.
459
        if type == "commit":
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
460
            (revid, tree_sha) = type_data
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
461
            try:
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
462
                rev = self.repository.get_revision(revid)
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
463
            except errors.NoSuchRevision:
0.200.836 by Jelmer Vernooij
Allow content cache.
464
                trace.mutter('entry for %s %s in shamap: %r, but not found in '
465
                             'repository', type, sha, type_data)
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
466
                raise KeyError(sha)
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
467
            commit = self._revision_to_commit(rev, tree_sha)
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
468
            _check_expected_sha(sha, commit)
0.200.785 by Jelmer Vernooij
Eliminate _get_commit.
469
            return commit
0.200.229 by Jelmer Vernooij
More work on converter.
470
        elif type == "blob":
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
471
            (fileid, revision) = type_data
472
            return self._get_blob(fileid, revision, expected_sha=sha)
0.200.229 by Jelmer Vernooij
More work on converter.
473
        elif type == "tree":
0.200.836 by Jelmer Vernooij
Allow content cache.
474
            if self._content_cache is not None:
475
                try:
476
                    return self._content_cache[sha]
477
                except KeyError:
478
                    pass
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
479
            (fileid, revid) = type_data
0.200.561 by Jelmer Vernooij
Cope with revisions pointed to by trees in the shamap disappearing.
480
            try:
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
481
                inv = self.parent_invs_cache.get_inventory(revid)
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
482
                rev = self.repository.get_revision(revid)
0.200.561 by Jelmer Vernooij
Cope with revisions pointed to by trees in the shamap disappearing.
483
            except errors.NoSuchRevision:
484
                trace.mutter('entry for %s %s in shamap: %r, but not found in repository', type, sha, type_data)
485
                raise KeyError(sha)
0.200.556 by Jelmer Vernooij
Fix syntax error.
486
            unusual_modes = extract_unusual_modes(rev)
0.200.491 by Jelmer Vernooij
Cope with map for Tree objects becoming invalid.
487
            try:
0.200.836 by Jelmer Vernooij
Allow content cache.
488
                return self._get_tree(fileid, revid, inv, unusual_modes,
489
                    expected_sha=sha)
0.200.491 by Jelmer Vernooij
Cope with map for Tree objects becoming invalid.
490
            except errors.NoSuchRevision:
491
                raise KeyError(sha)
0.200.228 by Jelmer Vernooij
Split out map.
492
        else:
493
            raise AssertionError("Unknown object type '%s'" % type)
0.200.782 by Jelmer Vernooij
Add custom generate_pack_contents implementation.
494
495
    def generate_pack_contents(self, have, want):
496
        """Iterate over the contents of a pack file.
497
498
        :param have: List of SHA1s of objects that should not be sent
499
        :param want: List of SHA1s of objects that should be sent
500
        """
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
501
        processed = set()
502
        for commit_sha in have:
503
            try:
504
                (type, (revid, tree_sha)) = self._lookup_git_sha(commit_sha)
505
            except KeyError:
506
                pass
507
            else:
508
                assert type == "commit"
509
                processed.add(revid)
510
        pending = set()
511
        for commit_sha in want:
512
            if commit_sha in have:
513
                continue
514
            (type, (revid, tree_sha)) = self._lookup_git_sha(commit_sha)
515
            assert type == "commit"
516
            pending.add(revid)
517
        todo = set()
518
        while pending:
519
            processed.update(pending)
520
            next_map = self.repository.get_parent_map(pending)
521
            next_pending = set()
522
            for item in next_map.iteritems():
523
                todo.add(item[0])
524
                next_pending.update(p for p in item[1] if p not in processed)
525
            pending = next_pending
526
        if NULL_REVISION in todo:
527
            todo.remove(NULL_REVISION)
528
        trace.mutter('sending revisions %r', todo)
529
        ret = []
530
        pb = ui.ui_factory.nested_progress_bar()
531
        try:
532
            for i, revid in enumerate(todo):
533
                pb.update("generating git objects", i, len(todo))
534
                rev = self.repository.get_revision(revid)
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
535
                inv = self.parent_invs_cache.get_inventory(revid)
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
536
                for path, obj, ie in self._revision_to_objects(rev, inv):
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
537
                    ret.append((obj, path))
538
        finally:
539
            pb.finished()
540
        return ret