/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.864 by Jelmer Vernooij
Cope with the first commit being pointless.
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.938 by Jelmer Vernooij
Rename shamap to cache, as it can also do content caching now.
46
from bzrlib.plugins.git.cache import (
0.200.842 by Jelmer Vernooij
Allow content cache to be provided.
47
    from_repository as cache_from_repository,
0.200.231 by Jelmer Vernooij
Partially fix pull.
48
    )
49
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
50
import posixpath
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
51
import stat
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
52
0.200.228 by Jelmer Vernooij
Split out map.
53
0.200.452 by Jelmer Vernooij
Rename converter -> object_store, provide utility function for getting ObjectStore's.
54
def get_object_store(repo, mapping=None):
55
    git = getattr(repo, "_git", None)
56
    if git is not None:
57
        return git.object_store
58
    return BazaarObjectStore(repo, mapping)
59
60
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
61
MAX_TREE_CACHE_SIZE = 50 * 1024 * 1024
62
63
64
class LRUTreeCache(object):
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
65
66
    def __init__(self, repository):
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
67
        def approx_tree_size(tree):
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
68
            # Very rough estimate, 1k per inventory entry
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
69
            return len(tree.inventory) * 1024
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
70
        self.repository = repository
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
71
        self._cache = lru_cache.LRUSizeCache(max_size=MAX_TREE_CACHE_SIZE,
72
            after_cleanup_size=None, compute_size=approx_tree_size)
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
73
0.200.963 by Jelmer Vernooij
Add some tests for LRUTreeCache.
74
    def revision_tree(self, revid):
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
75
        try:
0.200.989 by Jelmer Vernooij
Add asserts.
76
            tree = self._cache[revid]
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
77
        except KeyError:
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
78
            tree = self.repository.revision_tree(revid)
79
            self.add(tree)
0.200.989 by Jelmer Vernooij
Add asserts.
80
        assert tree.get_revision_id() == tree.inventory.revision_id
81
        return tree
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
82
83
    def iter_revision_trees(self, revids):
0.200.989 by Jelmer Vernooij
Add asserts.
84
        trees = {}
85
        todo = []
86
        for revid in revids:
87
            try:
88
                tree = self._cache[revid]
89
            except KeyError:
90
                todo.append(revid)
91
            else:
92
                assert tree.get_revision_id() == revid
93
                assert tree.inventory.revision_id == revid
94
                trees[revid] = tree
95
        for tree in self.repository.revision_trees(todo):
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
96
            trees[tree.get_revision_id()] = tree
97
            self.add(tree)
98
        return (trees[r] for r in revids)
99
100
    def revision_trees(self, revids):
101
        return list(self.iter_revision_trees(revids))
102
103
    def add(self, tree):
104
        self._cache.add(tree.get_revision_id(), tree)
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
105
106
0.252.5 by Jelmer Vernooij
enable 'bzr push'.
107
def _find_missing_bzr_revids(get_parent_map, want, have):
108
    """Find the revisions that have to be pushed.
109
110
    :param get_parent_map: Function that returns the parents for a sequence
111
        of revisions.
112
    :param want: Revisions the target wants
113
    :param have: Revisions the target already has
114
    :return: Set of revisions to fetch
115
    """
116
    pending = want - have
117
    processed = set()
0.200.899 by Jelmer Vernooij
Add tests for find_missing_bzr_revids.
118
    todo = set()
119
    while pending:
120
        processed.update(pending)
121
        next_map = get_parent_map(pending)
122
        next_pending = set()
123
        for item in next_map.iteritems():
0.252.5 by Jelmer Vernooij
enable 'bzr push'.
124
            if item[0] in have:
125
                continue
0.200.899 by Jelmer Vernooij
Add tests for find_missing_bzr_revids.
126
            todo.add(item[0])
127
            next_pending.update(p for p in item[1] if p not in processed)
128
        pending = next_pending
129
    if NULL_REVISION in todo:
130
        todo.remove(NULL_REVISION)
131
    return todo
132
133
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
134
def _check_expected_sha(expected_sha, object):
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
135
    """Check whether an object matches an expected SHA.
136
137
    :param expected_sha: None or expected SHA as either binary or as hex digest
138
    :param object: Object to verify
139
    """
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
140
    if expected_sha is None:
141
        return
142
    if len(expected_sha) == 40:
143
        if expected_sha != object.sha().hexdigest():
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
144
            raise AssertionError("Invalid sha for %r: %s" % (object,
145
                expected_sha))
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
146
    elif len(expected_sha) == 20:
147
        if expected_sha != object.sha().digest():
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
148
            raise AssertionError("Invalid sha for %r: %s" % (object,
149
                sha_to_hex(expected_sha)))
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
150
    else:
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
151
        raise AssertionError("Unknown length %d for %r" % (len(expected_sha),
152
            expected_sha))
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
153
154
0.200.931 by Jelmer Vernooij
Update docstring, deal with kind changes appropriately in _tree_to_objects
155
def _tree_to_objects(tree, parent_trees, idmap, unusual_modes,
156
                     dummy_file_name=None):
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
157
    """Iterate over the objects that were introduced in a revision.
158
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
159
    :param idmap: id map
0.200.931 by Jelmer Vernooij
Update docstring, deal with kind changes appropriately in _tree_to_objects
160
    :param parent_trees: Parent revision trees
161
    :param unusual_modes: Unusual file modes dictionary
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
162
    :param dummy_file_name: File name to use for dummy files
163
        in empty directories. None to skip empty directories
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
164
    :return: Yields (path, object, ie) entries
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
165
    """
166
    new_trees = {}
167
    new_blobs = []
168
    shamap = {}
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
169
    try:
170
        base_tree = parent_trees[0]
171
        other_parent_trees = parent_trees[1:]
172
    except IndexError:
173
        base_tree = tree._repository.revision_tree(NULL_REVISION)
174
        other_parent_trees = []
0.200.868 by Jelmer Vernooij
Cope with no-change merges.
175
    def find_unchanged_parent_ie(ie, parent_trees):
176
        assert ie.kind in ("symlink", "file")
177
        for ptree in parent_trees:
178
            try:
179
                pie = ptree.inventory[ie.file_id]
180
            except errors.NoSuchId:
181
                pass
182
            else:
183
                if (pie.text_sha1 == ie.text_sha1 and 
184
                    pie.kind == ie.kind and
185
                    pie.symlink_target == ie.symlink_target):
186
                    return pie
187
        raise KeyError
0.200.965 by Jelmer Vernooij
Formatting fixes.
188
0.200.931 by Jelmer Vernooij
Update docstring, deal with kind changes appropriately in _tree_to_objects
189
    # Find all the changed blobs
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
190
    for (file_id, path, changed_content, versioned, parent, name, kind,
191
         executable) in tree.iter_changes(base_tree):
192
        if kind[1] == "file":
193
            ie = tree.inventory[file_id]
194
            if changed_content:
0.200.868 by Jelmer Vernooij
Cope with no-change merges.
195
                try:
196
                    pie = find_unchanged_parent_ie(ie, other_parent_trees)
197
                except KeyError:
198
                    pass
199
                else:
0.252.40 by Jelmer Vernooij
Checks for roundtripping.
200
                    try:
201
                        shamap[ie.file_id] = idmap.lookup_blob_id(
202
                            pie.file_id, pie.revision)
203
                    except KeyError:
204
                        # no-change merge ?
205
                        blob = Blob()
206
                        blob.data = tree.get_file_text(ie.file_id)
207
                        shamap[ie.file_id] = blob.id
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
208
            if not file_id in shamap:
209
                new_blobs.append((path[1], ie))
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
210
            new_trees[posixpath.dirname(path[1])] = parent[1]
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
211
        elif kind[1] == "symlink":
212
            ie = tree.inventory[file_id]
213
            if changed_content:
214
                blob = symlink_to_blob(ie)
0.200.868 by Jelmer Vernooij
Cope with no-change merges.
215
                shamap[file_id] = blob.id
216
                try:
217
                    find_unchanged_parent_ie(ie, other_parent_trees)
218
                except KeyError:
219
                    yield path[1], blob, ie
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
220
            new_trees[posixpath.dirname(path[1])] = parent[1]
0.250.3 by Jelmer Vernooij
Simplify..
221
        elif kind[1] not in (None, "directory"):
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
222
            raise AssertionError(kind[1])
0.200.1017 by Jelmer Vernooij
Cope with root moving.
223
        if (path[0] not in (None, "") and
224
            parent[0] in tree.inventory and
225
            tree.inventory[parent[0]].kind == "directory"):
0.200.931 by Jelmer Vernooij
Update docstring, deal with kind changes appropriately in _tree_to_objects
226
            # Removal
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
227
            new_trees[posixpath.dirname(path[0])] = parent[0]
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
228
    
0.200.931 by Jelmer Vernooij
Update docstring, deal with kind changes appropriately in _tree_to_objects
229
    # Fetch contents of the blobs that were changed
0.250.2 by Jelmer Vernooij
Make it work for evolution.
230
    for (path, ie), chunks in tree.iter_files_bytes(
231
        [(ie.file_id, (path, ie)) for (path, ie) in new_blobs]):
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
232
        obj = Blob()
0.200.851 by Jelmer Vernooij
Use blob.chunked.
233
        obj.chunked = chunks
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
234
        yield path, obj, ie
235
        shamap[ie.file_id] = obj.id
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
236
0.200.879 by Jelmer Vernooij
Fix unusual modes.
237
    for path in unusual_modes:
238
        parent_path = posixpath.dirname(path)
239
        new_trees[parent_path] = tree.path2id(parent_path)
0.200.989 by Jelmer Vernooij
Add asserts.
240
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
241
    trees = {}
242
    while new_trees:
243
        items = new_trees.items()
244
        new_trees = {}
245
        for path, file_id in items:
0.200.931 by Jelmer Vernooij
Update docstring, deal with kind changes appropriately in _tree_to_objects
246
            parent_id = tree.inventory[file_id].parent_id
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
247
            if parent_id is not None:
248
                parent_path = urlutils.dirname(path)
249
                new_trees[parent_path] = parent_id
250
            trees[path] = file_id
251
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
252
    def ie_to_hexsha(ie):
253
        try:
254
            return shamap[ie.file_id]
255
        except KeyError:
0.200.884 by Jelmer Vernooij
Cope with -0000 as timezone in Git commits.
256
            # FIXME: Should be the same as in parent
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
257
            if ie.kind in ("file", "symlink"):
0.200.868 by Jelmer Vernooij
Cope with no-change merges.
258
                try:
259
                    return idmap.lookup_blob_id(ie.file_id, ie.revision)
260
                except KeyError:
261
                    # no-change merge ?
262
                    blob = Blob()
263
                    blob.data = tree.get_file_text(ie.file_id)
264
                    return blob.id
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
265
            elif ie.kind == "directory":
266
                # Not all cache backends store the tree information, 
267
                # calculate again from scratch
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
268
                ret = directory_to_tree(ie, ie_to_hexsha, unusual_modes,
269
                    dummy_file_name)
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
270
                if ret is None:
271
                    return ret
272
                return ret.id
273
            else:
274
                raise AssertionError
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
275
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
276
    for path in sorted(trees.keys(), reverse=True):
0.250.1 by Jelmer Vernooij
Use iter_changes() rather than iterating over all contents of an inventory.
277
        ie = tree.inventory[trees[path]]
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
278
        assert ie.kind == "directory"
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
279
        obj = directory_to_tree(ie, ie_to_hexsha, unusual_modes,
280
            dummy_file_name)
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
281
        if obj is not None:
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
282
            yield path, obj, ie
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
283
            shamap[ie.file_id] = obj.id
284
285
0.200.457 by Jelmer Vernooij
Use BaseObjectStore.
286
class BazaarObjectStore(BaseObjectStore):
0.200.320 by Jelmer Vernooij
Handle lightweight checkouts.
287
    """A Git-style object store backed onto a Bazaar repository."""
0.200.228 by Jelmer Vernooij
Split out map.
288
289
    def __init__(self, repository, mapping=None):
290
        self.repository = repository
291
        if mapping is None:
0.200.463 by Jelmer Vernooij
Support remote dpush (except for references).
292
            self.mapping = default_mapping
0.200.228 by Jelmer Vernooij
Split out map.
293
        else:
294
            self.mapping = mapping
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
295
        self._cache = cache_from_repository(repository)
0.254.40 by Jelmer Vernooij
Add content cache infrastructure.
296
        self._content_cache_types = ("tree")
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
297
        self.start_write_group = self._cache.idmap.start_write_group
298
        self.abort_write_group = self._cache.idmap.abort_write_group
299
        self.commit_write_group = self._cache.idmap.commit_write_group
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
300
        self.tree_cache = LRUTreeCache(self.repository)
0.200.228 by Jelmer Vernooij
Split out map.
301
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
302
    def _update_sha_map(self, stop_revision=None):
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
303
        graph = self.repository.get_graph()
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
304
        if stop_revision is None:
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
305
            heads = graph.heads(self.repository.all_revision_ids())
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
306
        else:
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
307
            heads = set([stop_revision])
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
308
        missing_revids = self._cache.idmap.missing_revisions(heads)
0.200.683 by Jelmer Vernooij
Lazier checking of which revisions need to be fetched.
309
        while heads:
310
            parents = graph.get_parent_map(heads)
311
            todo = set()
312
            for p in parents.values():
0.200.684 by Jelmer Vernooij
Properly close write groups.
313
                todo.update([x for x in p if x not in missing_revids])
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
314
            heads = self._cache.idmap.missing_revisions(todo)
0.200.684 by Jelmer Vernooij
Properly close write groups.
315
            missing_revids.update(heads)
0.200.694 by Jelmer Vernooij
Avoid processing NULL_REVISION.
316
        if NULL_REVISION in missing_revids:
317
            missing_revids.remove(NULL_REVISION)
0.254.16 by Jelmer Vernooij
Add optimization preventing recursive index updating.
318
        missing_revids = self.repository.has_revisions(missing_revids)
319
        if not missing_revids:
320
            return
0.200.735 by Jelmer Vernooij
Use convenience functions for start/stop write groups.
321
        self.start_write_group()
0.200.231 by Jelmer Vernooij
Partially fix pull.
322
        try:
0.254.4 by Jelmer Vernooij
Merge trunk.
323
            pb = ui.ui_factory.nested_progress_bar()
324
            try:
325
                for i, revid in enumerate(graph.iter_topo_order(missing_revids)):
0.254.16 by Jelmer Vernooij
Add optimization preventing recursive index updating.
326
                    trace.mutter('processing %r', revid)
0.254.4 by Jelmer Vernooij
Merge trunk.
327
                    pb.update("updating git map", i, len(missing_revids))
328
                    self._update_sha_map_revision(revid)
329
            finally:
330
                pb.finished()
0.200.735 by Jelmer Vernooij
Use convenience functions for start/stop write groups.
331
        except:
332
            self.abort_write_group()
333
            raise
334
        else:
335
            self.commit_write_group()
0.200.229 by Jelmer Vernooij
More work on converter.
336
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
337
    def __iter__(self):
338
        self._update_sha_map()
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
339
        return iter(self._cache.idmap.sha1s())
0.200.422 by Jelmer Vernooij
'bzr git-object' without arguments now prints the available git objects.
340
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
341
    def _reconstruct_commit(self, rev, tree_sha, roundtrip):
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
342
        def parent_lookup(revid):
343
            try:
344
                return self._lookup_revision_sha1(revid)
345
            except errors.NoSuchRevision:
346
                return None
0.252.4 by Jelmer Vernooij
More work on roundtripping.
347
        return self.mapping.export_commit(rev, tree_sha, parent_lookup,
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
348
            roundtrip)
0.238.7 by Jelmer Vernooij
Cope with ghosts a bit better.
349
0.252.49 by Jelmer Vernooij
Avoid trying to set HEAD for remote branches.
350
    def _create_fileid_map_blob(self, inv):
351
        # FIXME: This can probably be a lot more efficient, 
352
        # not all files necessarily have to be processed.
353
        file_ids = {}
354
        for (path, ie) in inv.iter_entries():
355
            if self.mapping.generate_file_id(path) != ie.file_id:
356
                file_ids[path] = ie.file_id
357
        return self.mapping.export_fileid_map(file_ids)
358
0.252.4 by Jelmer Vernooij
More work on roundtripping.
359
    def _revision_to_objects(self, rev, tree, roundtrip):
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
360
        """Convert a revision to a set of git objects.
361
362
        :param rev: Bazaar revision object
363
        :param tree: Bazaar revision tree
364
        :param roundtrip: Whether to roundtrip all Bazaar revision data
365
        """
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
366
        unusual_modes = extract_unusual_modes(rev)
0.200.789 by Jelmer Vernooij
Cope with ghosts, cache inventories.
367
        present_parents = self.repository.has_revisions(rev.parent_ids)
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
368
        parent_trees = self.tree_cache.revision_trees(
0.200.797 by Jelmer Vernooij
Add docstring, fix formatting.
369
            [p for p in rev.parent_ids if p in present_parents])
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
370
        root_tree = None
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
371
        for path, obj, ie in _tree_to_objects(tree, parent_trees,
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
372
                self._cache.idmap, unusual_modes, self.mapping.BZR_DUMMY_FILE):
0.200.773 by Jelmer Vernooij
Implement inventory_to_objects
373
            if path == "":
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
374
                root_tree = obj
0.252.34 by Jelmer Vernooij
Yield the proper object for the tree root.
375
                root_ie = ie
376
                # Don't yield just yet
377
            else:
378
                yield path, obj, ie
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
379
        if root_tree is None:
0.250.2 by Jelmer Vernooij
Make it work for evolution.
380
            # Pointless commit - get the tree sha elsewhere
0.200.864 by Jelmer Vernooij
Cope with the first commit being pointless.
381
            if not rev.parent_ids:
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
382
                root_tree = Tree()
0.200.864 by Jelmer Vernooij
Cope with the first commit being pointless.
383
            else:
384
                base_sha1 = self._lookup_revision_sha1(rev.parent_ids[0])
0.252.37 by Jelmer Vernooij
Factor out some common code for finding refs to send.
385
                root_tree = self[self[base_sha1].tree]
0.252.35 by Jelmer Vernooij
Ignore control files in inventories.
386
            root_ie = tree.inventory.root
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
387
        if roundtrip and self.mapping.BZR_FILE_IDS_FILE is not None:
0.252.49 by Jelmer Vernooij
Avoid trying to set HEAD for remote branches.
388
            b = self._create_fileid_map_blob(tree.inventory)
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
389
            if b is not None:
390
                root_tree[self.mapping.BZR_FILE_IDS_FILE] = ((stat.S_IFREG | 0644), b.id)
391
                yield self.mapping.BZR_FILE_IDS_FILE, b, None
0.252.34 by Jelmer Vernooij
Yield the proper object for the tree root.
392
        yield "", root_tree, root_ie
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
393
        commit_obj = self._reconstruct_commit(rev, root_tree.id,
394
            roundtrip=roundtrip)
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
395
        try:
0.200.841 by Jelmer Vernooij
Eliminate InventorySHAMap.
396
            foreign_revid, mapping = mapping_registry.parse_revision_id(
397
                rev.revision_id)
0.231.1 by Jelmer Vernooij
Check that regenerated objects have the expected sha1.
398
        except errors.InvalidRevisionId:
399
            pass
400
        else:
0.200.794 by Jelmer Vernooij
Use _check_expected_sha rather than custom checks.
401
            _check_expected_sha(foreign_revid, commit_obj)
0.200.837 by Jelmer Vernooij
Return inventory entries when creating git objects for a revision.
402
        yield None, commit_obj, None
0.200.783 by Jelmer Vernooij
Move object generation into a separate function.
403
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
404
    def _get_updater(self, rev):
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
405
        return self._cache.get_updater(rev)
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
406
0.200.783 by Jelmer Vernooij
Move object generation into a separate function.
407
    def _update_sha_map_revision(self, revid):
408
        rev = self.repository.get_revision(revid)
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
409
        tree = self.tree_cache.revision_tree(rev.revision_id)
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
410
        updater = self._get_updater(rev)
0.252.4 by Jelmer Vernooij
More work on roundtripping.
411
        for path, obj, ie in self._revision_to_objects(rev, tree,
412
            roundtrip=True):
0.200.952 by Jelmer Vernooij
Write git pack files rather than loose objects.
413
            updater.add_object(obj, ie, path)
0.200.838 by Jelmer Vernooij
Add convenience object for updating the object store.
414
        commit_obj = updater.finish()
0.200.781 by Jelmer Vernooij
Return commit id after converting a revision.
415
        return commit_obj.id
0.200.229 by Jelmer Vernooij
More work on converter.
416
0.200.855 by Jelmer Vernooij
_get_ -> _reconstruct_.
417
    def _reconstruct_blobs(self, keys):
0.200.698 by Jelmer Vernooij
Merge fixes for SHA1s of symlinks.
418
        """Return a Git Blob object from a fileid and revision stored in bzr.
419
420
        :param fileid: File id of the text
421
        :param revision: Revision of the text
422
        """
0.250.2 by Jelmer Vernooij
Make it work for evolution.
423
        stream = self.repository.iter_files_bytes(
424
            ((key[0], key[1], key) for key in keys))
0.200.856 by Jelmer Vernooij
Support reconstructing multiple blobs at the same time.
425
        for (fileid, revision, expected_sha), chunks in stream:
0.200.854 by Jelmer Vernooij
_get_blob -> _get_blobs.
426
            blob = Blob()
427
            blob.chunked = chunks
0.200.868 by Jelmer Vernooij
Cope with no-change merges.
428
            if blob.id != expected_sha and blob.data == "":
0.200.854 by Jelmer Vernooij
_get_blob -> _get_blobs.
429
                # Perhaps it's a symlink ?
430
                tree = self.tree_cache.revision_tree(revision)
431
                entry = tree.inventory[fileid]
0.200.868 by Jelmer Vernooij
Cope with no-change merges.
432
                if entry.kind == 'symlink':
433
                    blob = symlink_to_blob(entry)
0.200.854 by Jelmer Vernooij
_get_blob -> _get_blobs.
434
            _check_expected_sha(expected_sha, blob)
435
            yield blob
0.200.229 by Jelmer Vernooij
More work on converter.
436
0.200.855 by Jelmer Vernooij
_get_ -> _reconstruct_.
437
    def _reconstruct_tree(self, fileid, revid, inv, unusual_modes,
438
        expected_sha=None):
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
439
        """Return a Git Tree object from a file id and a revision stored in bzr.
0.200.249 by Jelmer Vernooij
Implement Tree.
440
0.200.343 by Jelmer Vernooij
Use file ids consistently in map.
441
        :param fileid: fileid in the tree.
0.200.249 by Jelmer Vernooij
Implement Tree.
442
        :param revision: Revision of the tree.
443
        """
0.200.776 by Jelmer Vernooij
Remove unnecessary lookups.
444
        def get_ie_sha1(entry):
445
            if entry.kind == "directory":
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
446
                try:
0.200.859 by Jelmer Vernooij
Trivial cleanups.
447
                    return self._cache.idmap.lookup_tree_id(entry.file_id,
448
                        revid)
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.
449
                except (NotImplementedError, KeyError):
0.200.855 by Jelmer Vernooij
_get_ -> _reconstruct_.
450
                    obj = self._reconstruct_tree(entry.file_id, revid, inv,
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
451
                        unusual_modes)
452
                    if obj is None:
453
                        return None
454
                    else:
455
                        return obj.id
0.200.776 by Jelmer Vernooij
Remove unnecessary lookups.
456
            elif entry.kind in ("file", "symlink"):
0.200.868 by Jelmer Vernooij
Cope with no-change merges.
457
                try:
458
                    return self._cache.idmap.lookup_blob_id(entry.file_id,
459
                        entry.revision)
460
                except KeyError:
461
                    # no-change merge?
462
                    return self._reconstruct_blobs(
463
                        [(entry.file_id, entry.revision, None)]).next().id
0.200.776 by Jelmer Vernooij
Remove unnecessary lookups.
464
            else:
465
                raise AssertionError("unknown entry kind '%s'" % entry.kind)
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
466
        tree = directory_to_tree(inv[fileid], get_ie_sha1, unusual_modes,
467
            self.mapping.BZR_DUMMY_FILE)
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
468
        if (inv.root.file_id == fileid and
469
            self.mapping.BZR_FILE_IDS_FILE is not None):
0.252.49 by Jelmer Vernooij
Avoid trying to set HEAD for remote branches.
470
            b = self._create_fileid_map_blob(inv)
471
            # If this is the root tree, add the file ids
472
            tree[self.mapping.BZR_FILE_IDS_FILE] = ((stat.S_IFREG | 0644), b.id)
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
473
        _check_expected_sha(expected_sha, tree)
0.200.249 by Jelmer Vernooij
Implement Tree.
474
        return tree
0.200.229 by Jelmer Vernooij
More work on converter.
475
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
476
    def get_parents(self, sha):
0.200.454 by Jelmer Vernooij
Use ObjectStore.find_missing_objects in server.
477
        """Retrieve the parents of a Git commit by SHA1.
478
479
        :param sha: SHA1 of the commit
480
        :raises: KeyError, NotCommitError
481
        """
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
482
        return self[sha].parents
483
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
484
    def _lookup_revision_sha1(self, revid):
0.200.449 by Jelmer Vernooij
Use BazaarObjectStore to find matching SHA1s for bzr revisions.
485
        """Return the SHA1 matching a Bazaar revision."""
0.200.891 by Jelmer Vernooij
Use ZERO_SHA constant where possible.
486
        from dulwich.protocol import ZERO_SHA
0.200.541 by Jelmer Vernooij
Cope with NULL_REVISION.
487
        if revid == NULL_REVISION:
0.200.891 by Jelmer Vernooij
Use ZERO_SHA constant where possible.
488
            return ZERO_SHA
0.200.364 by Jelmer Vernooij
Reimplement dpush, but more efficient and only writing a single pack file rather than one per revision.
489
        try:
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
490
            return self._cache.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.
491
        except KeyError:
0.200.682 by Jelmer Vernooij
Avoid doing a full sha map update if we already know the SHA1.
492
            try:
493
                return mapping_registry.parse_revision_id(revid)[0]
494
            except errors.InvalidRevisionId:
0.252.47 by Jelmer Vernooij
Fix handling of HEAD refs.
495
                self.repository.lock_read()
496
                try:
497
                    self._update_sha_map(revid)
498
                finally:
499
                    self.repository.unlock()
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
500
                return self._cache.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.
501
0.200.310 by Jelmer Vernooij
Fix pull from remote branches.
502
    def get_raw(self, sha):
0.200.454 by Jelmer Vernooij
Use ObjectStore.find_missing_objects in server.
503
        """Get the raw representation of a Git object by SHA1.
504
505
        :param sha: SHA1 of the git object
506
        """
0.200.566 by Jelmer Vernooij
Fix ObjectStore.get_raw() .
507
        obj = self[sha]
508
        return (obj.type, obj.as_raw_string())
0.200.310 by Jelmer Vernooij
Fix pull from remote branches.
509
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
510
    def __contains__(self, sha):
511
        # See if sha is in map
512
        try:
0.200.897 by Jelmer Vernooij
Make lookup_git_sha public.
513
            (type, type_data) = self.lookup_git_sha(sha)
0.200.568 by Jelmer Vernooij
Properly check that matching bzr objects exist.
514
            if type == "commit":
515
                return self.repository.has_revision(type_data[0])
516
            elif type == "blob":
0.200.964 by Jelmer Vernooij
Add some tests for object store.
517
                return self.repository.texts.has_key(type_data)
0.200.568 by Jelmer Vernooij
Properly check that matching bzr objects exist.
518
            elif type == "tree":
519
                return self.repository.has_revision(type_data[1])
520
            else:
521
                raise AssertionError("Unknown object type '%s'" % type)
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
522
        except KeyError:
523
            return False
524
0.200.898 by Jelmer Vernooij
Optimize finding of git shas.
525
    def lookup_git_shas(self, shas, update_map=True):
0.200.969 by Jelmer Vernooij
Use tuples with bzr revid and git sha to avoid lookups.
526
        from dulwich.protocol import ZERO_SHA
0.200.898 by Jelmer Vernooij
Optimize finding of git shas.
527
        ret = {}
528
        for sha in shas:
0.200.969 by Jelmer Vernooij
Use tuples with bzr revid and git sha to avoid lookups.
529
            if sha == ZERO_SHA:
0.200.985 by Jelmer Vernooij
Fix handling of ZERO_SHA in lookup_git_sha.
530
                ret[sha] = ("commit", (NULL_REVISION, None))
0.200.969 by Jelmer Vernooij
Use tuples with bzr revid and git sha to avoid lookups.
531
                continue
0.200.898 by Jelmer Vernooij
Optimize finding of git shas.
532
            try:
533
                ret[sha] = self._cache.idmap.lookup_git_sha(sha)
534
            except KeyError:
535
                if update_map:
536
                    # if not, see if there are any unconverted revisions and add
537
                    # them to the map, search for sha in map again
538
                    self._update_sha_map()
539
                    update_map = False
540
                    try:
541
                        ret[sha] = self._cache.idmap.lookup_git_sha(sha)
542
                    except KeyError:
543
                        pass
544
        return ret
545
546
    def lookup_git_sha(self, sha, update_map=True):
547
        return self.lookup_git_shas([sha], update_map=update_map)[sha]
0.200.437 by Jelmer Vernooij
Implement BazaarObjectStore.__contains__, BazaarObjectStore.iter_shas, BazaarObjectStore.get_parents.
548
549
    def __getitem__(self, sha):
0.200.849 by Jelmer Vernooij
Allow cache backends to decide when to add entries rather than adding once per commit.
550
        if self._cache.content_cache is not None:
0.200.840 by Jelmer Vernooij
Support using content cache.
551
            try:
0.200.847 by Jelmer Vernooij
Add BzrGitCache object.
552
                return self._cache.content_cache[sha]
0.200.840 by Jelmer Vernooij
Support using content cache.
553
            except KeyError:
554
                pass
0.200.897 by Jelmer Vernooij
Make lookup_git_sha public.
555
        (type, type_data) = self.lookup_git_sha(sha)
0.200.228 by Jelmer Vernooij
Split out map.
556
        # convert object to git object
0.200.229 by Jelmer Vernooij
More work on converter.
557
        if type == "commit":
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
558
            (revid, tree_sha) = type_data
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
559
            try:
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
560
                rev = self.repository.get_revision(revid)
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
561
            except errors.NoSuchRevision:
0.200.836 by Jelmer Vernooij
Allow content cache.
562
                trace.mutter('entry for %s %s in shamap: %r, but not found in '
563
                             'repository', type, sha, type_data)
0.200.478 by Jelmer Vernooij
Cope with disappeared revisions.
564
                raise KeyError(sha)
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
565
            commit = self._reconstruct_commit(rev, tree_sha, roundtrip=True)
0.200.793 by Jelmer Vernooij
Make _check_expected_sha a global fn.
566
            _check_expected_sha(sha, commit)
0.200.785 by Jelmer Vernooij
Eliminate _get_commit.
567
            return commit
0.200.229 by Jelmer Vernooij
More work on converter.
568
        elif type == "blob":
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
569
            (fileid, revision) = type_data
0.200.855 by Jelmer Vernooij
_get_ -> _reconstruct_.
570
            return self._reconstruct_blobs([(fileid, revision, sha)]).next()
0.200.229 by Jelmer Vernooij
More work on converter.
571
        elif type == "tree":
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
572
            (fileid, revid) = type_data
0.200.561 by Jelmer Vernooij
Cope with revisions pointed to by trees in the shamap disappearing.
573
            try:
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
574
                tree = self.tree_cache.revision_tree(revid)
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
575
                rev = self.repository.get_revision(revid)
0.200.561 by Jelmer Vernooij
Cope with revisions pointed to by trees in the shamap disappearing.
576
            except errors.NoSuchRevision:
577
                trace.mutter('entry for %s %s in shamap: %r, but not found in repository', type, sha, type_data)
578
                raise KeyError(sha)
0.200.556 by Jelmer Vernooij
Fix syntax error.
579
            unusual_modes = extract_unusual_modes(rev)
0.200.491 by Jelmer Vernooij
Cope with map for Tree objects becoming invalid.
580
            try:
0.200.855 by Jelmer Vernooij
_get_ -> _reconstruct_.
581
                return self._reconstruct_tree(fileid, revid, tree.inventory,
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
582
                    unusual_modes, expected_sha=sha)
0.200.491 by Jelmer Vernooij
Cope with map for Tree objects becoming invalid.
583
            except errors.NoSuchRevision:
584
                raise KeyError(sha)
0.200.228 by Jelmer Vernooij
Split out map.
585
        else:
586
            raise AssertionError("Unknown object type '%s'" % type)
0.200.782 by Jelmer Vernooij
Add custom generate_pack_contents implementation.
587
0.252.37 by Jelmer Vernooij
Factor out some common code for finding refs to send.
588
    def generate_lossy_pack_contents(self, have, want, progress=None,
589
            get_tagged=None):
590
        return self.generate_pack_contents(have, want, progress, get_tagged,
591
            lossy=True)
592
0.200.899 by Jelmer Vernooij
Add tests for find_missing_bzr_revids.
593
    def generate_pack_contents(self, have, want, progress=None,
0.252.37 by Jelmer Vernooij
Factor out some common code for finding refs to send.
594
            get_tagged=None, lossy=False):
0.200.782 by Jelmer Vernooij
Add custom generate_pack_contents implementation.
595
        """Iterate over the contents of a pack file.
596
597
        :param have: List of SHA1s of objects that should not be sent
598
        :param want: List of SHA1s of objects that should be sent
599
        """
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
600
        processed = set()
0.200.898 by Jelmer Vernooij
Optimize finding of git shas.
601
        ret = self.lookup_git_shas(have + want)
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
602
        for commit_sha in have:
603
            try:
0.200.898 by Jelmer Vernooij
Optimize finding of git shas.
604
                (type, (revid, tree_sha)) = ret[commit_sha]
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
605
            except KeyError:
606
                pass
607
            else:
608
                assert type == "commit"
609
                processed.add(revid)
610
        pending = set()
611
        for commit_sha in want:
612
            if commit_sha in have:
613
                continue
0.200.898 by Jelmer Vernooij
Optimize finding of git shas.
614
            try:
615
                (type, (revid, tree_sha)) = ret[commit_sha]
616
            except KeyError:
617
                pass
618
            else:
619
                assert type == "commit"
620
                pending.add(revid)
0.200.899 by Jelmer Vernooij
Add tests for find_missing_bzr_revids.
621
622
        todo = _find_missing_bzr_revids(self.repository.get_parent_map, 
623
                                        pending, processed)
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
624
        trace.mutter('sending revisions %r', todo)
625
        ret = []
626
        pb = ui.ui_factory.nested_progress_bar()
627
        try:
628
            for i, revid in enumerate(todo):
629
                pb.update("generating git objects", i, len(todo))
630
                rev = self.repository.get_revision(revid)
0.200.852 by Jelmer Vernooij
Cache trees rather than inventories.
631
                tree = self.tree_cache.revision_tree(revid)
0.252.37 by Jelmer Vernooij
Factor out some common code for finding refs to send.
632
                for path, obj, ie in self._revision_to_objects(rev, tree,
633
                    roundtrip=not lossy):
0.200.787 by Jelmer Vernooij
Implement custom ObjectWalker.generate_pack_contents.
634
                    ret.append((obj, path))
635
        finally:
636
            pb.finished()
637
        return ret
0.251.1 by Jelmer Vernooij
Implement ObjectStore.add_{thin_,}pack.
638
639
    def add_thin_pack(self):
640
        import tempfile
641
        import os
642
        fd, path = tempfile.mkstemp(suffix=".pack")
643
        f = os.fdopen(fd, 'wb')
644
        def commit():
645
            from dulwich.pack import PackData, Pack
646
            from bzrlib.plugins.git.fetch import import_git_objects
647
            os.fsync(fd)
648
            f.close()
649
            if os.path.getsize(path) == 0:
650
                return
651
            pd = PackData(path)
652
            pd.create_index_v2(path[:-5]+".idx", self.object_store.get_raw)
653
654
            p = Pack(path[:-5])
655
            self.repository.lock_write()
656
            try:
657
                self.repository.start_write_group()
658
                try:
659
                    import_git_objects(self.repository, self.mapping, 
660
                        p.iterobjects(get_raw=self.get_raw),
661
                        self.object_store)
662
                except:
663
                    self.repository.abort_write_group()
664
                    raise
665
                else:
666
                    self.repository.commit_write_group()
667
            finally:
668
                self.repository.unlock()
669
        return f, commit
670
671
    # The pack isn't kept around anyway, so no point 
672
    # in treating full packs different from thin packs
673
    add_pack = add_thin_pack