/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« 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:
 
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
from bzrlib import (
 
18
    errors,
 
19
    graph,
 
20
    knit,
 
21
    lockable_files,
 
22
    lockdir,
 
23
    transactions,
 
24
    xml6,
 
25
    )
 
26
 
 
27
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
28
from bzrlib.repository import (
 
29
    MetaDirRepository,
 
30
    MetaDirRepositoryFormat,
 
31
    RepositoryFormat,
 
32
    RootCommitBuilder,
 
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)
 
186
 
 
187
 
 
188
class KnitRepository2(KnitRepository):
 
189
    """"""
 
190
    def __init__(self, _format, a_bzrdir, control_files, _revision_store,
 
191
                 control_store, text_store):
 
192
        KnitRepository.__init__(self, _format, a_bzrdir, control_files,
 
193
                              _revision_store, control_store, text_store)
 
194
        self._serializer = xml6.serializer_v6
 
195
 
 
196
    def deserialise_inventory(self, revision_id, xml):
 
197
        """Transform the xml into an inventory object. 
 
198
 
 
199
        :param revision_id: The expected revision id of the inventory.
 
200
        :param xml: A serialised inventory.
 
201
        """
 
202
        result = self._serializer.read_inventory_from_string(xml)
 
203
        assert result.root.revision is not None
 
204
        return result
 
205
 
 
206
    def serialise_inventory(self, inv):
 
207
        """Transform the inventory object into XML text.
 
208
 
 
209
        :param revision_id: The expected revision id of the inventory.
 
210
        :param xml: A serialised inventory.
 
211
        """
 
212
        assert inv.revision_id is not None
 
213
        assert inv.root.revision is not None
 
214
        return KnitRepository.serialise_inventory(self, inv)
 
215
 
 
216
    def get_commit_builder(self, branch, parents, config, timestamp=None,
 
217
                           timezone=None, committer=None, revprops=None,
 
218
                           revision_id=None):
 
219
        """Obtain a CommitBuilder for this repository.
 
220
        
 
221
        :param branch: Branch to commit to.
 
222
        :param parents: Revision ids of the parents of the new revision.
 
223
        :param config: Configuration to use.
 
224
        :param timestamp: Optional timestamp recorded for commit.
 
225
        :param timezone: Optional timezone for timestamp.
 
226
        :param committer: Optional committer to set for commit.
 
227
        :param revprops: Optional dictionary of revision properties.
 
228
        :param revision_id: Optional revision id.
 
229
        """
 
230
        return RootCommitBuilder(self, parents, config, timestamp, timezone,
 
231
                                 committer, revprops, revision_id)
 
232
 
 
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
 
 
369
class RepositoryFormatKnit2(RepositoryFormatKnit):
 
370
    """Bzr repository knit format 2.
 
371
 
 
372
    THIS FORMAT IS EXPERIMENTAL
 
373
    This repository format has:
 
374
     - knits for file texts and inventory
 
375
     - hash subdirectory based stores.
 
376
     - knits for revisions and signatures
 
377
     - TextStores for revisions and signatures.
 
378
     - a format marker of its own
 
379
     - an optional 'shared-storage' flag
 
380
     - an optional 'no-working-trees' flag
 
381
     - a LockDir lock
 
382
     - Support for recording full info about the tree root
 
383
 
 
384
    """
 
385
    
 
386
    rich_root_data = True
 
387
 
 
388
    def get_format_string(self):
 
389
        """See RepositoryFormat.get_format_string()."""
 
390
        return "Bazaar Knit Repository Format 2\n"
 
391
 
 
392
    def get_format_description(self):
 
393
        """See RepositoryFormat.get_format_description()."""
 
394
        return "Knit repository format 2"
 
395
 
 
396
    def check_conversion_target(self, target_format):
 
397
        if not target_format.rich_root_data:
 
398
            raise errors.BadConversionTarget(
 
399
                'Does not support rich root data.', target_format)
 
400
 
 
401
    def open(self, a_bzrdir, _found=False, _override_transport=None):
 
402
        """See RepositoryFormat.open().
 
403
        
 
404
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
 
405
                                    repository at a slightly different url
 
406
                                    than normal. I.e. during 'upgrade'.
 
407
        """
 
408
        if not _found:
 
409
            format = RepositoryFormat.find_format(a_bzrdir)
 
410
            assert format.__class__ ==  self.__class__
 
411
        if _override_transport is not None:
 
412
            repo_transport = _override_transport
 
413
        else:
 
414
            repo_transport = a_bzrdir.get_repository_transport(None)
 
415
        control_files = lockable_files.LockableFiles(repo_transport, 'lock',
 
416
                                                     lockdir.LockDir)
 
417
        text_store = self._get_text_store(repo_transport, control_files)
 
418
        control_store = self._get_control_store(repo_transport, control_files)
 
419
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
420
        return KnitRepository2(_format=self,
 
421
                               a_bzrdir=a_bzrdir,
 
422
                               control_files=control_files,
 
423
                               _revision_store=_revision_store,
 
424
                               control_store=control_store,
 
425
                               text_store=text_store)
 
426
 
 
427
 
 
428
RepositoryFormatKnit1_instance = RepositoryFormatKnit1()
 
429
RepositoryFormatKnit2_instance = RepositoryFormatKnit2()