~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Aaron Bentley
  • Date: 2006-03-07 05:59:14 UTC
  • mfrom: (1558.1.20 Aaron's integration)
  • mto: This revision was merged to the branch mainline in revision 1595.
  • Revision ID: aaron.bentley@utoronto.ca-20060307055914-a88728997afceb90
MergeĀ fromĀ mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
19
19
from unittest import TestSuite
20
20
import xml.sax.saxutils
21
21
 
22
 
 
 
22
import bzrlib.bzrdir as bzrdir
23
23
from bzrlib.decorators import needs_read_lock, needs_write_lock
24
 
import bzrlib.errors as errors
25
24
from bzrlib.errors import InvalidRevisionId
26
 
from bzrlib.lockable_files import LockableFiles
 
25
from bzrlib.lockable_files import LockableFiles, TransportLock
 
26
from bzrlib.lockdir import LockDir
27
27
from bzrlib.osutils import safe_unicode
28
28
from bzrlib.revision import NULL_REVISION
 
29
import bzrlib.errors as errors
 
30
import bzrlib.gpg as gpg
29
31
from bzrlib.store import copy_all
30
32
from bzrlib.store.weave import WeaveStore
31
33
from bzrlib.store.text import TextStore
50
52
    remote) disk.
51
53
    """
52
54
 
 
55
    @needs_write_lock
 
56
    def add_inventory(self, revid, inv, parents):
 
57
        """Add the inventory inv to the repository as revid.
 
58
        
 
59
        :param parents: The revision ids of the parents that revid
 
60
                        is known to have and are in the repository already.
 
61
 
 
62
        returns the sha1 of the serialized inventory.
 
63
        """
 
64
        inv_text = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
65
        inv_sha1 = bzrlib.osutils.sha_string(inv_text)
 
66
        self.control_weaves.add_text('inventory', revid,
 
67
                   bzrlib.osutils.split_lines(inv_text), parents,
 
68
                   self.get_transaction())
 
69
        return inv_sha1
 
70
 
 
71
    @needs_write_lock
 
72
    def add_revision(self, rev_id, rev, inv=None, config=None):
 
73
        """Add rev to the revision store as rev_id.
 
74
 
 
75
        :param rev_id: the revision id to use.
 
76
        :param rev: The revision object.
 
77
        :param inv: The inventory for the revision. if None, it will be looked
 
78
                    up in the inventory storer
 
79
        :param config: If None no digital signature will be created.
 
80
                       If supplied its signature_needed method will be used
 
81
                       to determine if a signature should be made.
 
82
        """
 
83
        if config is not None and config.signature_needed():
 
84
            if inv is None:
 
85
                inv = self.get_inventory(rev_id)
 
86
            plaintext = Testament(rev, inv).as_short_text()
 
87
            self.store_revision_signature(
 
88
                gpg.GPGStrategy(config), plaintext, rev_id)
 
89
        if not rev_id in self.get_inventory_weave():
 
90
            if inv is None:
 
91
                raise errors.WeaveRevisionNotPresent(rev_id,
 
92
                                                     self.get_inventory_weave())
 
93
            else:
 
94
                # yes, this is not suitable for adding with ghosts.
 
95
                self.add_inventory(rev_id, inv, rev.parent_ids)
 
96
            
 
97
        rev_tmp = StringIO()
 
98
        bzrlib.xml5.serializer_v5.write_revision(rev, rev_tmp)
 
99
        rev_tmp.seek(0)
 
100
        self.revision_store.add(rev_tmp, rev_id)
 
101
        mutter('added revision_id {%s}', rev_id)
 
102
 
53
103
    @needs_read_lock
54
104
    def _all_possible_ids(self):
55
105
        """Return all the possible revisions that we could find."""
106
156
    def lock_read(self):
107
157
        self.control_files.lock_read()
108
158
 
 
159
    def is_locked(self):
 
160
        return self.control_files.is_locked()
 
161
 
109
162
    @needs_read_lock
110
163
    def missing_revision_ids(self, other, revision_id=None):
111
164
        """Return the revision ids that other has that this does not.
189
242
        return self.get_revision_xml_file(revision_id).read()
190
243
 
191
244
    @needs_read_lock
192
 
    def get_revision(self, revision_id):
193
 
        """Return the Revision object for a named revision"""
 
245
    def get_revision_reconcile(self, revision_id):
 
246
        """'reconcile' helper routine that allows access to a revision always.
 
247
        
 
248
        This variant of get_revision does not cross check the weave graph
 
249
        against the revision one as get_revision does: but it should only
 
250
        be used by reconcile, or reconcile-alike commands that are correcting
 
251
        or testing the revision graph.
 
252
        """
194
253
        xml_file = self.get_revision_xml_file(revision_id)
195
254
 
196
255
        try:
204
263
        return r
205
264
 
206
265
    @needs_read_lock
 
266
    def get_revision(self, revision_id):
 
267
        """Return the Revision object for a named revision"""
 
268
        r = self.get_revision_reconcile(revision_id)
 
269
        # weave corruption can lead to absent revision markers that should be
 
270
        # present.
 
271
        # the following test is reasonably cheap (it needs a single weave read)
 
272
        # and the weave is cached in read transactions. In write transactions
 
273
        # it is not cached but typically we only read a small number of
 
274
        # revisions. For knits when they are introduced we will probably want
 
275
        # to ensure that caching write transactions are in use.
 
276
        inv = self.get_inventory_weave()
 
277
        self._check_revision_parents(r, inv)
 
278
        return r
 
279
 
 
280
    def _check_revision_parents(self, revision, inventory):
 
281
        """Private to Repository and Fetch.
 
282
        
 
283
        This checks the parentage of revision in an inventory weave for 
 
284
        consistency and is only applicable to inventory-weave-for-ancestry
 
285
        using repository formats & fetchers.
 
286
        """
 
287
        weave_parents = inventory.parent_names(revision.revision_id)
 
288
        weave_names = inventory.names()
 
289
        for parent_id in revision.parent_ids:
 
290
            if parent_id in weave_names:
 
291
                # this parent must not be a ghost.
 
292
                if not parent_id in weave_parents:
 
293
                    # but it is a ghost
 
294
                    raise errors.CorruptRepository(self)
 
295
 
 
296
    @needs_read_lock
207
297
    def get_revision_sha1(self, revision_id):
208
298
        """Hash the stored value of a revision, and return it."""
209
299
        # In the future, revision entries will be signed. At that
339
429
        return self.get_revision(revision_id).inventory_sha1
340
430
 
341
431
    @needs_read_lock
 
432
    def get_revision_graph(self, revision_id=None):
 
433
        """Return a dictionary containing the revision graph.
 
434
        
 
435
        :return: a dictionary of revision_id->revision_parents_list.
 
436
        """
 
437
        weave = self.get_inventory_weave()
 
438
        all_revisions = self._eliminate_revisions_not_present(weave.names())
 
439
        entire_graph = dict([(node, weave.parent_names(node)) for 
 
440
                             node in all_revisions])
 
441
        if revision_id is None:
 
442
            return entire_graph
 
443
        elif revision_id not in entire_graph:
 
444
            raise errors.NoSuchRevision(self, revision_id)
 
445
        else:
 
446
            # add what can be reached from revision_id
 
447
            result = {}
 
448
            pending = set([revision_id])
 
449
            while len(pending) > 0:
 
450
                node = pending.pop()
 
451
                result[node] = entire_graph[node]
 
452
                for revision_id in result[node]:
 
453
                    if revision_id not in result:
 
454
                        pending.add(revision_id)
 
455
            return result
 
456
 
 
457
    @needs_read_lock
342
458
    def get_revision_inventory(self, revision_id):
343
459
        """Return inventory of a past revision."""
344
460
        # TODO: Unify this with get_inventory()
416
532
    def get_transaction(self):
417
533
        return self.control_files.get_transaction()
418
534
 
 
535
    def revision_parents(self, revid):
 
536
        return self.get_inventory_weave().parent_names(revid)
 
537
 
419
538
    @needs_write_lock
420
539
    def set_make_working_trees(self, new_value):
421
540
        """Set the policy flag for making working trees when creating branches.
697
816
 
698
817
        mutter('creating repository in %s.', a_bzrdir.transport.base)
699
818
        dirs = ['revision-store', 'weaves']
700
 
        lock_file = 'branch-lock'
701
 
        files = [('inventory.weave', StringIO(empty_weave)), 
 
819
        files = [('inventory.weave', StringIO(empty_weave)),
702
820
                 ]
703
821
        
704
822
        # FIXME: RBC 20060125 dont peek under the covers
705
823
        # NB: no need to escape relative paths that are url safe.
706
 
        control_files = LockableFiles(a_bzrdir.transport, 'branch-lock')
 
824
        control_files = LockableFiles(a_bzrdir.transport, 'branch-lock',
 
825
                                      TransportLock)
 
826
        control_files.create_lock()
707
827
        control_files.lock_write()
708
828
        control_files._transport.mkdir_multi(dirs,
709
829
                mode=control_files._dir_mode)
819
939
        """Create the required files and the initial control_files object."""
820
940
        # FIXME: RBC 20060125 dont peek under the covers
821
941
        # NB: no need to escape relative paths that are url safe.
822
 
        lock_file = 'lock'
823
942
        repository_transport = a_bzrdir.get_repository_transport(self)
824
 
        repository_transport.put(lock_file, StringIO()) # TODO get the file mode from the bzrdir lock files., mode=file_mode)
825
 
        control_files = LockableFiles(repository_transport, 'lock')
 
943
        control_files = LockableFiles(repository_transport, 'lock', LockDir)
 
944
        control_files.create_lock()
826
945
        return control_files
827
946
 
828
947
    def _get_revision_store(self, repo_transport, control_files):
848
967
            repo_transport = _override_transport
849
968
        else:
850
969
            repo_transport = a_bzrdir.get_repository_transport(None)
851
 
        control_files = LockableFiles(repo_transport, 'lock')
 
970
        control_files = LockableFiles(repo_transport, 'lock', LockDir)
852
971
        revision_store = self._get_revision_store(repo_transport, control_files)
853
972
        return MetaDirRepository(_format=self,
854
973
                                 a_bzrdir=a_bzrdir,
859
978
        """Upload the initial blank content."""
860
979
        control_files = self._create_control_files(a_bzrdir)
861
980
        control_files.lock_write()
862
 
        control_files._transport.mkdir_multi(dirs,
863
 
                mode=control_files._dir_mode)
864
981
        try:
 
982
            control_files._transport.mkdir_multi(dirs,
 
983
                    mode=control_files._dir_mode)
865
984
            for file, content in files:
866
985
                control_files.put(file, content)
867
986
            for file, content in utf8_files:
923
1042
     - a format marker of its own
924
1043
     - an optional 'shared-storage' flag
925
1044
     - an optional 'no-working-trees' flag
 
1045
     - a LockDir lock
926
1046
    """
927
1047
 
928
1048
    def get_format_string(self):