~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/knitrepo.py

  • Committer: Aaron Bentley
  • Date: 2007-07-04 23:38:26 UTC
  • mto: This revision was merged to the branch mainline in revision 2631.
  • Revision ID: aaron.bentley@utoronto.ca-20070704233826-jkp63376wi1n96mm
update docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
from bzrlib.lazy_import import lazy_import
18
 
lazy_import(globals(), """
19
 
from bzrlib import (
20
 
    debug,
21
 
    )
22
 
from bzrlib.store import revision
23
 
from bzrlib.store.revision.knit import KnitRevisionStore
24
 
""")
25
17
from bzrlib import (
26
18
    bzrdir,
 
19
    deprecated_graph,
27
20
    errors,
28
21
    knit,
29
22
    lockable_files,
30
23
    lockdir,
31
24
    osutils,
32
 
    symbol_versioning,
33
25
    transactions,
34
26
    xml5,
35
 
    xml6,
36
27
    xml7,
37
28
    )
 
29
 
38
30
from bzrlib.decorators import needs_read_lock, needs_write_lock
39
 
from bzrlib.knit import KnitVersionedFiles, _KndxIndex, _KnitKeyAccess
40
31
from bzrlib.repository import (
41
 
    CommitBuilder,
42
32
    MetaDirRepository,
43
33
    MetaDirRepositoryFormat,
44
34
    RepositoryFormat,
46
36
    )
47
37
import bzrlib.revision as _mod_revision
48
38
from bzrlib.store.versioned import VersionedFileStore
49
 
from bzrlib.trace import mutter, mutter_callsite
50
 
from bzrlib.util import bencode
51
 
from bzrlib.versionedfile import ConstantMapper, HashEscapedPrefixMapper
 
39
from bzrlib.trace import mutter, note, warning
52
40
 
53
41
 
54
42
class _KnitParentsProvider(object):
59
47
    def __repr__(self):
60
48
        return 'KnitParentsProvider(%r)' % self._knit
61
49
 
62
 
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
63
50
    def get_parents(self, revision_ids):
64
 
        """See graph._StackedParentsProvider.get_parents"""
65
 
        parent_map = self.get_parent_map(revision_ids)
66
 
        return [parent_map.get(r, None) for r in revision_ids]
67
 
 
68
 
    def get_parent_map(self, keys):
69
 
        """See graph._StackedParentsProvider.get_parent_map"""
70
 
        parent_map = {}
71
 
        for revision_id in keys:
72
 
            if revision_id is None:
73
 
                raise ValueError('get_parent_map(None) is not valid')
 
51
        parents_list = []
 
52
        for revision_id in revision_ids:
74
53
            if revision_id == _mod_revision.NULL_REVISION:
75
 
                parent_map[revision_id] = ()
 
54
                parents = []
76
55
            else:
77
56
                try:
78
 
                    parents = tuple(
79
 
                        self._knit.get_parents_with_ghosts(revision_id))
 
57
                    parents = self._knit.get_parents_with_ghosts(revision_id)
80
58
                except errors.RevisionNotPresent:
81
 
                    continue
 
59
                    parents = None
82
60
                else:
83
61
                    if len(parents) == 0:
84
 
                        parents = (_mod_revision.NULL_REVISION,)
85
 
                parent_map[revision_id] = parents
86
 
        return parent_map
87
 
 
88
 
 
89
 
class _KnitsParentsProvider(object):
90
 
 
91
 
    def __init__(self, knit, prefix=()):
92
 
        """Create a parent provider for string keys mapped to tuple keys."""
93
 
        self._knit = knit
94
 
        self._prefix = prefix
95
 
 
96
 
    def __repr__(self):
97
 
        return 'KnitsParentsProvider(%r)' % self._knit
98
 
 
99
 
    def get_parent_map(self, keys):
100
 
        """See graph._StackedParentsProvider.get_parent_map"""
101
 
        parent_map = self._knit.get_parent_map(
102
 
            [self._prefix + (key,) for key in keys])
103
 
        result = {}
104
 
        for key, parents in parent_map.items():
105
 
            revid = key[-1]
106
 
            if len(parents) == 0:
107
 
                parents = (_mod_revision.NULL_REVISION,)
108
 
            else:
109
 
                parents = tuple(parent[-1] for parent in parents)
110
 
            result[revid] = parents
111
 
        for revision_id in keys:
112
 
            if revision_id == _mod_revision.NULL_REVISION:
113
 
                result[revision_id] = ()
114
 
        return result
 
62
                        parents = [_mod_revision.NULL_REVISION]
 
63
            parents_list.append(parents)
 
64
        return parents_list
115
65
 
116
66
 
117
67
class KnitRepository(MetaDirRepository):
118
68
    """Knit format repository."""
119
69
 
120
 
    # These attributes are inherited from the Repository base class. Setting
121
 
    # them to None ensures that if the constructor is changed to not initialize
122
 
    # them, or a subclass fails to call the constructor, that an error will
123
 
    # occur rather than the system working but generating incorrect data.
124
 
    _commit_builder_class = None
125
 
    _serializer = None
126
 
 
127
 
    def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
128
 
        _serializer):
129
 
        MetaDirRepository.__init__(self, _format, a_bzrdir, control_files)
130
 
        self._commit_builder_class = _commit_builder_class
131
 
        self._serializer = _serializer
132
 
        self._reconcile_fixes_text_parents = True
133
 
        self._fetch_uses_deltas = True
134
 
        self._fetch_order = 'topological'
 
70
    _serializer = xml5.serializer_v5
 
71
 
 
72
    def _warn_if_deprecated(self):
 
73
        # This class isn't deprecated
 
74
        pass
 
75
 
 
76
    def _inventory_add_lines(self, inv_vf, revid, parents, lines):
 
77
        inv_vf.add_lines_with_ghosts(revid, parents, lines)
135
78
 
136
79
    @needs_read_lock
137
80
    def _all_revision_ids(self):
138
81
        """See Repository.all_revision_ids()."""
139
 
        return [key[0] for key in self.revisions.keys()]
140
 
 
141
 
    def _activate_new_inventory(self):
142
 
        """Put a replacement inventory.new into use as inventories."""
143
 
        # Copy the content across
144
 
        t = self._transport
145
 
        t.copy('inventory.new.kndx', 'inventory.kndx')
146
 
        try:
147
 
            t.copy('inventory.new.knit', 'inventory.knit')
148
 
        except errors.NoSuchFile:
149
 
            # empty inventories knit
150
 
            t.delete('inventory.knit')
151
 
        # delete the temp inventory
152
 
        t.delete('inventory.new.kndx')
153
 
        try:
154
 
            t.delete('inventory.new.knit')
155
 
        except errors.NoSuchFile:
156
 
            # empty inventories knit
157
 
            pass
158
 
        # Force index reload (sanity check)
159
 
        self.inventories._index._reset_cache()
160
 
        self.inventories.keys()
161
 
 
162
 
    def _backup_inventory(self):
163
 
        t = self._transport
164
 
        t.copy('inventory.kndx', 'inventory.backup.kndx')
165
 
        t.copy('inventory.knit', 'inventory.backup.knit')
166
 
 
167
 
    def _move_file_id(self, from_id, to_id):
168
 
        t = self._transport.clone('knits')
169
 
        from_rel_url = self.texts._index._mapper.map((from_id, None))
170
 
        to_rel_url = self.texts._index._mapper.map((to_id, None))
171
 
        # We expect both files to always exist in this case.
172
 
        for suffix in ('.knit', '.kndx'):
173
 
            t.rename(from_rel_url + suffix, to_rel_url + suffix)
174
 
 
175
 
    def _remove_file_id(self, file_id):
176
 
        t = self._transport.clone('knits')
177
 
        rel_url = self.texts._index._mapper.map((file_id, None))
178
 
        for suffix in ('.kndx', '.knit'):
179
 
            try:
180
 
                t.delete(rel_url + suffix)
181
 
            except errors.NoSuchFile:
182
 
                pass
183
 
 
184
 
    def _temp_inventories(self):
185
 
        result = self._format._get_inventories(self._transport, self,
186
 
            'inventory.new')
187
 
        # Reconciling when the output has no revisions would result in no
188
 
        # writes - but we want to ensure there is an inventory for
189
 
        # compatibility with older clients that don't lazy-load.
190
 
        result.get_parent_map([('A',)])
191
 
        return result
 
82
        # Knits get the revision graph from the index of the revision knit, so
 
83
        # it's always possible even if they're on an unlistable transport.
 
84
        return self._revision_store.all_revision_ids(self.get_transaction())
192
85
 
193
86
    def fileid_involved_between_revs(self, from_revid, to_revid):
194
87
        """Find file_id(s) which are involved in the changes between revisions.
196
89
        This determines the set of revisions which are involved, and then
197
90
        finds all file ids affected by those revisions.
198
91
        """
 
92
        from_revid = osutils.safe_revision_id(from_revid)
 
93
        to_revid = osutils.safe_revision_id(to_revid)
199
94
        vf = self._get_revision_vf()
200
95
        from_set = set(vf.get_ancestry(from_revid))
201
96
        to_set = set(vf.get_ancestry(to_revid))
216
111
        return self._fileid_involved_by_set(changed)
217
112
 
218
113
    @needs_read_lock
 
114
    def get_ancestry(self, revision_id, topo_sorted=True):
 
115
        """Return a list of revision-ids integrated by a revision.
 
116
        
 
117
        This is topologically sorted, unless 'topo_sorted' is specified as
 
118
        False.
 
119
        """
 
120
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
 
121
            return [None]
 
122
        revision_id = osutils.safe_revision_id(revision_id)
 
123
        vf = self._get_revision_vf()
 
124
        try:
 
125
            return [None] + vf.get_ancestry(revision_id, topo_sorted)
 
126
        except errors.RevisionNotPresent:
 
127
            raise errors.NoSuchRevision(self, revision_id)
 
128
 
 
129
    @needs_read_lock
219
130
    def get_revision(self, revision_id):
220
131
        """Return the Revision object for a named revision"""
221
132
        revision_id = osutils.safe_revision_id(revision_id)
222
133
        return self.get_revision_reconcile(revision_id)
223
134
 
 
135
    @needs_read_lock
 
136
    def get_revision_graph(self, revision_id=None):
 
137
        """Return a dictionary containing the revision graph.
 
138
 
 
139
        :param revision_id: The revision_id to get a graph from. If None, then
 
140
        the entire revision graph is returned. This is a deprecated mode of
 
141
        operation and will be removed in the future.
 
142
        :return: a dictionary of revision_id->revision_parents_list.
 
143
        """
 
144
        # special case NULL_REVISION
 
145
        if revision_id == _mod_revision.NULL_REVISION:
 
146
            return {}
 
147
        revision_id = osutils.safe_revision_id(revision_id)
 
148
        a_weave = self._get_revision_vf()
 
149
        entire_graph = a_weave.get_graph()
 
150
        if revision_id is None:
 
151
            return a_weave.get_graph()
 
152
        elif revision_id not in a_weave:
 
153
            raise errors.NoSuchRevision(self, revision_id)
 
154
        else:
 
155
            # add what can be reached from revision_id
 
156
            result = {}
 
157
            pending = set([revision_id])
 
158
            while len(pending) > 0:
 
159
                node = pending.pop()
 
160
                result[node] = a_weave.get_parents(node)
 
161
                for revision_id in result[node]:
 
162
                    if revision_id not in result:
 
163
                        pending.add(revision_id)
 
164
            return result
 
165
 
 
166
    @needs_read_lock
 
167
    def get_revision_graph_with_ghosts(self, revision_ids=None):
 
168
        """Return a graph of the revisions with ghosts marked as applicable.
 
169
 
 
170
        :param revision_ids: an iterable of revisions to graph or None for all.
 
171
        :return: a Graph object with the graph reachable from revision_ids.
 
172
        """
 
173
        result = deprecated_graph.Graph()
 
174
        vf = self._get_revision_vf()
 
175
        versions = set(vf.versions())
 
176
        if not revision_ids:
 
177
            pending = set(self.all_revision_ids())
 
178
            required = set([])
 
179
        else:
 
180
            pending = set(osutils.safe_revision_id(r) for r in revision_ids)
 
181
            # special case NULL_REVISION
 
182
            if _mod_revision.NULL_REVISION in pending:
 
183
                pending.remove(_mod_revision.NULL_REVISION)
 
184
            required = set(pending)
 
185
        done = set([])
 
186
        while len(pending):
 
187
            revision_id = pending.pop()
 
188
            if not revision_id in versions:
 
189
                if revision_id in required:
 
190
                    raise errors.NoSuchRevision(self, revision_id)
 
191
                # a ghost
 
192
                result.add_ghost(revision_id)
 
193
                # mark it as done so we don't try for it again.
 
194
                done.add(revision_id)
 
195
                continue
 
196
            parent_ids = vf.get_parents_with_ghosts(revision_id)
 
197
            for parent_id in parent_ids:
 
198
                # is this queued or done ?
 
199
                if (parent_id not in pending and
 
200
                    parent_id not in done):
 
201
                    # no, queue it.
 
202
                    pending.add(parent_id)
 
203
            result.add_node(revision_id, parent_ids)
 
204
            done.add(revision_id)
 
205
        return result
 
206
 
 
207
    def _get_revision_vf(self):
 
208
        """:return: a versioned file containing the revisions."""
 
209
        vf = self._revision_store.get_revision_file(self.get_transaction())
 
210
        return vf
 
211
 
 
212
    def _get_history_vf(self):
 
213
        """Get a versionedfile whose history graph reflects all revisions.
 
214
 
 
215
        For knit repositories, this is the revision knit.
 
216
        """
 
217
        return self._get_revision_vf()
 
218
 
224
219
    @needs_write_lock
225
220
    def reconcile(self, other=None, thorough=False):
226
221
        """Reconcile this repository."""
229
224
        reconciler.reconcile()
230
225
        return reconciler
231
226
    
 
227
    def revision_parents(self, revision_id):
 
228
        revision_id = osutils.safe_revision_id(revision_id)
 
229
        return self._get_revision_vf().get_parents(revision_id)
 
230
 
232
231
    def _make_parents_provider(self):
233
 
        return _KnitsParentsProvider(self.revisions)
234
 
 
235
 
    def _find_inconsistent_revision_parents(self):
236
 
        """Find revisions with different parent lists in the revision object
237
 
        and in the index graph.
238
 
 
239
 
        :returns: an iterator yielding tuples of (revison-id, parents-in-index,
240
 
            parents-in-revision).
241
 
        """
242
 
        if not self.is_locked():
243
 
            raise AssertionError()
244
 
        vf = self.revisions
245
 
        for index_version in vf.keys():
246
 
            parent_map = vf.get_parent_map([index_version])
247
 
            parents_according_to_index = tuple(parent[-1] for parent in
248
 
                parent_map[index_version])
249
 
            revision = self.get_revision(index_version[-1])
250
 
            parents_according_to_revision = tuple(revision.parent_ids)
251
 
            if parents_according_to_index != parents_according_to_revision:
252
 
                yield (index_version[-1], parents_according_to_index,
253
 
                    parents_according_to_revision)
254
 
 
255
 
    def _check_for_inconsistent_revision_parents(self):
256
 
        inconsistencies = list(self._find_inconsistent_revision_parents())
257
 
        if inconsistencies:
258
 
            raise errors.BzrCheckError(
259
 
                "Revision knit has inconsistent parents.")
260
 
 
261
 
    def revision_graph_can_have_wrong_parents(self):
262
 
        # The revision.kndx could potentially claim a revision has a different
263
 
        # parent to the revision text.
264
 
        return True
 
232
        return _KnitParentsProvider(self._get_revision_vf())
 
233
 
 
234
 
 
235
class KnitRepository3(KnitRepository):
 
236
 
 
237
    def __init__(self, _format, a_bzrdir, control_files, _revision_store,
 
238
                 control_store, text_store):
 
239
        KnitRepository.__init__(self, _format, a_bzrdir, control_files,
 
240
                              _revision_store, control_store, text_store)
 
241
        self._serializer = xml7.serializer_v7
 
242
 
 
243
    def deserialise_inventory(self, revision_id, xml):
 
244
        """Transform the xml into an inventory object. 
 
245
 
 
246
        :param revision_id: The expected revision id of the inventory.
 
247
        :param xml: A serialised inventory.
 
248
        """
 
249
        result = self._serializer.read_inventory_from_string(xml)
 
250
        assert result.root.revision is not None
 
251
        return result
 
252
 
 
253
    def serialise_inventory(self, inv):
 
254
        """Transform the inventory object into XML text.
 
255
 
 
256
        :param revision_id: The expected revision id of the inventory.
 
257
        :param xml: A serialised inventory.
 
258
        """
 
259
        assert inv.revision_id is not None
 
260
        assert inv.root.revision is not None
 
261
        return KnitRepository.serialise_inventory(self, inv)
 
262
 
 
263
    def get_commit_builder(self, branch, parents, config, timestamp=None,
 
264
                           timezone=None, committer=None, revprops=None,
 
265
                           revision_id=None):
 
266
        """Obtain a CommitBuilder for this repository.
 
267
        
 
268
        :param branch: Branch to commit to.
 
269
        :param parents: Revision ids of the parents of the new revision.
 
270
        :param config: Configuration to use.
 
271
        :param timestamp: Optional timestamp recorded for commit.
 
272
        :param timezone: Optional timezone for timestamp.
 
273
        :param committer: Optional committer to set for commit.
 
274
        :param revprops: Optional dictionary of revision properties.
 
275
        :param revision_id: Optional revision id.
 
276
        """
 
277
        revision_id = osutils.safe_revision_id(revision_id)
 
278
        return RootCommitBuilder(self, parents, config, timestamp, timezone,
 
279
                                 committer, revprops, revision_id)
265
280
 
266
281
 
267
282
class RepositoryFormatKnit(MetaDirRepositoryFormat):
278
293
     - a LockDir lock
279
294
    """
280
295
 
281
 
    # Set this attribute in derived classes to control the repository class
282
 
    # created by open and initialize.
283
 
    repository_class = None
284
 
    # Set this attribute in derived classes to control the
285
 
    # _commit_builder_class that the repository objects will have passed to
286
 
    # their constructor.
287
 
    _commit_builder_class = None
288
 
    # Set this attribute in derived clases to control the _serializer that the
289
 
    # repository objects will have passed to their constructor.
290
 
    _serializer = xml5.serializer_v5
291
 
    # Knit based repositories handle ghosts reasonably well.
292
 
    supports_ghosts = True
293
 
    # External lookups are not supported in this format.
294
 
    supports_external_lookups = False
295
 
 
296
 
    def _get_inventories(self, repo_transport, repo, name='inventory'):
297
 
        mapper = ConstantMapper(name)
298
 
        index = _KndxIndex(repo_transport, mapper, repo.get_transaction,
299
 
            repo.is_write_locked, repo.is_locked)
300
 
        access = _KnitKeyAccess(repo_transport, mapper)
301
 
        return KnitVersionedFiles(index, access, annotated=False)
302
 
 
303
 
    def _get_revisions(self, repo_transport, repo):
304
 
        mapper = ConstantMapper('revisions')
305
 
        index = _KndxIndex(repo_transport, mapper, repo.get_transaction,
306
 
            repo.is_write_locked, repo.is_locked)
307
 
        access = _KnitKeyAccess(repo_transport, mapper)
308
 
        return KnitVersionedFiles(index, access, max_delta_chain=0,
309
 
            annotated=False)
310
 
 
311
 
    def _get_signatures(self, repo_transport, repo):
312
 
        mapper = ConstantMapper('signatures')
313
 
        index = _KndxIndex(repo_transport, mapper, repo.get_transaction,
314
 
            repo.is_write_locked, repo.is_locked)
315
 
        access = _KnitKeyAccess(repo_transport, mapper)
316
 
        return KnitVersionedFiles(index, access, max_delta_chain=0,
317
 
            annotated=False)
318
 
 
319
 
    def _get_texts(self, repo_transport, repo):
320
 
        mapper = HashEscapedPrefixMapper()
321
 
        base_transport = repo_transport.clone('knits')
322
 
        index = _KndxIndex(base_transport, mapper, repo.get_transaction,
323
 
            repo.is_write_locked, repo.is_locked)
324
 
        access = _KnitKeyAccess(base_transport, mapper)
325
 
        return KnitVersionedFiles(index, access, max_delta_chain=200,
326
 
            annotated=True)
 
296
    def _get_control_store(self, repo_transport, control_files):
 
297
        """Return the control store for this repository."""
 
298
        return VersionedFileStore(
 
299
            repo_transport,
 
300
            prefixed=False,
 
301
            file_mode=control_files._file_mode,
 
302
            versionedfile_class=knit.KnitVersionedFile,
 
303
            versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
 
304
            )
 
305
 
 
306
    def _get_revision_store(self, repo_transport, control_files):
 
307
        """See RepositoryFormat._get_revision_store()."""
 
308
        from bzrlib.store.revision.knit import KnitRevisionStore
 
309
        versioned_file_store = VersionedFileStore(
 
310
            repo_transport,
 
311
            file_mode=control_files._file_mode,
 
312
            prefixed=False,
 
313
            precious=True,
 
314
            versionedfile_class=knit.KnitVersionedFile,
 
315
            versionedfile_kwargs={'delta':False,
 
316
                                  'factory':knit.KnitPlainFactory(),
 
317
                                 },
 
318
            escaped=True,
 
319
            )
 
320
        return KnitRevisionStore(versioned_file_store)
 
321
 
 
322
    def _get_text_store(self, transport, control_files):
 
323
        """See RepositoryFormat._get_text_store()."""
 
324
        return self._get_versioned_file_store('knits',
 
325
                                  transport,
 
326
                                  control_files,
 
327
                                  versionedfile_class=knit.KnitVersionedFile,
 
328
                                  versionedfile_kwargs={
 
329
                                      'create_parent_dir':True,
 
330
                                      'delay_create':True,
 
331
                                      'dir_mode':control_files._dir_mode,
 
332
                                  },
 
333
                                  escaped=True)
327
334
 
328
335
    def initialize(self, a_bzrdir, shared=False):
329
336
        """Create a knit format 1 repository.
334
341
                       repository.
335
342
        """
336
343
        mutter('creating repository in %s.', a_bzrdir.transport.base)
337
 
        dirs = ['knits']
 
344
        dirs = ['revision-store', 'knits']
338
345
        files = []
339
346
        utf8_files = [('format', self.get_format_string())]
340
347
        
342
349
        repo_transport = a_bzrdir.get_repository_transport(None)
343
350
        control_files = lockable_files.LockableFiles(repo_transport,
344
351
                                'lock', lockdir.LockDir)
 
352
        control_store = self._get_control_store(repo_transport, control_files)
345
353
        transaction = transactions.WriteTransaction()
346
 
        result = self.open(a_bzrdir=a_bzrdir, _found=True)
347
 
        result.lock_write()
 
354
        # trigger a write of the inventory store.
 
355
        control_store.get_weave_or_empty('inventory', transaction)
 
356
        _revision_store = self._get_revision_store(repo_transport, control_files)
348
357
        # the revision id here is irrelevant: it will not be stored, and cannot
349
 
        # already exist, we do this to create files on disk for older clients.
350
 
        result.inventories.get_parent_map([('A',)])
351
 
        result.revisions.get_parent_map([('A',)])
352
 
        result.signatures.get_parent_map([('A',)])
353
 
        result.unlock()
354
 
        return result
 
358
        # already exist.
 
359
        _revision_store.has_revision_id('A', transaction)
 
360
        _revision_store.get_signature_file(transaction)
 
361
        return self.open(a_bzrdir=a_bzrdir, _found=True)
355
362
 
356
363
    def open(self, a_bzrdir, _found=False, _override_transport=None):
357
364
        """See RepositoryFormat.open().
362
369
        """
363
370
        if not _found:
364
371
            format = RepositoryFormat.find_format(a_bzrdir)
 
372
            assert format.__class__ ==  self.__class__
365
373
        if _override_transport is not None:
366
374
            repo_transport = _override_transport
367
375
        else:
368
376
            repo_transport = a_bzrdir.get_repository_transport(None)
369
377
        control_files = lockable_files.LockableFiles(repo_transport,
370
378
                                'lock', lockdir.LockDir)
371
 
        repo = self.repository_class(_format=self,
 
379
        text_store = self._get_text_store(repo_transport, control_files)
 
380
        control_store = self._get_control_store(repo_transport, control_files)
 
381
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
382
        return KnitRepository(_format=self,
372
383
                              a_bzrdir=a_bzrdir,
373
384
                              control_files=control_files,
374
 
                              _commit_builder_class=self._commit_builder_class,
375
 
                              _serializer=self._serializer)
376
 
        repo.revisions = self._get_revisions(repo_transport, repo)
377
 
        repo.signatures = self._get_signatures(repo_transport, repo)
378
 
        repo.inventories = self._get_inventories(repo_transport, repo)
379
 
        repo.texts = self._get_texts(repo_transport, repo)
380
 
        repo._transport = repo_transport
381
 
        return repo
 
385
                              _revision_store=_revision_store,
 
386
                              control_store=control_store,
 
387
                              text_store=text_store)
382
388
 
383
389
 
384
390
class RepositoryFormatKnit1(RepositoryFormatKnit):
397
403
    This format was introduced in bzr 0.8.
398
404
    """
399
405
 
400
 
    repository_class = KnitRepository
401
 
    _commit_builder_class = CommitBuilder
402
 
    _serializer = xml5.serializer_v5
403
 
 
404
406
    def __ne__(self, other):
405
407
        return self.__class__ is not other.__class__
406
408
 
417
419
 
418
420
 
419
421
class RepositoryFormatKnit3(RepositoryFormatKnit):
420
 
    """Bzr repository knit format 3.
 
422
    """Bzr repository knit format 2.
421
423
 
422
424
    This repository format has:
423
425
     - knits for file texts and inventory
432
434
     - support for recording tree-references
433
435
    """
434
436
 
435
 
    repository_class = KnitRepository
436
 
    _commit_builder_class = RootCommitBuilder
 
437
    repository_class = KnitRepository3
437
438
    rich_root_data = True
438
439
    supports_tree_reference = True
439
 
    _serializer = xml7.serializer_v7
440
440
 
441
441
    def _get_matching_bzrdir(self):
442
442
        return bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
462
462
        """See RepositoryFormat.get_format_description()."""
463
463
        return "Knit repository format 3"
464
464
 
465
 
 
466
 
class RepositoryFormatKnit4(RepositoryFormatKnit):
467
 
    """Bzr repository knit format 4.
468
 
 
469
 
    This repository format has everything in format 3, except for
470
 
    tree-references:
471
 
     - knits for file texts and inventory
472
 
     - hash subdirectory based stores.
473
 
     - knits for revisions and signatures
474
 
     - TextStores for revisions and signatures.
475
 
     - a format marker of its own
476
 
     - an optional 'shared-storage' flag
477
 
     - an optional 'no-working-trees' flag
478
 
     - a LockDir lock
479
 
     - support for recording full info about the tree root
480
 
    """
481
 
 
482
 
    repository_class = KnitRepository
483
 
    _commit_builder_class = RootCommitBuilder
484
 
    rich_root_data = True
485
 
    supports_tree_reference = False
486
 
    _serializer = xml6.serializer_v6
487
 
 
488
 
    def _get_matching_bzrdir(self):
489
 
        return bzrdir.format_registry.make_bzrdir('rich-root')
490
 
 
491
 
    def _ignore_setting_bzrdir(self, format):
492
 
        pass
493
 
 
494
 
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
495
 
 
496
 
    def check_conversion_target(self, target_format):
497
 
        if not target_format.rich_root_data:
498
 
            raise errors.BadConversionTarget(
499
 
                'Does not support rich root data.', target_format)
500
 
 
501
 
    def get_format_string(self):
502
 
        """See RepositoryFormat.get_format_string()."""
503
 
        return 'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
504
 
 
505
 
    def get_format_description(self):
506
 
        """See RepositoryFormat.get_format_description()."""
507
 
        return "Knit repository format 4"
 
465
    def open(self, a_bzrdir, _found=False, _override_transport=None):
 
466
        """See RepositoryFormat.open().
 
467
        
 
468
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
 
469
                                    repository at a slightly different url
 
470
                                    than normal. I.e. during 'upgrade'.
 
471
        """
 
472
        if not _found:
 
473
            format = RepositoryFormat.find_format(a_bzrdir)
 
474
            assert format.__class__ ==  self.__class__
 
475
        if _override_transport is not None:
 
476
            repo_transport = _override_transport
 
477
        else:
 
478
            repo_transport = a_bzrdir.get_repository_transport(None)
 
479
        control_files = lockable_files.LockableFiles(repo_transport, 'lock',
 
480
                                                     lockdir.LockDir)
 
481
        text_store = self._get_text_store(repo_transport, control_files)
 
482
        control_store = self._get_control_store(repo_transport, control_files)
 
483
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
484
        return self.repository_class(_format=self,
 
485
                                     a_bzrdir=a_bzrdir,
 
486
                                     control_files=control_files,
 
487
                                     _revision_store=_revision_store,
 
488
                                     control_store=control_store,
 
489
                                     text_store=text_store)