13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
17
from bzrlib.lazy_import import lazy_import
20
18
lazy_import(globals(), """
23
19
from bzrlib import (
30
26
revision as _mod_revision,
39
37
from bzrlib.decorators import needs_read_lock, needs_write_lock
40
38
from bzrlib.repository import (
43
RepositoryFormatMetaDir,
45
from bzrlib.vf_repository import (
46
InterSameDataRepository,
47
MetaDirVersionedFileRepository,
48
MetaDirVersionedFileRepositoryFormat,
49
VersionedFileCommitBuilder,
50
VersionedFileRootCommitBuilder,
52
from bzrlib import symbol_versioning
41
MetaDirRepositoryFormat,
45
from bzrlib.trace import mutter, mutter_callsite
55
48
class _KnitParentsProvider(object):
60
53
def __repr__(self):
61
54
return 'KnitParentsProvider(%r)' % self._knit
56
@symbol_versioning.deprecated_method(symbol_versioning.one_one)
57
def get_parents(self, revision_ids):
58
"""See graph._StackedParentsProvider.get_parents"""
59
parent_map = self.get_parent_map(revision_ids)
60
return [parent_map.get(r, None) for r in revision_ids]
63
62
def get_parent_map(self, keys):
64
"""See graph.StackedParentsProvider.get_parent_map"""
63
"""See graph._StackedParentsProvider.get_parent_map"""
66
65
for revision_id in keys:
67
66
if revision_id is None:
122
121
def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
124
super(KnitRepository, self).__init__(_format, a_bzrdir, control_files)
123
MetaDirRepository.__init__(self, _format, a_bzrdir, control_files)
125
124
self._commit_builder_class = _commit_builder_class
126
125
self._serializer = _serializer
127
126
self._reconcile_fixes_text_parents = True
127
self._fetch_uses_deltas = True
128
self._fetch_order = 'topological'
130
131
def _all_revision_ids(self):
183
184
result.get_parent_map([('A',)])
187
def fileid_involved_between_revs(self, from_revid, to_revid):
188
"""Find file_id(s) which are involved in the changes between revisions.
190
This determines the set of revisions which are involved, and then
191
finds all file ids affected by those revisions.
193
vf = self._get_revision_vf()
194
from_set = set(vf.get_ancestry(from_revid))
195
to_set = set(vf.get_ancestry(to_revid))
196
changed = to_set.difference(from_set)
197
return self._fileid_involved_by_set(changed)
199
def fileid_involved(self, last_revid=None):
200
"""Find all file_ids modified in the ancestry of last_revid.
202
:param last_revid: If None, last_revision() will be used.
205
changed = set(self.all_revision_ids())
207
changed = set(self.get_ancestry(last_revid))
210
return self._fileid_involved_by_set(changed)
187
213
def get_revision(self, revision_id):
188
214
"""Return the Revision object for a named revision"""
189
215
revision_id = osutils.safe_revision_id(revision_id)
190
216
return self.get_revision_reconcile(revision_id)
192
def _refresh_data(self):
193
if not self.is_locked():
195
if self.is_in_write_group():
196
raise IsInWriteGroupError(self)
197
# Create a new transaction to force all knits to see the scope change.
198
# This is safe because we're outside a write group.
199
self.control_files._finish_transaction()
200
if self.is_write_locked():
201
self.control_files._set_write_transaction()
203
self.control_files._set_read_transaction()
205
218
@needs_write_lock
206
219
def reconcile(self, other=None, thorough=False):
207
220
"""Reconcile this repository."""
209
222
reconciler = KnitReconciler(self, thorough=thorough)
210
223
reconciler.reconcile()
211
224
return reconciler
213
226
def _make_parents_provider(self):
214
227
return _KnitsParentsProvider(self.revisions)
217
class RepositoryFormatKnit(MetaDirVersionedFileRepositoryFormat):
218
"""Bzr repository knit format (generalized).
229
def _find_inconsistent_revision_parents(self):
230
"""Find revisions with different parent lists in the revision object
231
and in the index graph.
233
:returns: an iterator yielding tuples of (revison-id, parents-in-index,
234
parents-in-revision).
236
if not self.is_locked():
237
raise AssertionError()
239
for index_version in vf.keys():
240
parent_map = vf.get_parent_map([index_version])
241
parents_according_to_index = tuple(parent[-1] for parent in
242
parent_map[index_version])
243
revision = self.get_revision(index_version[-1])
244
parents_according_to_revision = tuple(revision.parent_ids)
245
if parents_according_to_index != parents_according_to_revision:
246
yield (index_version[-1], parents_according_to_index,
247
parents_according_to_revision)
249
def _check_for_inconsistent_revision_parents(self):
250
inconsistencies = list(self._find_inconsistent_revision_parents())
252
raise errors.BzrCheckError(
253
"Revision knit has inconsistent parents.")
255
def revision_graph_can_have_wrong_parents(self):
256
# The revision.kndx could potentially claim a revision has a different
257
# parent to the revision text.
261
class RepositoryFormatKnit(MetaDirRepositoryFormat):
262
"""Bzr repository knit format (generalized).
220
264
This repository format has:
221
265
- knits for file texts and inventory
244
288
supports_ghosts = True
245
289
# External lookups are not supported in this format.
246
290
supports_external_lookups = False
248
supports_chks = False
249
_fetch_order = 'topological'
250
_fetch_uses_deltas = True
252
supports_funky_characters = True
253
# The revision.kndx could potentially claim a revision has a different
254
# parent to the revision text.
255
revision_graph_can_have_wrong_parents = True
257
292
def _get_inventories(self, repo_transport, repo, name='inventory'):
258
293
mapper = versionedfile.ConstantMapper(name)
294
329
:param shared: If true the repository will be initialized as a shared
297
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
332
mutter('creating repository in %s.', a_bzrdir.transport.base)
300
335
utf8_files = [('format', self.get_format_string())]
302
337
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
303
338
repo_transport = a_bzrdir.get_repository_transport(None)
304
339
control_files = lockable_files.LockableFiles(repo_transport,
312
347
result.revisions.get_parent_map([('A',)])
313
348
result.signatures.get_parent_map([('A',)])
315
self._run_post_repo_init_hooks(result, a_bzrdir, shared)
318
352
def open(self, a_bzrdir, _found=False, _override_transport=None):
319
353
"""See RepositoryFormat.open().
321
355
:param _override_transport: INTERNAL USE ONLY. Allows opening the
322
356
repository at a slightly different url
323
357
than normal. I.e. during 'upgrade'.
326
format = RepositoryFormatMetaDir.find_format(a_bzrdir)
360
format = RepositoryFormat.find_format(a_bzrdir)
327
361
if _override_transport is not None:
328
362
repo_transport = _override_transport
398
433
repository_class = KnitRepository
399
_commit_builder_class = VersionedFileRootCommitBuilder
434
_commit_builder_class = RootCommitBuilder
400
435
rich_root_data = True
402
436
supports_tree_reference = True
404
438
def _serializer(self):
405
439
return xml7.serializer_v7
407
441
def _get_matching_bzrdir(self):
408
return controldir.format_registry.make_bzrdir('dirstate-with-subtree')
442
return bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
410
444
def _ignore_setting_bzrdir(self, format):
413
447
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
416
def get_format_string(cls):
449
def check_conversion_target(self, target_format):
450
if not target_format.rich_root_data:
451
raise errors.BadConversionTarget(
452
'Does not support rich root data.', target_format)
453
if not getattr(target_format, 'supports_tree_reference', False):
454
raise errors.BadConversionTarget(
455
'Does not support nested trees', target_format)
457
def get_format_string(self):
417
458
"""See RepositoryFormat.get_format_string()."""
418
459
return "Bazaar Knit Repository Format 3 (bzr 0.15)\n"
447
488
return xml6.serializer_v6
449
490
def _get_matching_bzrdir(self):
450
return controldir.format_registry.make_bzrdir('rich-root')
491
return bzrdir.format_registry.make_bzrdir('rich-root')
452
493
def _ignore_setting_bzrdir(self, format):
455
496
_matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
458
def get_format_string(cls):
498
def check_conversion_target(self, target_format):
499
if not target_format.rich_root_data:
500
raise errors.BadConversionTarget(
501
'Does not support rich root data.', target_format)
503
def get_format_string(self):
459
504
"""See RepositoryFormat.get_format_string()."""
460
505
return 'Bazaar Knit Repository Format 4 (bzr 1.0)\n'
462
507
def get_format_description(self):
463
508
"""See RepositoryFormat.get_format_description()."""
464
509
return "Knit repository format 4"
467
class InterKnitRepo(InterSameDataRepository):
468
"""Optimised code paths between Knit based repositories."""
471
def _get_repo_format_to_test(self):
472
return RepositoryFormatKnit1()
475
def is_compatible(source, target):
476
"""Be compatible with known Knit formats.
478
We don't test for the stores being of specific types because that
479
could lead to confusing results, and there is no need to be
483
are_knits = (isinstance(source._format, RepositoryFormatKnit) and
484
isinstance(target._format, RepositoryFormatKnit))
485
except AttributeError:
487
return are_knits and InterRepository._same_model(source, target)
490
def search_missing_revision_ids(self,
491
find_ghosts=True, revision_ids=None, if_present_ids=None,
493
"""See InterRepository.search_missing_revision_ids()."""
494
source_ids_set = self._present_source_revisions_for(
495
revision_ids, if_present_ids)
496
# source_ids is the worst possible case we may need to pull.
497
# now we want to filter source_ids against what we actually
498
# have in target, but don't try to check for existence where we know
499
# we do not have a revision as that would be pointless.
500
target_ids = set(self.target.all_revision_ids())
501
possibly_present_revisions = target_ids.intersection(source_ids_set)
502
actually_present_revisions = set(
503
self.target._eliminate_revisions_not_present(possibly_present_revisions))
504
required_revisions = source_ids_set.difference(actually_present_revisions)
505
if revision_ids is not None:
506
# we used get_ancestry to determine source_ids then we are assured all
507
# revisions referenced are present as they are installed in topological order.
508
# and the tip revision was validated by get_ancestry.
509
result_set = required_revisions
511
# if we just grabbed the possibly available ids, then
512
# we only have an estimate of whats available and need to validate
513
# that against the revision records.
515
self.source._eliminate_revisions_not_present(required_revisions))
516
if limit is not None:
517
topo_ordered = self.source.get_graph().iter_topo_order(result_set)
518
result_set = set(itertools.islice(topo_ordered, limit))
519
return self.source.revision_ids_to_search_result(result_set)
522
InterRepository.register_optimiser(InterKnitRepo)