23
from __future__ import absolute_import
27
24
from cStringIO import StringIO
29
from bzrlib.lazy_import import lazy_import
30
lazy_import(globals(), """
34
revision as _mod_revision,
53
40
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
41
from bzrlib.repository import (
56
RepositoryFormatMetaDir,
43
MetaDirVersionedFileRepository,
44
MetaDirRepositoryFormat,
58
48
from bzrlib.store.text import TextStore
49
from bzrlib.trace import mutter
50
from bzrlib.tuned_gzip import GzipFile, bytes_to_gzip
59
51
from bzrlib.versionedfile import (
60
52
AbsentContentFactory,
61
53
FulltextContentFactory,
64
from bzrlib.vf_repository import (
65
InterSameDataRepository,
66
VersionedFileCommitBuilder,
67
VersionedFileRepository,
68
VersionedFileRepositoryFormat,
69
MetaDirVersionedFileRepository,
70
MetaDirVersionedFileRepositoryFormat,
73
from bzrlib.plugins.weave_fmt import bzrdir as weave_bzrdir
76
class AllInOneRepository(VersionedFileRepository):
58
class AllInOneRepository(Repository):
77
59
"""Legacy support - the repository behaviour for all-in-one branches."""
80
def _serializer(self):
81
return xml5.serializer_v5
83
def _escape(self, file_or_path):
84
if not isinstance(file_or_path, basestring):
85
file_or_path = '/'.join(file_or_path)
86
if file_or_path == '':
88
return urlutils.escape(osutils.safe_unicode(file_or_path))
61
_serializer = xml5.serializer_v5
90
63
def __init__(self, _format, a_bzrdir):
91
64
# we reuse one control files instance.
107
80
# not broken out yet because the controlweaves|inventory_store
108
81
# and texts bits are still different.
109
82
if isinstance(_format, RepositoryFormat4):
110
# cannot remove these - there is still no consistent api
83
# cannot remove these - there is still no consistent api
111
84
# which allows access to this old info.
112
85
self.inventory_store = get_store('inventory-store')
113
86
self._text_store = get_store('text-store')
114
87
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files)
88
self._fetch_order = 'topological'
89
self._fetch_reconcile = True
117
92
def _all_possible_ids(self):
118
93
"""Return all the possible revisions that we could find."""
119
94
if 'evil' in debug.debug_flags:
120
trace.mutter_callsite(
121
3, "_all_possible_ids scales with size of history.")
95
mutter_callsite(3, "_all_possible_ids scales with size of history.")
122
96
return [key[-1] for key in self.inventories.keys()]
125
99
def _all_revision_ids(self):
126
"""Returns a list of all the revision ids in the repository.
100
"""Returns a list of all the revision ids in the repository.
128
These are in as much topological order as the underlying store can
102
These are in as much topological order as the underlying store can
129
103
present: for weaves ghosts may lead to a lack of correctness until
130
104
the reweave updates the parents list.
152
126
def get_commit_builder(self, branch, parents, config, timestamp=None,
153
127
timezone=None, committer=None, revprops=None,
154
revision_id=None, lossy=False):
155
129
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
156
result = VersionedFileCommitBuilder(self, parents, config, timestamp,
157
timezone, committer, revprops, revision_id, lossy=lossy)
130
result = CommitBuilder(self, parents, config, timestamp, timezone,
131
committer, revprops, revision_id)
158
132
self.start_write_group()
188
162
:param new_value: True to restore the default, False to disable making
191
raise errors.RepositoryUpgradeRequired(self.user_url)
165
raise errors.RepositoryUpgradeRequired(self.bzrdir.root_transport.base)
193
167
def make_working_trees(self):
194
168
"""Returns the policy for making working trees on new branches."""
171
def revision_graph_can_have_wrong_parents(self):
172
# XXX: This is an old format that we don't support full checking on, so
173
# just claim that checking for this inconsistency is not required.
198
177
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
199
178
"""A subclass of MetaDirRepository to set weave specific policy."""
180
_serializer = xml5.serializer_v5
201
182
def __init__(self, _format, a_bzrdir, control_files):
202
183
super(WeaveMetaDirRepository, self).__init__(_format, a_bzrdir, control_files)
203
self._serializer = _format._serializer
184
self._fetch_order = 'topological'
185
self._fetch_reconcile = True
206
188
def _all_possible_ids(self):
207
189
"""Return all the possible revisions that we could find."""
208
190
if 'evil' in debug.debug_flags:
209
trace.mutter_callsite(
210
3, "_all_possible_ids scales with size of history.")
191
mutter_callsite(3, "_all_possible_ids scales with size of history.")
211
192
return [key[-1] for key in self.inventories.keys()]
214
195
def _all_revision_ids(self):
215
"""Returns a list of all the revision ids in the repository.
196
"""Returns a list of all the revision ids in the repository.
217
These are in as much topological order as the underlying store can
198
These are in as much topological order as the underlying store can
218
199
present: for weaves ghosts may lead to a lack of correctness until
219
200
the reweave updates the parents list.
241
222
def get_commit_builder(self, branch, parents, config, timestamp=None,
242
223
timezone=None, committer=None, revprops=None,
243
revision_id=None, lossy=False):
244
225
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
245
result = VersionedFileCommitBuilder(self, parents, config, timestamp,
246
timezone, committer, revprops, revision_id, lossy=lossy)
226
result = CommitBuilder(self, parents, config, timestamp, timezone,
227
committer, revprops, revision_id)
247
228
self.start_write_group()
264
245
return self.inventories.add_lines((revision_id,), final_parents, lines,
265
246
check_content=check_content)[0]
268
class PreSplitOutRepositoryFormat(VersionedFileRepositoryFormat):
248
def revision_graph_can_have_wrong_parents(self):
252
class PreSplitOutRepositoryFormat(RepositoryFormat):
269
253
"""Base class for the pre split out repository formats."""
271
255
rich_root_data = False
272
256
supports_tree_reference = False
273
257
supports_ghosts = False
274
258
supports_external_lookups = False
275
supports_chks = False
276
supports_nesting_repositories = True
277
_fetch_order = 'topological'
278
_fetch_reconcile = True
280
supports_leaving_lock = False
281
# XXX: This is an old format that we don't support full checking on, so
282
# just claim that checking for this inconsistency is not required.
283
revision_graph_can_have_wrong_parents = False
285
260
def initialize(self, a_bzrdir, shared=False, _internal=False):
286
261
"""Create a weave repository."""
399
374
_versionedfile_class = weave.WeaveFile
400
_matchingbzrdir = weave_bzrdir.BzrDirFormat5()
401
supports_funky_characters = False
375
_matchingbzrdir = bzrdir.BzrDirFormat5()
404
def _serializer(self):
405
return xml5.serializer_v5
378
super(RepositoryFormat5, self).__init__()
379
self._fetch_order = 'topological'
380
self._fetch_reconcile = True
407
382
def get_format_description(self):
408
383
"""See RepositoryFormat.get_format_description()."""
409
384
return "Weave repository format 5"
411
def network_name(self):
412
"""The network name for this format is the control dirs disk label."""
413
return self._matchingbzrdir.get_format_string()
415
386
def _get_inventories(self, repo_transport, repo, name='inventory'):
416
387
mapper = versionedfile.ConstantMapper(name)
417
388
return versionedfile.ThunkedVersionedFiles(repo_transport,
418
389
weave.WeaveFile, mapper, repo.is_locked)
420
391
def _get_revisions(self, repo_transport, repo):
392
from bzrlib.xml5 import serializer_v5
421
393
return RevisionTextStore(repo_transport.clone('revision-store'),
422
xml5.serializer_v5, False, versionedfile.PrefixMapper(),
394
serializer_v5, False, versionedfile.PrefixMapper(),
423
395
repo.is_locked, repo.is_write_locked)
425
397
def _get_signatures(self, repo_transport, repo):
446
418
_versionedfile_class = weave.WeaveFile
447
_matchingbzrdir = weave_bzrdir.BzrDirFormat6()
448
supports_funky_characters = False
450
def _serializer(self):
451
return xml5.serializer_v5
419
_matchingbzrdir = bzrdir.BzrDirFormat6()
422
super(RepositoryFormat6, self).__init__()
423
self._fetch_order = 'topological'
424
self._fetch_reconcile = True
453
426
def get_format_description(self):
454
427
"""See RepositoryFormat.get_format_description()."""
455
428
return "Weave repository format 6"
457
def network_name(self):
458
"""The network name for this format is the control dirs disk label."""
459
return self._matchingbzrdir.get_format_string()
461
430
def _get_inventories(self, repo_transport, repo, name='inventory'):
462
431
mapper = versionedfile.ConstantMapper(name)
463
432
return versionedfile.ThunkedVersionedFiles(repo_transport,
464
433
weave.WeaveFile, mapper, repo.is_locked)
466
435
def _get_revisions(self, repo_transport, repo):
436
from bzrlib.xml5 import serializer_v5
467
437
return RevisionTextStore(repo_transport.clone('revision-store'),
468
xml5.serializer_v5, False, versionedfile.HashPrefixMapper(),
438
serializer_v5, False, versionedfile.HashPrefixMapper(),
469
439
repo.is_locked, repo.is_write_locked)
471
441
def _get_signatures(self, repo_transport, repo):
514
473
"""See RepositoryFormat.get_format_description()."""
515
474
return "Weave repository format 7"
476
def check_conversion_target(self, target_format):
517
479
def _get_inventories(self, repo_transport, repo, name='inventory'):
518
480
mapper = versionedfile.ConstantMapper(name)
519
481
return versionedfile.ThunkedVersionedFiles(repo_transport,
520
482
weave.WeaveFile, mapper, repo.is_locked)
522
484
def _get_revisions(self, repo_transport, repo):
485
from bzrlib.xml5 import serializer_v5
523
486
return RevisionTextStore(repo_transport.clone('revision-store'),
524
xml5.serializer_v5, True, versionedfile.HashPrefixMapper(),
487
serializer_v5, True, versionedfile.HashPrefixMapper(),
525
488
repo.is_locked, repo.is_write_locked)
527
490
def _get_signatures(self, repo_transport, repo):
546
509
weavefile.write_weave_v5(weave.Weave(), sio)
547
510
empty_weave = sio.getvalue()
549
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
512
mutter('creating repository in %s.', a_bzrdir.transport.base)
550
513
dirs = ['revision-store', 'weaves']
551
files = [('inventory.weave', StringIO(empty_weave)),
514
files = [('inventory.weave', StringIO(empty_weave)),
553
516
utf8_files = [('format', self.get_format_string())]
555
518
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
556
519
return self.open(a_bzrdir=a_bzrdir, _found=True)
558
521
def open(self, a_bzrdir, _found=False, _override_transport=None):
559
522
"""See RepositoryFormat.open().
561
524
:param _override_transport: INTERNAL USE ONLY. Allows opening the
562
525
repository at a slightly different url
563
526
than normal. I.e. during 'upgrade'.
566
format = RepositoryFormatMetaDir.find_format(a_bzrdir)
529
format = RepositoryFormat.find_format(a_bzrdir)
567
530
if _override_transport is not None:
568
531
repo_transport = _override_transport
759
711
paths = list(relpaths)
760
712
return set([self._mapper.unmap(path) for path in paths])
763
class InterWeaveRepo(InterSameDataRepository):
764
"""Optimised code paths between Weave based repositories.
768
def _get_repo_format_to_test(self):
769
return RepositoryFormat7()
772
def is_compatible(source, target):
773
"""Be compatible with known Weave formats.
775
We don't test for the stores being of specific types because that
776
could lead to confusing results, and there is no need to be
780
return (isinstance(source._format, (RepositoryFormat5,
782
RepositoryFormat7)) and
783
isinstance(target._format, (RepositoryFormat5,
786
except AttributeError:
790
def copy_content(self, revision_id=None):
791
"""See InterRepository.copy_content()."""
792
# weave specific optimised path:
794
self.target.set_make_working_trees(self.source.make_working_trees())
795
except (errors.RepositoryUpgradeRequired, NotImplemented):
798
if self.source._transport.listable():
799
pb = ui.ui_factory.nested_progress_bar()
801
self.target.texts.insert_record_stream(
802
self.source.texts.get_record_stream(
803
self.source.texts.keys(), 'topological', False))
804
pb.update('Copying inventory', 0, 1)
805
self.target.inventories.insert_record_stream(
806
self.source.inventories.get_record_stream(
807
self.source.inventories.keys(), 'topological', False))
808
self.target.signatures.insert_record_stream(
809
self.source.signatures.get_record_stream(
810
self.source.signatures.keys(),
812
self.target.revisions.insert_record_stream(
813
self.source.revisions.get_record_stream(
814
self.source.revisions.keys(),
815
'topological', True))
819
self.target.fetch(self.source, revision_id=revision_id)
822
def search_missing_revision_ids(self,
823
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
824
find_ghosts=True, revision_ids=None, if_present_ids=None,
826
"""See InterRepository.search_missing_revision_ids()."""
827
# we want all revisions to satisfy revision_id in source.
828
# but we don't want to stat every file here and there.
829
# we want then, all revisions other needs to satisfy revision_id
830
# checked, but not those that we have locally.
831
# so the first thing is to get a subset of the revisions to
832
# satisfy revision_id in source, and then eliminate those that
833
# we do already have.
834
# this is slow on high latency connection to self, but as this
835
# disk format scales terribly for push anyway due to rewriting
836
# inventory.weave, this is considered acceptable.
838
if symbol_versioning.deprecated_passed(revision_id):
839
symbol_versioning.warn(
840
'search_missing_revision_ids(revision_id=...) was '
841
'deprecated in 2.4. Use revision_ids=[...] instead.',
842
DeprecationWarning, stacklevel=2)
843
if revision_ids is not None:
844
raise AssertionError(
845
'revision_ids is mutually exclusive with revision_id')
846
if revision_id is not None:
847
revision_ids = [revision_id]
849
source_ids_set = self._present_source_revisions_for(
850
revision_ids, if_present_ids)
851
# source_ids is the worst possible case we may need to pull.
852
# now we want to filter source_ids against what we actually
853
# have in target, but don't try to check for existence where we know
854
# we do not have a revision as that would be pointless.
855
target_ids = set(self.target._all_possible_ids())
856
possibly_present_revisions = target_ids.intersection(source_ids_set)
857
actually_present_revisions = set(
858
self.target._eliminate_revisions_not_present(possibly_present_revisions))
859
required_revisions = source_ids_set.difference(actually_present_revisions)
860
if revision_ids is not None:
861
# we used get_ancestry to determine source_ids then we are assured all
862
# revisions referenced are present as they are installed in topological order.
863
# and the tip revision was validated by get_ancestry.
864
result_set = required_revisions
866
# if we just grabbed the possibly available ids, then
867
# we only have an estimate of whats available and need to validate
868
# that against the revision records.
870
self.source._eliminate_revisions_not_present(required_revisions))
871
if limit is not None:
872
topo_ordered = self.get_graph().iter_topo_order(result_set)
873
result_set = set(itertools.islice(topo_ordered, limit))
874
return self.source.revision_ids_to_search_result(result_set)
877
InterRepository.register_optimiser(InterWeaveRepo)
880
def get_extra_interrepo_test_combinations():
881
from bzrlib.repofmt import knitrepo
882
return [(InterRepository, RepositoryFormat5(),
883
knitrepo.RepositoryFormatKnit3())]
714
_legacy_formats = [RepositoryFormat4(),