23
23
from bzrlib.decorators import needs_read_lock, needs_write_lock
24
24
import bzrlib.errors as errors
25
25
from bzrlib.errors import InvalidRevisionId
26
import bzrlib.gpg as gpg
26
27
from bzrlib.inter import InterObject
27
28
from bzrlib.knit import KnitVersionedFile
28
29
from bzrlib.lockable_files import LockableFiles
58
def add_inventory(self, revid, inv, parents):
59
"""Add the inventory inv to the repository as revid.
61
:param parents: The revision ids of the parents that revid
62
is known to have and are in the repository already.
64
returns the sha1 of the serialized inventory.
66
inv_text = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
67
inv_sha1 = bzrlib.osutils.sha_string(inv_text)
68
inv_vf = self.control_weaves.get_weave('inventory',
69
self.get_transaction())
70
inv_vf.add_lines(revid, parents, bzrlib.osutils.split_lines(inv_text))
74
def add_revision(self, rev_id, rev, inv=None, config=None):
75
"""Add rev to the revision store as rev_id.
77
:param rev_id: the revision id to use.
78
:param rev: The revision object.
79
:param inv: The inventory for the revision. if None, it will be looked
80
up in the inventory storer
81
:param config: If None no digital signature will be created.
82
If supplied its signature_needed method will be used
83
to determine if a signature should be made.
85
if config is not None and config.signature_needed():
87
inv = self.get_inventory(rev_id)
88
plaintext = Testament(rev, inv).as_short_text()
89
self.store_revision_signature(
90
gpg.GPGStrategy(config), plaintext, rev_id)
91
if not rev_id in self.get_inventory_weave():
93
raise errors.WeaveRevisionNotPresent(rev_id,
94
self.get_inventory_weave())
96
# yes, this is not suitable for adding with ghosts.
97
self.add_inventory(rev_id, inv, rev.parent_ids)
100
bzrlib.xml5.serializer_v5.write_revision(rev, rev_tmp)
102
self.revision_store.add(rev_tmp, rev_id)
103
mutter('added revision_id {%s}', rev_id)
57
106
def _all_possible_ids(self):
58
107
"""Return all the possible revisions that we could find."""
72
121
for rev_id in self.revision_store:
73
122
rev = self.get_revision(rev_id)
74
123
result_graph[rev_id] = rev.parent_ids
125
for rev_id, parents in result_graph.items():
126
for parent in parents:
127
if not parent in result_graph:
128
del parents[parents.index(parent)]
75
129
return topo_sort(result_graph.items())
76
130
result = self._all_possible_ids()
77
131
return self._eliminate_revisions_not_present(result)
206
260
return self.get_revision_xml_file(revision_id).read()
263
def get_revision_reconcile(self, revision_id):
264
"""'reconcile' helper routine that allows access to a revision always.
266
This variant of get_revision does not cross check the weave graph
267
against the revision one as get_revision does: but it should only
268
be used by reconcile, or reconcile-alike commands that are correcting
269
or testing the revision graph.
271
if not revision_id or not isinstance(revision_id, basestring):
272
raise InvalidRevisionId(revision_id=revision_id, branch=self)
273
return self._revision_store.get_revision(revision_id,
274
self.get_transaction())
209
277
def get_revision(self, revision_id):
210
278
"""Return the Revision object for a named revision"""
211
if not revision_id or not isinstance(revision_id, basestring):
212
raise InvalidRevisionId(revision_id=revision_id, branch=self)
213
return self._revision_store.get_revision(revision_id,
214
self.get_transaction())
279
r = self.get_revision_reconcile(revision_id)
280
# weave corruption can lead to absent revision markers that should be
282
# the following test is reasonably cheap (it needs a single weave read)
283
# and the weave is cached in read transactions. In write transactions
284
# it is not cached but typically we only read a small number of
285
# revisions. For knits when they are introduced we will probably want
286
# to ensure that caching write transactions are in use.
287
inv = self.get_inventory_weave()
288
self._check_revision_parents(r, inv)
291
def _check_revision_parents(self, revision, inventory):
292
"""Private to Repository and Fetch.
294
This checks the parentage of revision in an inventory weave for
295
consistency and is only applicable to inventory-weave-for-ancestry
296
using repository formats & fetchers.
298
weave_parents = inventory.get_parents(revision.revision_id)
299
weave_names = inventory.versions()
300
for parent_id in revision.parent_ids:
301
if parent_id in weave_names:
302
# this parent must not be a ghost.
303
if not parent_id in weave_parents:
305
raise errors.CorruptRepository(self)
216
307
@needs_write_lock
217
308
def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
1005
1096
utf8_files = [('format', self.get_format_string())]
1007
1098
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1099
repo_transport = a_bzrdir.get_repository_transport(None)
1100
control_files = LockableFiles(repo_transport, 'lock')
1101
control_store = self._get_control_store(repo_transport, control_files)
1102
control_store.get_weave_or_empty('inventory',
1103
bzrlib.transactions.PassThroughTransaction())
1008
1104
return self.open(a_bzrdir=a_bzrdir, _found=True)