~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/knitrepo.py

  • Committer: Martin Pool
  • Date: 2007-02-07 09:11:31 UTC
  • mto: This revision was merged to the branch mainline in revision 2283.
  • Revision ID: mbp@sourcefrog.net-20070207091131-458fw18bgytvaz7t
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
lazily load from the registry.

InterRepo._matching_repo_format is now a method not a class field so that
it can load repositories when we need them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
from bzrlib import (
18
18
    errors,
 
19
    graph,
 
20
    knit,
19
21
    lockable_files,
20
22
    lockdir,
 
23
    transactions,
21
24
    xml6,
22
25
    )
23
26
 
 
27
from bzrlib.decorators import needs_read_lock, needs_write_lock
24
28
from bzrlib.repository import (
25
 
    KnitRepository,
 
29
    MetaDirRepository,
 
30
    MetaDirRepositoryFormat,
26
31
    RepositoryFormat,
27
 
    RepositoryFormatKnit,
28
32
    RootCommitBuilder,
29
33
    )
 
34
import bzrlib.revision as _mod_revision
 
35
from bzrlib.store.versioned import VersionedFileStore
 
36
from bzrlib.trace import mutter, note, warning
 
37
 
 
38
 
 
39
class KnitRepository(MetaDirRepository):
 
40
    """Knit format repository."""
 
41
 
 
42
    def _warn_if_deprecated(self):
 
43
        # This class isn't deprecated
 
44
        pass
 
45
 
 
46
    def _inventory_add_lines(self, inv_vf, revid, parents, lines):
 
47
        inv_vf.add_lines_with_ghosts(revid, parents, lines)
 
48
 
 
49
    @needs_read_lock
 
50
    def _all_revision_ids(self):
 
51
        """See Repository.all_revision_ids()."""
 
52
        # Knits get the revision graph from the index of the revision knit, so
 
53
        # it's always possible even if they're on an unlistable transport.
 
54
        return self._revision_store.all_revision_ids(self.get_transaction())
 
55
 
 
56
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
57
        """Find file_id(s) which are involved in the changes between revisions.
 
58
 
 
59
        This determines the set of revisions which are involved, and then
 
60
        finds all file ids affected by those revisions.
 
61
        """
 
62
        vf = self._get_revision_vf()
 
63
        from_set = set(vf.get_ancestry(from_revid))
 
64
        to_set = set(vf.get_ancestry(to_revid))
 
65
        changed = to_set.difference(from_set)
 
66
        return self._fileid_involved_by_set(changed)
 
67
 
 
68
    def fileid_involved(self, last_revid=None):
 
69
        """Find all file_ids modified in the ancestry of last_revid.
 
70
 
 
71
        :param last_revid: If None, last_revision() will be used.
 
72
        """
 
73
        if not last_revid:
 
74
            changed = set(self.all_revision_ids())
 
75
        else:
 
76
            changed = set(self.get_ancestry(last_revid))
 
77
        if None in changed:
 
78
            changed.remove(None)
 
79
        return self._fileid_involved_by_set(changed)
 
80
 
 
81
    @needs_read_lock
 
82
    def get_ancestry(self, revision_id):
 
83
        """Return a list of revision-ids integrated by a revision.
 
84
        
 
85
        This is topologically sorted.
 
86
        """
 
87
        if revision_id is None:
 
88
            return [None]
 
89
        vf = self._get_revision_vf()
 
90
        try:
 
91
            return [None] + vf.get_ancestry(revision_id)
 
92
        except errors.RevisionNotPresent:
 
93
            raise errors.NoSuchRevision(self, revision_id)
 
94
 
 
95
    @needs_read_lock
 
96
    def get_revision(self, revision_id):
 
97
        """Return the Revision object for a named revision"""
 
98
        return self.get_revision_reconcile(revision_id)
 
99
 
 
100
    @needs_read_lock
 
101
    def get_revision_graph(self, revision_id=None):
 
102
        """Return a dictionary containing the revision graph.
 
103
 
 
104
        :param revision_id: The revision_id to get a graph from. If None, then
 
105
        the entire revision graph is returned. This is a deprecated mode of
 
106
        operation and will be removed in the future.
 
107
        :return: a dictionary of revision_id->revision_parents_list.
 
108
        """
 
109
        # special case NULL_REVISION
 
110
        if revision_id == _mod_revision.NULL_REVISION:
 
111
            return {}
 
112
        a_weave = self._get_revision_vf()
 
113
        entire_graph = a_weave.get_graph()
 
114
        if revision_id is None:
 
115
            return a_weave.get_graph()
 
116
        elif revision_id not in a_weave:
 
117
            raise errors.NoSuchRevision(self, revision_id)
 
118
        else:
 
119
            # add what can be reached from revision_id
 
120
            result = {}
 
121
            pending = set([revision_id])
 
122
            while len(pending) > 0:
 
123
                node = pending.pop()
 
124
                result[node] = a_weave.get_parents(node)
 
125
                for revision_id in result[node]:
 
126
                    if revision_id not in result:
 
127
                        pending.add(revision_id)
 
128
            return result
 
129
 
 
130
    @needs_read_lock
 
131
    def get_revision_graph_with_ghosts(self, revision_ids=None):
 
132
        """Return a graph of the revisions with ghosts marked as applicable.
 
133
 
 
134
        :param revision_ids: an iterable of revisions to graph or None for all.
 
135
        :return: a Graph object with the graph reachable from revision_ids.
 
136
        """
 
137
        result = graph.Graph()
 
138
        vf = self._get_revision_vf()
 
139
        versions = set(vf.versions())
 
140
        if not revision_ids:
 
141
            pending = set(self.all_revision_ids())
 
142
            required = set([])
 
143
        else:
 
144
            pending = set(revision_ids)
 
145
            # special case NULL_REVISION
 
146
            if _mod_revision.NULL_REVISION in pending:
 
147
                pending.remove(_mod_revision.NULL_REVISION)
 
148
            required = set(pending)
 
149
        done = set([])
 
150
        while len(pending):
 
151
            revision_id = pending.pop()
 
152
            if not revision_id in versions:
 
153
                if revision_id in required:
 
154
                    raise errors.NoSuchRevision(self, revision_id)
 
155
                # a ghost
 
156
                result.add_ghost(revision_id)
 
157
                # mark it as done so we don't try for it again.
 
158
                done.add(revision_id)
 
159
                continue
 
160
            parent_ids = vf.get_parents_with_ghosts(revision_id)
 
161
            for parent_id in parent_ids:
 
162
                # is this queued or done ?
 
163
                if (parent_id not in pending and
 
164
                    parent_id not in done):
 
165
                    # no, queue it.
 
166
                    pending.add(parent_id)
 
167
            result.add_node(revision_id, parent_ids)
 
168
            done.add(revision_id)
 
169
        return result
 
170
 
 
171
    def _get_revision_vf(self):
 
172
        """:return: a versioned file containing the revisions."""
 
173
        vf = self._revision_store.get_revision_file(self.get_transaction())
 
174
        return vf
 
175
 
 
176
    @needs_write_lock
 
177
    def reconcile(self, other=None, thorough=False):
 
178
        """Reconcile this repository."""
 
179
        from bzrlib.reconcile import KnitReconciler
 
180
        reconciler = KnitReconciler(self, thorough=thorough)
 
181
        reconciler.reconcile()
 
182
        return reconciler
 
183
    
 
184
    def revision_parents(self, revision_id):
 
185
        return self._get_revision_vf().get_parents(revision_id)
30
186
 
31
187
 
32
188
class KnitRepository2(KnitRepository):
75
231
                                 committer, revprops, revision_id)
76
232
 
77
233
 
 
234
class RepositoryFormatKnit(MetaDirRepositoryFormat):
 
235
    """Bzr repository knit format (generalized). 
 
236
 
 
237
    This repository format has:
 
238
     - knits for file texts and inventory
 
239
     - hash subdirectory based stores.
 
240
     - knits for revisions and signatures
 
241
     - TextStores for revisions and signatures.
 
242
     - a format marker of its own
 
243
     - an optional 'shared-storage' flag
 
244
     - an optional 'no-working-trees' flag
 
245
     - a LockDir lock
 
246
    """
 
247
 
 
248
    def _get_control_store(self, repo_transport, control_files):
 
249
        """Return the control store for this repository."""
 
250
        return VersionedFileStore(
 
251
            repo_transport,
 
252
            prefixed=False,
 
253
            file_mode=control_files._file_mode,
 
254
            versionedfile_class=knit.KnitVersionedFile,
 
255
            versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
 
256
            )
 
257
 
 
258
    def _get_revision_store(self, repo_transport, control_files):
 
259
        """See RepositoryFormat._get_revision_store()."""
 
260
        from bzrlib.store.revision.knit import KnitRevisionStore
 
261
        versioned_file_store = VersionedFileStore(
 
262
            repo_transport,
 
263
            file_mode=control_files._file_mode,
 
264
            prefixed=False,
 
265
            precious=True,
 
266
            versionedfile_class=knit.KnitVersionedFile,
 
267
            versionedfile_kwargs={'delta':False,
 
268
                                  'factory':knit.KnitPlainFactory(),
 
269
                                 },
 
270
            escaped=True,
 
271
            )
 
272
        return KnitRevisionStore(versioned_file_store)
 
273
 
 
274
    def _get_text_store(self, transport, control_files):
 
275
        """See RepositoryFormat._get_text_store()."""
 
276
        return self._get_versioned_file_store('knits',
 
277
                                  transport,
 
278
                                  control_files,
 
279
                                  versionedfile_class=knit.KnitVersionedFile,
 
280
                                  versionedfile_kwargs={
 
281
                                      'create_parent_dir':True,
 
282
                                      'delay_create':True,
 
283
                                      'dir_mode':control_files._dir_mode,
 
284
                                  },
 
285
                                  escaped=True)
 
286
 
 
287
    def initialize(self, a_bzrdir, shared=False):
 
288
        """Create a knit format 1 repository.
 
289
 
 
290
        :param a_bzrdir: bzrdir to contain the new repository; must already
 
291
            be initialized.
 
292
        :param shared: If true the repository will be initialized as a shared
 
293
                       repository.
 
294
        """
 
295
        mutter('creating repository in %s.', a_bzrdir.transport.base)
 
296
        dirs = ['revision-store', 'knits']
 
297
        files = []
 
298
        utf8_files = [('format', self.get_format_string())]
 
299
        
 
300
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
 
301
        repo_transport = a_bzrdir.get_repository_transport(None)
 
302
        control_files = lockable_files.LockableFiles(repo_transport,
 
303
                                'lock', lockdir.LockDir)
 
304
        control_store = self._get_control_store(repo_transport, control_files)
 
305
        transaction = transactions.WriteTransaction()
 
306
        # trigger a write of the inventory store.
 
307
        control_store.get_weave_or_empty('inventory', transaction)
 
308
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
309
        # the revision id here is irrelevant: it will not be stored, and cannot
 
310
        # already exist.
 
311
        _revision_store.has_revision_id('A', transaction)
 
312
        _revision_store.get_signature_file(transaction)
 
313
        return self.open(a_bzrdir=a_bzrdir, _found=True)
 
314
 
 
315
    def open(self, a_bzrdir, _found=False, _override_transport=None):
 
316
        """See RepositoryFormat.open().
 
317
        
 
318
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
 
319
                                    repository at a slightly different url
 
320
                                    than normal. I.e. during 'upgrade'.
 
321
        """
 
322
        if not _found:
 
323
            format = RepositoryFormat.find_format(a_bzrdir)
 
324
            assert format.__class__ ==  self.__class__
 
325
        if _override_transport is not None:
 
326
            repo_transport = _override_transport
 
327
        else:
 
328
            repo_transport = a_bzrdir.get_repository_transport(None)
 
329
        control_files = lockable_files.LockableFiles(repo_transport,
 
330
                                'lock', lockdir.LockDir)
 
331
        text_store = self._get_text_store(repo_transport, control_files)
 
332
        control_store = self._get_control_store(repo_transport, control_files)
 
333
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
334
        return KnitRepository(_format=self,
 
335
                              a_bzrdir=a_bzrdir,
 
336
                              control_files=control_files,
 
337
                              _revision_store=_revision_store,
 
338
                              control_store=control_store,
 
339
                              text_store=text_store)
 
340
 
 
341
 
 
342
class RepositoryFormatKnit1(RepositoryFormatKnit):
 
343
    """Bzr repository knit format 1.
 
344
 
 
345
    This repository format has:
 
346
     - knits for file texts and inventory
 
347
     - hash subdirectory based stores.
 
348
     - knits for revisions and signatures
 
349
     - TextStores for revisions and signatures.
 
350
     - a format marker of its own
 
351
     - an optional 'shared-storage' flag
 
352
     - an optional 'no-working-trees' flag
 
353
     - a LockDir lock
 
354
 
 
355
    This format was introduced in bzr 0.8.
 
356
    """
 
357
    def get_format_string(self):
 
358
        """See RepositoryFormat.get_format_string()."""
 
359
        return "Bazaar-NG Knit Repository Format 1"
 
360
 
 
361
    def get_format_description(self):
 
362
        """See RepositoryFormat.get_format_description()."""
 
363
        return "Knit repository format 1"
 
364
 
 
365
    def check_conversion_target(self, target_format):
 
366
        pass
 
367
 
 
368
 
78
369
class RepositoryFormatKnit2(RepositoryFormatKnit):
79
370
    """Bzr repository knit format 2.
80
371
 
134
425
                               text_store=text_store)
135
426
 
136
427
 
 
428
RepositoryFormatKnit1_instance = RepositoryFormatKnit1()
137
429
RepositoryFormatKnit2_instance = RepositoryFormatKnit2()