~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/weaverepo.py

  • Committer: Alexander Belchenko
  • Date: 2008-03-12 21:07:46 UTC
  • mto: This revision was merged to the branch mainline in revision 3272.
  • Revision ID: bialix@ukr.net-20080312210746-39xx932qcb92g3lj
Significantly reducing execution time and network traffic for trivial case of `bzr missing`

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_parents(revision.revision_id)
 
111
        weave_names = inventory.versions()
 
112
        for parent_id in revision.parent_ids:
 
113
            if parent_id in weave_names:
 
114
                # this parent must not be a ghost.
 
115
                if not parent_id in weave_parents:
 
116
                    # but it is a ghost
 
117
                    raise errors.CorruptRepository(self)
 
118
 
 
119
    def get_commit_builder(self, branch, parents, config, timestamp=None,
 
120
                           timezone=None, committer=None, revprops=None,
 
121
                           revision_id=None):
 
122
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
 
123
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
 
124
                              committer, revprops, revision_id)
 
125
        self.start_write_group()
 
126
        return result
 
127
 
 
128
    @needs_read_lock
 
129
    def get_revisions(self, revision_ids):
 
130
        revs = self._get_revisions(revision_ids)
 
131
        # weave corruption can lead to absent revision markers that should be
 
132
        # present.
 
133
        # the following test is reasonably cheap (it needs a single weave read)
 
134
        # and the weave is cached in read transactions. In write transactions
 
135
        # it is not cached but typically we only read a small number of
 
136
        # revisions. For knits when they are introduced we will probably want
 
137
        # to ensure that caching write transactions are in use.
 
138
        inv = self.get_inventory_weave()
 
139
        for rev in revs:
 
140
            self._check_revision_parents(rev, inv)
 
141
        return revs
 
142
 
 
143
    @needs_read_lock
 
144
    def get_revision_graph(self, revision_id=None):
 
145
        """Return a dictionary containing the revision graph.
 
146
        
 
147
        :param revision_id: The revision_id to get a graph from. If None, then
 
148
        the entire revision graph is returned. This is a deprecated mode of
 
149
        operation and will be removed in the future.
 
150
        :return: a dictionary of revision_id->revision_parents_list.
 
151
        """
 
152
        if 'evil' in debug.debug_flags:
 
153
            mutter_callsite(2,
 
154
                "get_revision_graph scales with size of history.")
 
155
        # special case NULL_REVISION
 
156
        if revision_id == _mod_revision.NULL_REVISION:
 
157
            return {}
 
158
        a_weave = self.get_inventory_weave()
 
159
        all_revisions = self._eliminate_revisions_not_present(
 
160
                                a_weave.versions())
 
161
        entire_graph = dict([(node, tuple(a_weave.get_parents(node))) for 
 
162
                             node in 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_parents(revision.revision_id)
 
251
        weave_names = inventory.versions()
 
252
        for parent_id in revision.parent_ids:
 
253
            if parent_id in weave_names:
 
254
                # this parent must not be a ghost.
 
255
                if not parent_id in weave_parents:
 
256
                    # but it is a ghost
 
257
                    raise errors.CorruptRepository(self)
 
258
 
 
259
    def get_commit_builder(self, branch, parents, config, timestamp=None,
 
260
                           timezone=None, committer=None, revprops=None,
 
261
                           revision_id=None):
 
262
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
 
263
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
 
264
                              committer, revprops, revision_id)
 
265
        self.start_write_group()
 
266
        return result
 
267
 
 
268
    @needs_read_lock
 
269
    def get_revision(self, revision_id):
 
270
        """Return the Revision object for a named revision"""
 
271
        # TODO: jam 20070210 get_revision_reconcile should do this for us
 
272
        r = self.get_revision_reconcile(revision_id)
 
273
        # weave corruption can lead to absent revision markers that should be
 
274
        # present.
 
275
        # the following test is reasonably cheap (it needs a single weave read)
 
276
        # and the weave is cached in read transactions. In write transactions
 
277
        # it is not cached but typically we only read a small number of
 
278
        # revisions. For knits when they are introduced we will probably want
 
279
        # to ensure that caching write transactions are in use.
 
280
        inv = self.get_inventory_weave()
 
281
        self._check_revision_parents(r, inv)
 
282
        return r
 
283
 
 
284
    @needs_read_lock
 
285
    def get_revision_graph(self, revision_id=None):
 
286
        """Return a dictionary containing the revision graph.
 
287
        
 
288
        :param revision_id: The revision_id to get a graph from. If None, then
 
289
        the entire revision graph is returned. This is a deprecated mode of
 
290
        operation and will be removed in the future.
 
291
        :return: a dictionary of revision_id->revision_parents_list.
 
292
        """
 
293
        if 'evil' in debug.debug_flags:
 
294
            mutter_callsite(3,
 
295
                "get_revision_graph scales with size of history.")
 
296
        # special case NULL_REVISION
 
297
        if revision_id == _mod_revision.NULL_REVISION:
 
298
            return {}
 
299
        a_weave = self.get_inventory_weave()
 
300
        all_revisions = self._eliminate_revisions_not_present(
 
301
                                a_weave.versions())
 
302
        entire_graph = dict([(node, tuple(a_weave.get_parents(node))) for 
 
303
                             node in 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()]