23
from __future__ import absolute_import
24
from cStringIO import StringIO
28
from ...lazy_import import lazy_import
27
from bzrlib.lazy_import import lazy_import
29
28
lazy_import(globals(), """
33
31
graph as _mod_graph,
36
from breezy.bzr import (
41
revision as _mod_revision,
55
from ...repository import (
58
from ...bzr.repository import (
59
RepositoryFormatMetaDir,
61
from ...sixish import (
65
from .store.text import TextStore
66
from ...bzr.versionedfile import (
48
from bzrlib.decorators import needs_read_lock, needs_write_lock
49
from bzrlib.repository import (
51
MetaDirVersionedFileRepository,
52
MetaDirRepositoryFormat,
56
from bzrlib.store.text import TextStore
57
from bzrlib.tuned_gzip import GzipFile, bytes_to_gzip
58
from bzrlib.versionedfile import (
67
59
AbsentContentFactory,
68
60
FulltextContentFactory,
71
from ...bzr.vf_repository import (
72
InterSameDataRepository,
73
VersionedFileCommitBuilder,
74
VersionedFileRepository,
75
VersionedFileRepositoryFormat,
76
MetaDirVersionedFileRepository,
77
MetaDirVersionedFileRepositoryFormat,
80
from . import bzrdir as weave_bzrdir
83
class AllInOneRepository(VersionedFileRepository):
65
class AllInOneRepository(Repository):
84
66
"""Legacy support - the repository behaviour for all-in-one branches."""
88
70
return xml5.serializer_v5
90
72
def _escape(self, file_or_path):
91
if not isinstance(file_or_path, (str, text_type)):
73
if not isinstance(file_or_path, basestring):
92
74
file_or_path = '/'.join(file_or_path)
93
75
if file_or_path == '':
95
77
return urlutils.escape(osutils.safe_unicode(file_or_path))
97
def __init__(self, _format, a_controldir):
79
def __init__(self, _format, a_bzrdir):
98
80
# we reuse one control files instance.
99
dir_mode = a_controldir._get_dir_mode()
100
file_mode = a_controldir._get_file_mode()
81
dir_mode = a_bzrdir._get_dir_mode()
82
file_mode = a_bzrdir._get_file_mode()
102
84
def get_store(name, compressed=True, prefixed=False):
103
85
# FIXME: This approach of assuming stores are all entirely compressed
118
100
# which allows access to this old info.
119
101
self.inventory_store = get_store('inventory-store')
120
102
self._text_store = get_store('text-store')
121
super(AllInOneRepository, self).__init__(_format, a_controldir, a_controldir._control_files)
103
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files)
123
106
def _all_possible_ids(self):
124
107
"""Return all the possible revisions that we could find."""
125
108
if 'evil' in debug.debug_flags:
126
109
trace.mutter_callsite(
127
110
3, "_all_possible_ids scales with size of history.")
128
with self.lock_read():
129
return [key[-1] for key in self.inventories.keys()]
111
return [key[-1] for key in self.inventories.keys()]
131
114
def _all_revision_ids(self):
132
115
"""Returns a list of all the revision ids in the repository.
149
131
self.inventories.keys()
151
133
def _backup_inventory(self):
152
t = self.controldir._control_files._transport
134
t = self.bzrdir._control_files._transport
153
135
t.copy('inventory.weave', 'inventory.backup.weave')
155
137
def _temp_inventories(self):
156
t = self.controldir._control_files._transport
138
t = self.bzrdir._control_files._transport
157
139
return self._format._get_inventories(t, self, 'inventory.new')
159
141
def get_commit_builder(self, branch, parents, config, timestamp=None,
160
142
timezone=None, committer=None, revprops=None,
161
revision_id=None, lossy=False):
162
144
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
163
result = VersionedFileCommitBuilder(self, parents, config, timestamp,
164
timezone, committer, revprops, revision_id, lossy=lossy)
145
result = CommitBuilder(self, parents, config, timestamp, timezone,
146
committer, revprops, revision_id)
165
147
self.start_write_group()
151
def get_revisions(self, revision_ids):
152
revs = self._get_revisions(revision_ids)
168
155
def _inventory_add_lines(self, revision_id, parents, lines,
169
156
check_content=True):
170
157
"""Store lines in inv_vf and return the sha1 of the inventory."""
195
183
"""Returns the policy for making working trees on new branches."""
186
def revision_graph_can_have_wrong_parents(self):
187
# XXX: This is an old format that we don't support full checking on, so
188
# just claim that checking for this inconsistency is not required.
199
192
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
200
193
"""A subclass of MetaDirRepository to set weave specific policy."""
202
def __init__(self, _format, a_controldir, control_files):
203
super(WeaveMetaDirRepository, self).__init__(
204
_format, a_controldir, control_files)
195
def __init__(self, _format, a_bzrdir, control_files):
196
super(WeaveMetaDirRepository, self).__init__(_format, a_bzrdir, control_files)
205
197
self._serializer = _format._serializer
207
200
def _all_possible_ids(self):
208
201
"""Return all the possible revisions that we could find."""
209
202
if 'evil' in debug.debug_flags:
210
203
trace.mutter_callsite(
211
204
3, "_all_possible_ids scales with size of history.")
212
with self.lock_read():
213
return [key[-1] for key in self.inventories.keys()]
205
return [key[-1] for key in self.inventories.keys()]
215
208
def _all_revision_ids(self):
216
209
"""Returns a list of all the revision ids in the repository.
243
235
def get_commit_builder(self, branch, parents, config, timestamp=None,
244
236
timezone=None, committer=None, revprops=None,
245
revision_id=None, lossy=False):
246
238
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
247
result = VersionedFileCommitBuilder(self, parents, config, timestamp,
248
timezone, committer, revprops, revision_id, lossy=lossy)
239
result = CommitBuilder(self, parents, config, timestamp, timezone,
240
committer, revprops, revision_id)
249
241
self.start_write_group()
252
245
def get_revision(self, revision_id):
253
246
"""Return the Revision object for a named revision"""
254
with self.lock_read():
255
return self.get_revision_reconcile(revision_id)
247
r = self.get_revision_reconcile(revision_id)
257
250
def _inventory_add_lines(self, revision_id, parents, lines,
258
251
check_content=True):
274
270
supports_ghosts = False
275
271
supports_external_lookups = False
276
272
supports_chks = False
277
supports_nesting_repositories = True
278
273
_fetch_order = 'topological'
279
274
_fetch_reconcile = True
280
275
fast_deltas = False
281
supports_leaving_lock = False
282
supports_overriding_transport = False
283
# XXX: This is an old format that we don't support full checking on, so
284
# just claim that checking for this inconsistency is not required.
285
revision_graph_can_have_wrong_parents = False
287
def initialize(self, a_controldir, shared=False, _internal=False):
277
def initialize(self, a_bzrdir, shared=False, _internal=False):
288
278
"""Create a weave repository."""
290
raise errors.IncompatibleFormat(self, a_controldir._format)
280
raise errors.IncompatibleFormat(self, a_bzrdir._format)
292
282
if not _internal:
293
283
# always initialized when the bzrdir is.
294
return self.open(a_controldir, _found=True)
284
return self.open(a_bzrdir, _found=True)
296
286
# Create an empty weave
298
288
weavefile.write_weave_v5(weave.Weave(), sio)
299
289
empty_weave = sio.getvalue()
301
trace.mutter('creating repository in %s.', a_controldir.transport.base)
291
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
303
293
# FIXME: RBC 20060125 don't peek under the covers
304
294
# NB: no need to escape relative paths that are url safe.
305
control_files = lockable_files.LockableFiles(a_controldir.transport,
295
control_files = lockable_files.LockableFiles(a_bzrdir.transport,
306
296
'branch-lock', lockable_files.TransportLock)
307
297
control_files.create_lock()
308
298
control_files.lock_write()
309
transport = a_controldir.transport
299
transport = a_bzrdir.transport
311
transport.mkdir('revision-store',
312
mode=a_controldir._get_dir_mode())
313
transport.mkdir('weaves', mode=a_controldir._get_dir_mode())
301
transport.mkdir_multi(['revision-store', 'weaves'],
302
mode=a_bzrdir._get_dir_mode())
314
303
transport.put_bytes_non_atomic('inventory.weave', empty_weave,
315
mode=a_controldir._get_file_mode())
304
mode=a_bzrdir._get_file_mode())
317
306
control_files.unlock()
318
repository = self.open(a_controldir, _found=True)
319
self._run_post_repo_init_hooks(repository, a_controldir, shared)
307
repository = self.open(a_bzrdir, _found=True)
308
self._run_post_repo_init_hooks(repository, a_bzrdir, shared)
320
309
return repository
322
def open(self, a_controldir, _found=False):
311
def open(self, a_bzrdir, _found=False):
323
312
"""See RepositoryFormat.open()."""
325
314
# we are being called directly and must probe.
326
315
raise NotImplementedError
328
repo_transport = a_controldir.get_repository_transport(None)
329
result = AllInOneRepository(_format=self, a_controldir=a_controldir)
317
repo_transport = a_bzrdir.get_repository_transport(None)
318
control_files = a_bzrdir._control_files
319
result = AllInOneRepository(_format=self, a_bzrdir=a_bzrdir)
330
320
result.revisions = self._get_revisions(repo_transport, result)
331
321
result.signatures = self._get_signatures(repo_transport, result)
332
322
result.inventories = self._get_inventories(repo_transport, result)
538
517
return versionedfile.ThunkedVersionedFiles(base_transport,
539
518
weave.WeaveFile, mapper, repo.is_locked)
541
def initialize(self, a_controldir, shared=False):
520
def initialize(self, a_bzrdir, shared=False):
542
521
"""Create a weave repository.
544
523
:param shared: If true the repository will be initialized as a shared
547
526
# Create an empty weave
549
528
weavefile.write_weave_v5(weave.Weave(), sio)
550
529
empty_weave = sio.getvalue()
552
trace.mutter('creating repository in %s.', a_controldir.transport.base)
531
trace.mutter('creating repository in %s.', a_bzrdir.transport.base)
553
532
dirs = ['revision-store', 'weaves']
554
files = [('inventory.weave', BytesIO(empty_weave)),
533
files = [('inventory.weave', StringIO(empty_weave)),
556
535
utf8_files = [('format', self.get_format_string())]
558
self._upload_blank_content(a_controldir, dirs, files, utf8_files, shared)
559
return self.open(a_controldir=a_controldir, _found=True)
537
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
538
return self.open(a_bzrdir=a_bzrdir, _found=True)
561
def open(self, a_controldir, _found=False, _override_transport=None):
540
def open(self, a_bzrdir, _found=False, _override_transport=None):
562
541
"""See RepositoryFormat.open().
564
543
:param _override_transport: INTERNAL USE ONLY. Allows opening the
566
545
than normal. I.e. during 'upgrade'.
569
format = RepositoryFormatMetaDir.find_format(a_controldir)
548
format = RepositoryFormat.find_format(a_bzrdir)
570
549
if _override_transport is not None:
571
550
repo_transport = _override_transport
573
repo_transport = a_controldir.get_repository_transport(None)
552
repo_transport = a_bzrdir.get_repository_transport(None)
574
553
control_files = lockable_files.LockableFiles(repo_transport,
575
554
'lock', lockdir.LockDir)
576
result = WeaveMetaDirRepository(_format=self, a_controldir=a_controldir,
555
result = WeaveMetaDirRepository(_format=self, a_bzrdir=a_bzrdir,
577
556
control_files=control_files)
578
557
result.revisions = self._get_revisions(repo_transport, result)
579
558
result.signatures = self._get_signatures(repo_transport, result)
763
737
relpaths.add(relpath[:-4])
764
738
paths = list(relpaths)
765
return {self._mapper.unmap(path) for path in paths}
768
class InterWeaveRepo(InterSameDataRepository):
769
"""Optimised code paths between Weave based repositories.
773
def _get_repo_format_to_test(self):
774
return RepositoryFormat7()
777
def is_compatible(source, target):
778
"""Be compatible with known Weave formats.
780
We don't test for the stores being of specific types because that
781
could lead to confusing results, and there is no need to be
785
return (isinstance(source._format, (RepositoryFormat5,
787
RepositoryFormat7)) and
788
isinstance(target._format, (RepositoryFormat5,
791
except AttributeError:
794
def copy_content(self, revision_id=None):
795
"""See InterRepository.copy_content()."""
796
with self.lock_write():
797
# weave specific optimised path:
799
self.target.set_make_working_trees(self.source.make_working_trees())
800
except (errors.RepositoryUpgradeRequired, NotImplementedError):
803
if self.source._transport.listable():
804
with ui.ui_factory.nested_progress_bar() as pb:
805
self.target.texts.insert_record_stream(
806
self.source.texts.get_record_stream(
807
self.source.texts.keys(), 'topological', False))
808
pb.update('Copying inventory', 0, 1)
809
self.target.inventories.insert_record_stream(
810
self.source.inventories.get_record_stream(
811
self.source.inventories.keys(), 'topological', False))
812
self.target.signatures.insert_record_stream(
813
self.source.signatures.get_record_stream(
814
self.source.signatures.keys(),
816
self.target.revisions.insert_record_stream(
817
self.source.revisions.get_record_stream(
818
self.source.revisions.keys(),
819
'topological', True))
821
self.target.fetch(self.source, revision_id=revision_id)
823
def search_missing_revision_ids(self, find_ghosts=True, revision_ids=None,
824
if_present_ids=None, limit=None):
825
"""See InterRepository.search_missing_revision_ids()."""
826
with self.lock_read():
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
source_ids_set = self._present_source_revisions_for(
839
revision_ids, if_present_ids)
840
# source_ids is the worst possible case we may need to pull.
841
# now we want to filter source_ids against what we actually
842
# have in target, but don't try to check for existence where we
843
# know we do not have a revision as that would be pointless.
844
target_ids = set(self.target._all_possible_ids())
845
possibly_present_revisions = target_ids.intersection(
847
actually_present_revisions = set(
848
self.target._eliminate_revisions_not_present(
849
possibly_present_revisions))
850
required_revisions = source_ids_set.difference(
851
actually_present_revisions)
852
if revision_ids is not None:
853
# we used get_ancestry to determine source_ids then we are
854
# assured all revisions referenced are present as they are
855
# installed in topological order. and the tip revision was
856
# validated by get_ancestry.
857
result_set = required_revisions
859
# if we just grabbed the possibly available ids, then
860
# we only have an estimate of whats available and need to
861
# validate that against the revision records.
863
self.source._eliminate_revisions_not_present(
865
if limit is not None:
866
topo_ordered = self.get_graph().iter_topo_order(result_set)
867
result_set = set(itertools.islice(topo_ordered, limit))
868
return self.source.revision_ids_to_search_result(result_set)
871
InterRepository.register_optimiser(InterWeaveRepo)
874
def get_extra_interrepo_test_combinations():
875
from ...bzr import knitrepo
876
return [(InterRepository, RepositoryFormat5(),
877
knitrepo.RepositoryFormatKnit3())]
739
return set([self._mapper.unmap(path) for path in paths])
741
_legacy_formats = [RepositoryFormat4(),