/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: Canonical.com Patch Queue Manager
  • Date: 2007-02-15 15:11:31 UTC
  • mfrom: (2230.3.55 branch6)
  • Revision ID: pqm@pqm.ubuntu.com-20070215151131-1f2ce67d76e40200
Provide new branch6 format

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
    xml5,
 
25
    xml6,
 
26
    )
 
27
 
 
28
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
29
from bzrlib.repository import (
 
30
    MetaDirRepository,
 
31
    MetaDirRepositoryFormat,
 
32
    RepositoryFormat,
 
33
    RootCommitBuilder,
 
34
    )
 
35
import bzrlib.revision as _mod_revision
 
36
from bzrlib.store.versioned import VersionedFileStore
 
37
from bzrlib.trace import mutter, note, warning
 
38
 
 
39
 
 
40
class KnitRepository(MetaDirRepository):
 
41
    """Knit format repository."""
 
42
 
 
43
 
 
44
    _serializer = xml5.serializer_v5
 
45
 
 
46
    def _warn_if_deprecated(self):
 
47
        # This class isn't deprecated
 
48
        pass
 
49
 
 
50
    def _inventory_add_lines(self, inv_vf, revid, parents, lines):
 
51
        inv_vf.add_lines_with_ghosts(revid, parents, lines)
 
52
 
 
53
    @needs_read_lock
 
54
    def _all_revision_ids(self):
 
55
        """See Repository.all_revision_ids()."""
 
56
        # Knits get the revision graph from the index of the revision knit, so
 
57
        # it's always possible even if they're on an unlistable transport.
 
58
        return self._revision_store.all_revision_ids(self.get_transaction())
 
59
 
 
60
    def fileid_involved_between_revs(self, from_revid, to_revid):
 
61
        """Find file_id(s) which are involved in the changes between revisions.
 
62
 
 
63
        This determines the set of revisions which are involved, and then
 
64
        finds all file ids affected by those revisions.
 
65
        """
 
66
        vf = self._get_revision_vf()
 
67
        from_set = set(vf.get_ancestry(from_revid))
 
68
        to_set = set(vf.get_ancestry(to_revid))
 
69
        changed = to_set.difference(from_set)
 
70
        return self._fileid_involved_by_set(changed)
 
71
 
 
72
    def fileid_involved(self, last_revid=None):
 
73
        """Find all file_ids modified in the ancestry of last_revid.
 
74
 
 
75
        :param last_revid: If None, last_revision() will be used.
 
76
        """
 
77
        if not last_revid:
 
78
            changed = set(self.all_revision_ids())
 
79
        else:
 
80
            changed = set(self.get_ancestry(last_revid))
 
81
        if None in changed:
 
82
            changed.remove(None)
 
83
        return self._fileid_involved_by_set(changed)
 
84
 
 
85
    @needs_read_lock
 
86
    def get_ancestry(self, revision_id):
 
87
        """Return a list of revision-ids integrated by a revision.
 
88
        
 
89
        This is topologically sorted.
 
90
        """
 
91
        if revision_id is None:
 
92
            return [None]
 
93
        vf = self._get_revision_vf()
 
94
        try:
 
95
            return [None] + vf.get_ancestry(revision_id)
 
96
        except errors.RevisionNotPresent:
 
97
            raise errors.NoSuchRevision(self, revision_id)
 
98
 
 
99
    @needs_read_lock
 
100
    def get_revision(self, revision_id):
 
101
        """Return the Revision object for a named revision"""
 
102
        return self.get_revision_reconcile(revision_id)
 
103
 
 
104
    @needs_read_lock
 
105
    def get_revision_graph(self, revision_id=None):
 
106
        """Return a dictionary containing the revision graph.
 
107
 
 
108
        :param revision_id: The revision_id to get a graph from. If None, then
 
109
        the entire revision graph is returned. This is a deprecated mode of
 
110
        operation and will be removed in the future.
 
111
        :return: a dictionary of revision_id->revision_parents_list.
 
112
        """
 
113
        # special case NULL_REVISION
 
114
        if revision_id == _mod_revision.NULL_REVISION:
 
115
            return {}
 
116
        a_weave = self._get_revision_vf()
 
117
        entire_graph = a_weave.get_graph()
 
118
        if revision_id is None:
 
119
            return a_weave.get_graph()
 
120
        elif revision_id not in a_weave:
 
121
            raise errors.NoSuchRevision(self, revision_id)
 
122
        else:
 
123
            # add what can be reached from revision_id
 
124
            result = {}
 
125
            pending = set([revision_id])
 
126
            while len(pending) > 0:
 
127
                node = pending.pop()
 
128
                result[node] = a_weave.get_parents(node)
 
129
                for revision_id in result[node]:
 
130
                    if revision_id not in result:
 
131
                        pending.add(revision_id)
 
132
            return result
 
133
 
 
134
    @needs_read_lock
 
135
    def get_revision_graph_with_ghosts(self, revision_ids=None):
 
136
        """Return a graph of the revisions with ghosts marked as applicable.
 
137
 
 
138
        :param revision_ids: an iterable of revisions to graph or None for all.
 
139
        :return: a Graph object with the graph reachable from revision_ids.
 
140
        """
 
141
        result = graph.Graph()
 
142
        vf = self._get_revision_vf()
 
143
        versions = set(vf.versions())
 
144
        if not revision_ids:
 
145
            pending = set(self.all_revision_ids())
 
146
            required = set([])
 
147
        else:
 
148
            pending = set(revision_ids)
 
149
            # special case NULL_REVISION
 
150
            if _mod_revision.NULL_REVISION in pending:
 
151
                pending.remove(_mod_revision.NULL_REVISION)
 
152
            required = set(pending)
 
153
        done = set([])
 
154
        while len(pending):
 
155
            revision_id = pending.pop()
 
156
            if not revision_id in versions:
 
157
                if revision_id in required:
 
158
                    raise errors.NoSuchRevision(self, revision_id)
 
159
                # a ghost
 
160
                result.add_ghost(revision_id)
 
161
                # mark it as done so we don't try for it again.
 
162
                done.add(revision_id)
 
163
                continue
 
164
            parent_ids = vf.get_parents_with_ghosts(revision_id)
 
165
            for parent_id in parent_ids:
 
166
                # is this queued or done ?
 
167
                if (parent_id not in pending and
 
168
                    parent_id not in done):
 
169
                    # no, queue it.
 
170
                    pending.add(parent_id)
 
171
            result.add_node(revision_id, parent_ids)
 
172
            done.add(revision_id)
 
173
        return result
 
174
 
 
175
    def _get_revision_vf(self):
 
176
        """:return: a versioned file containing the revisions."""
 
177
        vf = self._revision_store.get_revision_file(self.get_transaction())
 
178
        return vf
 
179
 
 
180
    def _get_history_vf(self):
 
181
        """Get a versionedfile whose history graph reflects all revisions.
 
182
 
 
183
        For knit repositories, this is the revision knit.
 
184
        """
 
185
        return self._get_revision_vf()
 
186
 
 
187
    @needs_write_lock
 
188
    def reconcile(self, other=None, thorough=False):
 
189
        """Reconcile this repository."""
 
190
        from bzrlib.reconcile import KnitReconciler
 
191
        reconciler = KnitReconciler(self, thorough=thorough)
 
192
        reconciler.reconcile()
 
193
        return reconciler
 
194
    
 
195
    def revision_parents(self, revision_id):
 
196
        return self._get_revision_vf().get_parents(revision_id)
 
197
 
 
198
 
 
199
class KnitRepository2(KnitRepository):
 
200
    """"""
 
201
    def __init__(self, _format, a_bzrdir, control_files, _revision_store,
 
202
                 control_store, text_store):
 
203
        KnitRepository.__init__(self, _format, a_bzrdir, control_files,
 
204
                              _revision_store, control_store, text_store)
 
205
        self._serializer = xml6.serializer_v6
 
206
 
 
207
    def deserialise_inventory(self, revision_id, xml):
 
208
        """Transform the xml into an inventory object. 
 
209
 
 
210
        :param revision_id: The expected revision id of the inventory.
 
211
        :param xml: A serialised inventory.
 
212
        """
 
213
        result = self._serializer.read_inventory_from_string(xml)
 
214
        assert result.root.revision is not None
 
215
        return result
 
216
 
 
217
    def serialise_inventory(self, inv):
 
218
        """Transform the inventory object into XML text.
 
219
 
 
220
        :param revision_id: The expected revision id of the inventory.
 
221
        :param xml: A serialised inventory.
 
222
        """
 
223
        assert inv.revision_id is not None
 
224
        assert inv.root.revision is not None
 
225
        return KnitRepository.serialise_inventory(self, inv)
 
226
 
 
227
    def get_commit_builder(self, branch, parents, config, timestamp=None,
 
228
                           timezone=None, committer=None, revprops=None,
 
229
                           revision_id=None):
 
230
        """Obtain a CommitBuilder for this repository.
 
231
        
 
232
        :param branch: Branch to commit to.
 
233
        :param parents: Revision ids of the parents of the new revision.
 
234
        :param config: Configuration to use.
 
235
        :param timestamp: Optional timestamp recorded for commit.
 
236
        :param timezone: Optional timezone for timestamp.
 
237
        :param committer: Optional committer to set for commit.
 
238
        :param revprops: Optional dictionary of revision properties.
 
239
        :param revision_id: Optional revision id.
 
240
        """
 
241
        return RootCommitBuilder(self, parents, config, timestamp, timezone,
 
242
                                 committer, revprops, revision_id)
 
243
 
 
244
 
 
245
class RepositoryFormatKnit(MetaDirRepositoryFormat):
 
246
    """Bzr repository knit format (generalized). 
 
247
 
 
248
    This repository format has:
 
249
     - knits for file texts and inventory
 
250
     - hash subdirectory based stores.
 
251
     - knits for revisions and signatures
 
252
     - TextStores for revisions and signatures.
 
253
     - a format marker of its own
 
254
     - an optional 'shared-storage' flag
 
255
     - an optional 'no-working-trees' flag
 
256
     - a LockDir lock
 
257
    """
 
258
 
 
259
    def _get_control_store(self, repo_transport, control_files):
 
260
        """Return the control store for this repository."""
 
261
        return VersionedFileStore(
 
262
            repo_transport,
 
263
            prefixed=False,
 
264
            file_mode=control_files._file_mode,
 
265
            versionedfile_class=knit.KnitVersionedFile,
 
266
            versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
 
267
            )
 
268
 
 
269
    def _get_revision_store(self, repo_transport, control_files):
 
270
        """See RepositoryFormat._get_revision_store()."""
 
271
        from bzrlib.store.revision.knit import KnitRevisionStore
 
272
        versioned_file_store = VersionedFileStore(
 
273
            repo_transport,
 
274
            file_mode=control_files._file_mode,
 
275
            prefixed=False,
 
276
            precious=True,
 
277
            versionedfile_class=knit.KnitVersionedFile,
 
278
            versionedfile_kwargs={'delta':False,
 
279
                                  'factory':knit.KnitPlainFactory(),
 
280
                                 },
 
281
            escaped=True,
 
282
            )
 
283
        return KnitRevisionStore(versioned_file_store)
 
284
 
 
285
    def _get_text_store(self, transport, control_files):
 
286
        """See RepositoryFormat._get_text_store()."""
 
287
        return self._get_versioned_file_store('knits',
 
288
                                  transport,
 
289
                                  control_files,
 
290
                                  versionedfile_class=knit.KnitVersionedFile,
 
291
                                  versionedfile_kwargs={
 
292
                                      'create_parent_dir':True,
 
293
                                      'delay_create':True,
 
294
                                      'dir_mode':control_files._dir_mode,
 
295
                                  },
 
296
                                  escaped=True)
 
297
 
 
298
    def initialize(self, a_bzrdir, shared=False):
 
299
        """Create a knit format 1 repository.
 
300
 
 
301
        :param a_bzrdir: bzrdir to contain the new repository; must already
 
302
            be initialized.
 
303
        :param shared: If true the repository will be initialized as a shared
 
304
                       repository.
 
305
        """
 
306
        mutter('creating repository in %s.', a_bzrdir.transport.base)
 
307
        dirs = ['revision-store', 'knits']
 
308
        files = []
 
309
        utf8_files = [('format', self.get_format_string())]
 
310
        
 
311
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
 
312
        repo_transport = a_bzrdir.get_repository_transport(None)
 
313
        control_files = lockable_files.LockableFiles(repo_transport,
 
314
                                'lock', lockdir.LockDir)
 
315
        control_store = self._get_control_store(repo_transport, control_files)
 
316
        transaction = transactions.WriteTransaction()
 
317
        # trigger a write of the inventory store.
 
318
        control_store.get_weave_or_empty('inventory', transaction)
 
319
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
320
        # the revision id here is irrelevant: it will not be stored, and cannot
 
321
        # already exist.
 
322
        _revision_store.has_revision_id('A', transaction)
 
323
        _revision_store.get_signature_file(transaction)
 
324
        return self.open(a_bzrdir=a_bzrdir, _found=True)
 
325
 
 
326
    def open(self, a_bzrdir, _found=False, _override_transport=None):
 
327
        """See RepositoryFormat.open().
 
328
        
 
329
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
 
330
                                    repository at a slightly different url
 
331
                                    than normal. I.e. during 'upgrade'.
 
332
        """
 
333
        if not _found:
 
334
            format = RepositoryFormat.find_format(a_bzrdir)
 
335
            assert format.__class__ ==  self.__class__
 
336
        if _override_transport is not None:
 
337
            repo_transport = _override_transport
 
338
        else:
 
339
            repo_transport = a_bzrdir.get_repository_transport(None)
 
340
        control_files = lockable_files.LockableFiles(repo_transport,
 
341
                                'lock', lockdir.LockDir)
 
342
        text_store = self._get_text_store(repo_transport, control_files)
 
343
        control_store = self._get_control_store(repo_transport, control_files)
 
344
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
345
        return KnitRepository(_format=self,
 
346
                              a_bzrdir=a_bzrdir,
 
347
                              control_files=control_files,
 
348
                              _revision_store=_revision_store,
 
349
                              control_store=control_store,
 
350
                              text_store=text_store)
 
351
 
 
352
 
 
353
class RepositoryFormatKnit1(RepositoryFormatKnit):
 
354
    """Bzr repository knit format 1.
 
355
 
 
356
    This repository format has:
 
357
     - knits for file texts and inventory
 
358
     - hash subdirectory based stores.
 
359
     - knits for revisions and signatures
 
360
     - TextStores for revisions and signatures.
 
361
     - a format marker of its own
 
362
     - an optional 'shared-storage' flag
 
363
     - an optional 'no-working-trees' flag
 
364
     - a LockDir lock
 
365
 
 
366
    This format was introduced in bzr 0.8.
 
367
    """
 
368
 
 
369
    def get_format_string(self):
 
370
        """See RepositoryFormat.get_format_string()."""
 
371
        return "Bazaar-NG Knit Repository Format 1"
 
372
 
 
373
    def get_format_description(self):
 
374
        """See RepositoryFormat.get_format_description()."""
 
375
        return "Knit repository format 1"
 
376
 
 
377
    def check_conversion_target(self, target_format):
 
378
        pass
 
379
 
 
380
 
 
381
class RepositoryFormatKnit2(RepositoryFormatKnit):
 
382
    """Bzr repository knit format 2.
 
383
 
 
384
    THIS FORMAT IS EXPERIMENTAL
 
385
    This repository format has:
 
386
     - knits for file texts and inventory
 
387
     - hash subdirectory based stores.
 
388
     - knits for revisions and signatures
 
389
     - TextStores for revisions and signatures.
 
390
     - a format marker of its own
 
391
     - an optional 'shared-storage' flag
 
392
     - an optional 'no-working-trees' flag
 
393
     - a LockDir lock
 
394
     - Support for recording full info about the tree root
 
395
 
 
396
    """
 
397
    
 
398
    rich_root_data = True
 
399
 
 
400
    def get_format_string(self):
 
401
        """See RepositoryFormat.get_format_string()."""
 
402
        return "Bazaar Knit Repository Format 2\n"
 
403
 
 
404
    def get_format_description(self):
 
405
        """See RepositoryFormat.get_format_description()."""
 
406
        return "Knit repository format 2"
 
407
 
 
408
    def check_conversion_target(self, target_format):
 
409
        if not target_format.rich_root_data:
 
410
            raise errors.BadConversionTarget(
 
411
                'Does not support rich root data.', target_format)
 
412
 
 
413
    def open(self, a_bzrdir, _found=False, _override_transport=None):
 
414
        """See RepositoryFormat.open().
 
415
        
 
416
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
 
417
                                    repository at a slightly different url
 
418
                                    than normal. I.e. during 'upgrade'.
 
419
        """
 
420
        if not _found:
 
421
            format = RepositoryFormat.find_format(a_bzrdir)
 
422
            assert format.__class__ ==  self.__class__
 
423
        if _override_transport is not None:
 
424
            repo_transport = _override_transport
 
425
        else:
 
426
            repo_transport = a_bzrdir.get_repository_transport(None)
 
427
        control_files = lockable_files.LockableFiles(repo_transport, 'lock',
 
428
                                                     lockdir.LockDir)
 
429
        text_store = self._get_text_store(repo_transport, control_files)
 
430
        control_store = self._get_control_store(repo_transport, control_files)
 
431
        _revision_store = self._get_revision_store(repo_transport, control_files)
 
432
        return KnitRepository2(_format=self,
 
433
                               a_bzrdir=a_bzrdir,
 
434
                               control_files=control_files,
 
435
                               _revision_store=_revision_store,
 
436
                               control_store=control_store,
 
437
                               text_store=text_store)