~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/weaverepo.py

  • Committer: Martin Pool
  • Date: 2005-09-12 09:50:44 UTC
  • Revision ID: mbp@sourcefrog.net-20050912095044-6acfdb5611729987
- no tests in bzrlib.fetch anymore

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
"""Deprecated weave-based repository formats.
18
 
 
19
 
Weave based formats scaled linearly with history size and could not represent
20
 
ghosts.
21
 
"""
22
 
 
23
 
from StringIO import StringIO
24
 
 
25
 
from bzrlib import (
26
 
    bzrdir,
27
 
    debug,
28
 
    errors,
29
 
    lockable_files,
30
 
    lockdir,
31
 
    osutils,
32
 
    revision as _mod_revision,
33
 
    weave,
34
 
    weavefile,
35
 
    xml5,
36
 
    )
37
 
from bzrlib.decorators import needs_read_lock, needs_write_lock
38
 
from bzrlib.repository import (
39
 
    CommitBuilder,
40
 
    MetaDirRepository,
41
 
    MetaDirRepositoryFormat,
42
 
    Repository,
43
 
    RepositoryFormat,
44
 
    )
45
 
from bzrlib.store.text import TextStore
46
 
from bzrlib.trace import mutter
47
 
 
48
 
 
49
 
class AllInOneRepository(Repository):
50
 
    """Legacy support - the repository behaviour for all-in-one branches."""
51
 
 
52
 
    _serializer = xml5.serializer_v5
53
 
 
54
 
    def __init__(self, _format, a_bzrdir, _revision_store, control_store, text_store):
55
 
        # we reuse one control files instance.
56
 
        dir_mode = a_bzrdir._control_files._dir_mode
57
 
        file_mode = a_bzrdir._control_files._file_mode
58
 
 
59
 
        def get_store(name, compressed=True, prefixed=False):
60
 
            # FIXME: This approach of assuming stores are all entirely compressed
61
 
            # or entirely uncompressed is tidy, but breaks upgrade from 
62
 
            # some existing branches where there's a mixture; we probably 
63
 
            # still want the option to look for both.
64
 
            relpath = a_bzrdir._control_files._escape(name)
65
 
            store = TextStore(a_bzrdir._control_files._transport.clone(relpath),
66
 
                              prefixed=prefixed, compressed=compressed,
67
 
                              dir_mode=dir_mode,
68
 
                              file_mode=file_mode)
69
 
            return store
70
 
 
71
 
        # not broken out yet because the controlweaves|inventory_store
72
 
        # and text_store | weave_store bits are still different.
73
 
        if isinstance(_format, RepositoryFormat4):
74
 
            # cannot remove these - there is still no consistent api 
75
 
            # which allows access to this old info.
76
 
            self.inventory_store = get_store('inventory-store')
77
 
            text_store = get_store('text-store')
78
 
        super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
79
 
 
80
 
    @needs_read_lock
81
 
    def _all_possible_ids(self):
82
 
        """Return all the possible revisions that we could find."""
83
 
        if 'evil' in debug.debug_flags:
84
 
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
85
 
        return self.get_inventory_weave().versions()
86
 
 
87
 
    @needs_read_lock
88
 
    def _all_revision_ids(self):
89
 
        """Returns a list of all the revision ids in the repository. 
90
 
 
91
 
        These are in as much topological order as the underlying store can 
92
 
        present: for weaves ghosts may lead to a lack of correctness until
93
 
        the reweave updates the parents list.
94
 
        """
95
 
        if self._revision_store.text_store.listable():
96
 
            return self._revision_store.all_revision_ids(self.get_transaction())
97
 
        result = self._all_possible_ids()
98
 
        # TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
99
 
        #       ids. (It should, since _revision_store's API should change to
100
 
        #       return utf8 revision_ids)
101
 
        return self._eliminate_revisions_not_present(result)
102
 
 
103
 
    def _check_revision_parents(self, revision, inventory):
104
 
        """Private to Repository and Fetch.
105
 
        
106
 
        This checks the parentage of revision in an inventory weave for 
107
 
        consistency and is only applicable to inventory-weave-for-ancestry
108
 
        using repository formats & fetchers.
109
 
        """
110
 
        weave_parents = inventory.get_parent_map(
111
 
            [revision.revision_id])[revision.revision_id]
112
 
        parent_map = inventory.get_parent_map(revision.parent_ids)
113
 
        for parent_id in revision.parent_ids:
114
 
            if parent_id in parent_map:
115
 
                # this parent must not be a ghost.
116
 
                if not parent_id in weave_parents:
117
 
                    # but it is a ghost
118
 
                    raise errors.CorruptRepository(self)
119
 
 
120
 
    def get_commit_builder(self, branch, parents, config, timestamp=None,
121
 
                           timezone=None, committer=None, revprops=None,
122
 
                           revision_id=None):
123
 
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
124
 
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
125
 
                              committer, revprops, revision_id)
126
 
        self.start_write_group()
127
 
        return result
128
 
 
129
 
    @needs_read_lock
130
 
    def get_revisions(self, revision_ids):
131
 
        revs = self._get_revisions(revision_ids)
132
 
        # weave corruption can lead to absent revision markers that should be
133
 
        # present.
134
 
        # the following test is reasonably cheap (it needs a single weave read)
135
 
        # and the weave is cached in read transactions. In write transactions
136
 
        # it is not cached but typically we only read a small number of
137
 
        # revisions. For knits when they are introduced we will probably want
138
 
        # to ensure that caching write transactions are in use.
139
 
        inv = self.get_inventory_weave()
140
 
        for rev in revs:
141
 
            self._check_revision_parents(rev, inv)
142
 
        return revs
143
 
 
144
 
    @needs_read_lock
145
 
    def get_revision_graph(self, revision_id=None):
146
 
        """Return a dictionary containing the revision graph.
147
 
        
148
 
        :param revision_id: The revision_id to get a graph from. If None, then
149
 
        the entire revision graph is returned. This is a deprecated mode of
150
 
        operation and will be removed in the future.
151
 
        :return: a dictionary of revision_id->revision_parents_list.
152
 
        """
153
 
        if 'evil' in debug.debug_flags:
154
 
            mutter_callsite(2,
155
 
                "get_revision_graph scales with size of history.")
156
 
        # special case NULL_REVISION
157
 
        if revision_id == _mod_revision.NULL_REVISION:
158
 
            return {}
159
 
        a_weave = self.get_inventory_weave()
160
 
        all_revisions = self._eliminate_revisions_not_present(
161
 
                                a_weave.versions())
162
 
        entire_graph = a_weave.get_parent_map(all_revisions)
163
 
        if revision_id is None:
164
 
            return entire_graph
165
 
        elif revision_id not in entire_graph:
166
 
            raise errors.NoSuchRevision(self, revision_id)
167
 
        else:
168
 
            # add what can be reached from revision_id
169
 
            result = {}
170
 
            pending = set([revision_id])
171
 
            while len(pending) > 0:
172
 
                node = pending.pop()
173
 
                result[node] = entire_graph[node]
174
 
                for revision_id in result[node]:
175
 
                    if revision_id not in result:
176
 
                        pending.add(revision_id)
177
 
            return result
178
 
 
179
 
    def has_revisions(self, revision_ids):
180
 
        """See Repository.has_revisions()."""
181
 
        result = set()
182
 
        transaction = self.get_transaction()
183
 
        for revision_id in revision_ids:
184
 
            if self._revision_store.has_revision_id(revision_id, transaction):
185
 
                result.add(revision_id)
186
 
        return result
187
 
 
188
 
    @needs_read_lock
189
 
    def is_shared(self):
190
 
        """AllInOne repositories cannot be shared."""
191
 
        return False
192
 
 
193
 
    @needs_write_lock
194
 
    def set_make_working_trees(self, new_value):
195
 
        """Set the policy flag for making working trees when creating branches.
196
 
 
197
 
        This only applies to branches that use this repository.
198
 
 
199
 
        The default is 'True'.
200
 
        :param new_value: True to restore the default, False to disable making
201
 
                          working trees.
202
 
        """
203
 
        raise NotImplementedError(self.set_make_working_trees)
204
 
    
205
 
    def make_working_trees(self):
206
 
        """Returns the policy for making working trees on new branches."""
207
 
        return True
208
 
 
209
 
    def revision_graph_can_have_wrong_parents(self):
210
 
        # XXX: This is an old format that we don't support full checking on, so
211
 
        # just claim that checking for this inconsistency is not required.
212
 
        return False
213
 
 
214
 
 
215
 
class WeaveMetaDirRepository(MetaDirRepository):
216
 
    """A subclass of MetaDirRepository to set weave specific policy."""
217
 
 
218
 
    _serializer = xml5.serializer_v5
219
 
 
220
 
    @needs_read_lock
221
 
    def _all_possible_ids(self):
222
 
        """Return all the possible revisions that we could find."""
223
 
        if 'evil' in debug.debug_flags:
224
 
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
225
 
        return self.get_inventory_weave().versions()
226
 
 
227
 
    @needs_read_lock
228
 
    def _all_revision_ids(self):
229
 
        """Returns a list of all the revision ids in the repository. 
230
 
 
231
 
        These are in as much topological order as the underlying store can 
232
 
        present: for weaves ghosts may lead to a lack of correctness until
233
 
        the reweave updates the parents list.
234
 
        """
235
 
        if self._revision_store.text_store.listable():
236
 
            return self._revision_store.all_revision_ids(self.get_transaction())
237
 
        result = self._all_possible_ids()
238
 
        # TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
239
 
        #       ids. (It should, since _revision_store's API should change to
240
 
        #       return utf8 revision_ids)
241
 
        return self._eliminate_revisions_not_present(result)
242
 
 
243
 
    def _check_revision_parents(self, revision, inventory):
244
 
        """Private to Repository and Fetch.
245
 
        
246
 
        This checks the parentage of revision in an inventory weave for 
247
 
        consistency and is only applicable to inventory-weave-for-ancestry
248
 
        using repository formats & fetchers.
249
 
        """
250
 
        weave_parents = inventory.get_parent_map(
251
 
            [revision.revision_id])[revision.revision_id]
252
 
        parent_map = inventory.get_parent_map(revision.parent_ids)
253
 
        for parent_id in revision.parent_ids:
254
 
            if parent_id in parent_map:
255
 
                # this parent must not be a ghost.
256
 
                if not parent_id in weave_parents:
257
 
                    # but it is a ghost
258
 
                    raise errors.CorruptRepository(self)
259
 
 
260
 
    def get_commit_builder(self, branch, parents, config, timestamp=None,
261
 
                           timezone=None, committer=None, revprops=None,
262
 
                           revision_id=None):
263
 
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
264
 
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
265
 
                              committer, revprops, revision_id)
266
 
        self.start_write_group()
267
 
        return result
268
 
 
269
 
    @needs_read_lock
270
 
    def get_revision(self, revision_id):
271
 
        """Return the Revision object for a named revision"""
272
 
        # TODO: jam 20070210 get_revision_reconcile should do this for us
273
 
        r = self.get_revision_reconcile(revision_id)
274
 
        # weave corruption can lead to absent revision markers that should be
275
 
        # present.
276
 
        # the following test is reasonably cheap (it needs a single weave read)
277
 
        # and the weave is cached in read transactions. In write transactions
278
 
        # it is not cached but typically we only read a small number of
279
 
        # revisions. For knits when they are introduced we will probably want
280
 
        # to ensure that caching write transactions are in use.
281
 
        inv = self.get_inventory_weave()
282
 
        self._check_revision_parents(r, inv)
283
 
        return r
284
 
 
285
 
    @needs_read_lock
286
 
    def get_revision_graph(self, revision_id=None):
287
 
        """Return a dictionary containing the revision graph.
288
 
        
289
 
        :param revision_id: The revision_id to get a graph from. If None, then
290
 
        the entire revision graph is returned. This is a deprecated mode of
291
 
        operation and will be removed in the future.
292
 
        :return: a dictionary of revision_id->revision_parents_list.
293
 
        """
294
 
        if 'evil' in debug.debug_flags:
295
 
            mutter_callsite(3,
296
 
                "get_revision_graph scales with size of history.")
297
 
        # special case NULL_REVISION
298
 
        if revision_id == _mod_revision.NULL_REVISION:
299
 
            return {}
300
 
        a_weave = self.get_inventory_weave()
301
 
        all_revisions = self._eliminate_revisions_not_present(
302
 
                                a_weave.versions())
303
 
        entire_graph = a_weave.get_parent_map(all_revisions)
304
 
        if revision_id is None:
305
 
            return entire_graph
306
 
        elif revision_id not in entire_graph:
307
 
            raise errors.NoSuchRevision(self, revision_id)
308
 
        else:
309
 
            # add what can be reached from revision_id
310
 
            result = {}
311
 
            pending = set([revision_id])
312
 
            while len(pending) > 0:
313
 
                node = pending.pop()
314
 
                result[node] = entire_graph[node]
315
 
                for revision_id in result[node]:
316
 
                    if revision_id not in result:
317
 
                        pending.add(revision_id)
318
 
            return result
319
 
 
320
 
    def has_revisions(self, revision_ids):
321
 
        """See Repository.has_revisions()."""
322
 
        result = set()
323
 
        transaction = self.get_transaction()
324
 
        for revision_id in revision_ids:
325
 
            if self._revision_store.has_revision_id(revision_id, transaction):
326
 
                result.add(revision_id)
327
 
        return result
328
 
 
329
 
    def revision_graph_can_have_wrong_parents(self):
330
 
        # XXX: This is an old format that we don't support full checking on, so
331
 
        # just claim that checking for this inconsistency is not required.
332
 
        return False
333
 
 
334
 
 
335
 
class PreSplitOutRepositoryFormat(RepositoryFormat):
336
 
    """Base class for the pre split out repository formats."""
337
 
 
338
 
    rich_root_data = False
339
 
    supports_tree_reference = False
340
 
    supports_ghosts = False
341
 
    supports_external_lookups = False
342
 
 
343
 
    def initialize(self, a_bzrdir, shared=False, _internal=False):
344
 
        """Create a weave repository."""
345
 
        if shared:
346
 
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
347
 
 
348
 
        if not _internal:
349
 
            # always initialized when the bzrdir is.
350
 
            return self.open(a_bzrdir, _found=True)
351
 
        
352
 
        # Create an empty weave
353
 
        sio = StringIO()
354
 
        weavefile.write_weave_v5(weave.Weave(), sio)
355
 
        empty_weave = sio.getvalue()
356
 
 
357
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
358
 
        dirs = ['revision-store', 'weaves']
359
 
        files = [('inventory.weave', StringIO(empty_weave)),
360
 
                 ]
361
 
        
362
 
        # FIXME: RBC 20060125 don't peek under the covers
363
 
        # NB: no need to escape relative paths that are url safe.
364
 
        control_files = lockable_files.LockableFiles(a_bzrdir.transport,
365
 
                                'branch-lock', lockable_files.TransportLock)
366
 
        control_files.create_lock()
367
 
        control_files.lock_write()
368
 
        control_files._transport.mkdir_multi(dirs,
369
 
                mode=control_files._dir_mode)
370
 
        try:
371
 
            for file, content in files:
372
 
                control_files.put(file, content)
373
 
        finally:
374
 
            control_files.unlock()
375
 
        return self.open(a_bzrdir, _found=True)
376
 
 
377
 
    def _get_control_store(self, repo_transport, control_files):
378
 
        """Return the control store for this repository."""
379
 
        return self._get_versioned_file_store('',
380
 
                                              repo_transport,
381
 
                                              control_files,
382
 
                                              prefixed=False)
383
 
 
384
 
    def _get_text_store(self, transport, control_files):
385
 
        """Get a store for file texts for this format."""
386
 
        raise NotImplementedError(self._get_text_store)
387
 
 
388
 
    def open(self, a_bzrdir, _found=False):
389
 
        """See RepositoryFormat.open()."""
390
 
        if not _found:
391
 
            # we are being called directly and must probe.
392
 
            raise NotImplementedError
393
 
 
394
 
        repo_transport = a_bzrdir.get_repository_transport(None)
395
 
        control_files = a_bzrdir._control_files
396
 
        text_store = self._get_text_store(repo_transport, control_files)
397
 
        control_store = self._get_control_store(repo_transport, control_files)
398
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
399
 
        return AllInOneRepository(_format=self,
400
 
                                  a_bzrdir=a_bzrdir,
401
 
                                  _revision_store=_revision_store,
402
 
                                  control_store=control_store,
403
 
                                  text_store=text_store)
404
 
 
405
 
    def check_conversion_target(self, target_format):
406
 
        pass
407
 
 
408
 
 
409
 
class RepositoryFormat4(PreSplitOutRepositoryFormat):
410
 
    """Bzr repository format 4.
411
 
 
412
 
    This repository format has:
413
 
     - flat stores
414
 
     - TextStores for texts, inventories,revisions.
415
 
 
416
 
    This format is deprecated: it indexes texts using a text id which is
417
 
    removed in format 5; initialization and write support for this format
418
 
    has been removed.
419
 
    """
420
 
 
421
 
    _matchingbzrdir = bzrdir.BzrDirFormat4()
422
 
 
423
 
    def __init__(self):
424
 
        super(RepositoryFormat4, self).__init__()
425
 
 
426
 
    def get_format_description(self):
427
 
        """See RepositoryFormat.get_format_description()."""
428
 
        return "Repository format 4"
429
 
 
430
 
    def initialize(self, url, shared=False, _internal=False):
431
 
        """Format 4 branches cannot be created."""
432
 
        raise errors.UninitializableFormat(self)
433
 
 
434
 
    def is_supported(self):
435
 
        """Format 4 is not supported.
436
 
 
437
 
        It is not supported because the model changed from 4 to 5 and the
438
 
        conversion logic is expensive - so doing it on the fly was not 
439
 
        feasible.
440
 
        """
441
 
        return False
442
 
 
443
 
    def _get_control_store(self, repo_transport, control_files):
444
 
        """Format 4 repositories have no formal control store at this point.
445
 
        
446
 
        This will cause any control-file-needing apis to fail - this is desired.
447
 
        """
448
 
        return None
449
 
    
450
 
    def _get_revision_store(self, repo_transport, control_files):
451
 
        """See RepositoryFormat._get_revision_store()."""
452
 
        from bzrlib.xml4 import serializer_v4
453
 
        return self._get_text_rev_store(repo_transport,
454
 
                                        control_files,
455
 
                                        'revision-store',
456
 
                                        serializer=serializer_v4)
457
 
 
458
 
    def _get_text_store(self, transport, control_files):
459
 
        """See RepositoryFormat._get_text_store()."""
460
 
 
461
 
 
462
 
class RepositoryFormat5(PreSplitOutRepositoryFormat):
463
 
    """Bzr control format 5.
464
 
 
465
 
    This repository format has:
466
 
     - weaves for file texts and inventory
467
 
     - flat stores
468
 
     - TextStores for revisions and signatures.
469
 
    """
470
 
 
471
 
    _versionedfile_class = weave.WeaveFile
472
 
    _matchingbzrdir = bzrdir.BzrDirFormat5()
473
 
 
474
 
    def __init__(self):
475
 
        super(RepositoryFormat5, self).__init__()
476
 
 
477
 
    def get_format_description(self):
478
 
        """See RepositoryFormat.get_format_description()."""
479
 
        return "Weave repository format 5"
480
 
 
481
 
    def _get_revision_store(self, repo_transport, control_files):
482
 
        """See RepositoryFormat._get_revision_store()."""
483
 
        """Return the revision store object for this a_bzrdir."""
484
 
        return self._get_text_rev_store(repo_transport,
485
 
                                        control_files,
486
 
                                        'revision-store',
487
 
                                        compressed=False)
488
 
 
489
 
    def _get_text_store(self, transport, control_files):
490
 
        """See RepositoryFormat._get_text_store()."""
491
 
        return self._get_versioned_file_store('weaves', transport, control_files, prefixed=False)
492
 
 
493
 
 
494
 
class RepositoryFormat6(PreSplitOutRepositoryFormat):
495
 
    """Bzr control format 6.
496
 
 
497
 
    This repository format has:
498
 
     - weaves for file texts and inventory
499
 
     - hash subdirectory based stores.
500
 
     - TextStores for revisions and signatures.
501
 
    """
502
 
 
503
 
    _versionedfile_class = weave.WeaveFile
504
 
    _matchingbzrdir = bzrdir.BzrDirFormat6()
505
 
 
506
 
    def __init__(self):
507
 
        super(RepositoryFormat6, self).__init__()
508
 
 
509
 
    def get_format_description(self):
510
 
        """See RepositoryFormat.get_format_description()."""
511
 
        return "Weave repository format 6"
512
 
 
513
 
    def _get_revision_store(self, repo_transport, control_files):
514
 
        """See RepositoryFormat._get_revision_store()."""
515
 
        return self._get_text_rev_store(repo_transport,
516
 
                                        control_files,
517
 
                                        'revision-store',
518
 
                                        compressed=False,
519
 
                                        prefixed=True)
520
 
 
521
 
    def _get_text_store(self, transport, control_files):
522
 
        """See RepositoryFormat._get_text_store()."""
523
 
        return self._get_versioned_file_store('weaves', transport, control_files)
524
 
 
525
 
class RepositoryFormat7(MetaDirRepositoryFormat):
526
 
    """Bzr repository 7.
527
 
 
528
 
    This repository format has:
529
 
     - weaves for file texts and inventory
530
 
     - hash subdirectory based stores.
531
 
     - TextStores for revisions and signatures.
532
 
     - a format marker of its own
533
 
     - an optional 'shared-storage' flag
534
 
     - an optional 'no-working-trees' flag
535
 
    """
536
 
 
537
 
    _versionedfile_class = weave.WeaveFile
538
 
    supports_ghosts = False
539
 
 
540
 
    def _get_control_store(self, repo_transport, control_files):
541
 
        """Return the control store for this repository."""
542
 
        return self._get_versioned_file_store('',
543
 
                                              repo_transport,
544
 
                                              control_files,
545
 
                                              prefixed=False)
546
 
 
547
 
    def get_format_string(self):
548
 
        """See RepositoryFormat.get_format_string()."""
549
 
        return "Bazaar-NG Repository format 7"
550
 
 
551
 
    def get_format_description(self):
552
 
        """See RepositoryFormat.get_format_description()."""
553
 
        return "Weave repository format 7"
554
 
 
555
 
    def check_conversion_target(self, target_format):
556
 
        pass
557
 
 
558
 
    def _get_revision_store(self, repo_transport, control_files):
559
 
        """See RepositoryFormat._get_revision_store()."""
560
 
        return self._get_text_rev_store(repo_transport,
561
 
                                        control_files,
562
 
                                        'revision-store',
563
 
                                        compressed=False,
564
 
                                        prefixed=True,
565
 
                                        )
566
 
 
567
 
    def _get_text_store(self, transport, control_files):
568
 
        """See RepositoryFormat._get_text_store()."""
569
 
        return self._get_versioned_file_store('weaves',
570
 
                                              transport,
571
 
                                              control_files)
572
 
 
573
 
    def initialize(self, a_bzrdir, shared=False):
574
 
        """Create a weave repository.
575
 
 
576
 
        :param shared: If true the repository will be initialized as a shared
577
 
                       repository.
578
 
        """
579
 
        # Create an empty weave
580
 
        sio = StringIO()
581
 
        weavefile.write_weave_v5(weave.Weave(), sio)
582
 
        empty_weave = sio.getvalue()
583
 
 
584
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
585
 
        dirs = ['revision-store', 'weaves']
586
 
        files = [('inventory.weave', StringIO(empty_weave)), 
587
 
                 ]
588
 
        utf8_files = [('format', self.get_format_string())]
589
 
 
590
 
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
591
 
        return self.open(a_bzrdir=a_bzrdir, _found=True)
592
 
 
593
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
594
 
        """See RepositoryFormat.open().
595
 
        
596
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
597
 
                                    repository at a slightly different url
598
 
                                    than normal. I.e. during 'upgrade'.
599
 
        """
600
 
        if not _found:
601
 
            format = RepositoryFormat.find_format(a_bzrdir)
602
 
            assert format.__class__ ==  self.__class__
603
 
        if _override_transport is not None:
604
 
            repo_transport = _override_transport
605
 
        else:
606
 
            repo_transport = a_bzrdir.get_repository_transport(None)
607
 
        control_files = lockable_files.LockableFiles(repo_transport,
608
 
                                'lock', lockdir.LockDir)
609
 
        text_store = self._get_text_store(repo_transport, control_files)
610
 
        control_store = self._get_control_store(repo_transport, control_files)
611
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
612
 
        return WeaveMetaDirRepository(_format=self,
613
 
            a_bzrdir=a_bzrdir,
614
 
            control_files=control_files,
615
 
            _revision_store=_revision_store,
616
 
            control_store=control_store,
617
 
            text_store=text_store)
618
 
 
619
 
 
620
 
class WeaveCommitBuilder(CommitBuilder):
621
 
    """A builder for weave based repos that don't support ghosts."""
622
 
 
623
 
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
624
 
        versionedfile = self.repository.weave_store.get_weave_or_empty(
625
 
            file_id, self.repository.get_transaction())
626
 
        result = versionedfile.add_lines(
627
 
            self._new_revision_id, parents, new_lines,
628
 
            nostore_sha=nostore_sha)[0:2]
629
 
        versionedfile.clear_cache()
630
 
        return result
631
 
 
632
 
 
633
 
_legacy_formats = [RepositoryFormat4(),
634
 
                   RepositoryFormat5(),
635
 
                   RepositoryFormat6()]