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