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
24
25
from bzrlib.errors import InvalidRevisionId
26
import bzrlib.gpg as gpg
27
from bzrlib.graph import Graph
28
from bzrlib.inter import InterObject
29
from bzrlib.knit import KnitVersionedFile
25
30
from bzrlib.lockable_files import LockableFiles, TransportLock
26
31
from bzrlib.lockdir import LockDir
27
32
from bzrlib.osutils import safe_unicode
28
33
from bzrlib.revision import NULL_REVISION
29
import bzrlib.errors as errors
30
import bzrlib.gpg as gpg
31
from bzrlib.store import copy_all
32
from bzrlib.store.weave import WeaveStore
34
from bzrlib.store.versioned import VersionedFileStore, WeaveStore
33
35
from bzrlib.store.text import TextStore
34
36
from bzrlib.symbol_versioning import *
35
37
from bzrlib.trace import mutter
36
38
from bzrlib.tree import RevisionTree
39
from bzrlib.tsort import topo_sort
37
40
from bzrlib.testament import Testament
38
41
from bzrlib.tree import EmptyTree
43
from bzrlib.weave import WeaveFile
64
68
inv_text = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
65
69
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())
70
inv_vf = self.control_weaves.get_weave('inventory',
71
self.get_transaction())
72
inv_vf.add_lines(revid, parents, bzrlib.osutils.split_lines(inv_text))
94
98
# yes, this is not suitable for adding with ghosts.
95
99
self.add_inventory(rev_id, inv, rev.parent_ids)
98
bzrlib.xml5.serializer_v5.write_revision(rev, rev_tmp)
100
self.revision_store.add(rev_tmp, rev_id)
101
mutter('added revision_id {%s}', rev_id)
100
self._revision_store.add_revision(rev, self.get_transaction())
104
103
def _all_possible_ids(self):
105
104
"""Return all the possible revisions that we could find."""
106
return self.get_inventory_weave().names()
105
return self.get_inventory_weave().versions()
109
108
def all_revision_ids(self):
133
134
"""Construct the current default format repository in a_bzrdir."""
134
135
return RepositoryFormat.get_default_format().initialize(a_bzrdir)
136
def __init__(self, _format, a_bzrdir, control_files, revision_store):
137
def __init__(self, _format, a_bzrdir, control_files, _revision_store, control_store, text_store):
137
138
"""instantiate a Repository.
139
140
:param _format: The format of the repository on disk.
148
149
# the following are part of the public API for Repository:
149
150
self.bzrdir = a_bzrdir
150
151
self.control_files = control_files
151
self.revision_store = revision_store
152
self._revision_store = _revision_store
153
self.text_store = text_store
154
# backwards compatability
155
self.weave_store = text_store
156
# not right yet - should be more semantically clear ?
158
self.control_store = control_store
159
self.control_weaves = control_store
153
161
def lock_write(self):
154
162
self.control_files.lock_write()
219
227
self.copy_content_into(result, revision_id, basis)
222
231
def has_revision(self, revision_id):
223
"""True if this branch has a copy of the revision.
225
This does not necessarily imply the revision is merge
226
or on the mainline."""
227
return (revision_id is None
228
or self.revision_store.has_id(revision_id))
231
def get_revision_xml_file(self, revision_id):
232
"""Return XML file object for revision object."""
233
if not revision_id or not isinstance(revision_id, basestring):
234
raise InvalidRevisionId(revision_id=revision_id, branch=self)
236
return self.revision_store.get(revision_id)
237
except (IndexError, KeyError):
238
raise bzrlib.errors.NoSuchRevision(self, revision_id)
241
def get_revision_xml(self, revision_id):
242
return self.get_revision_xml_file(revision_id).read()
232
"""True if this repository has a copy of the revision."""
233
return self._revision_store.has_revision_id(revision_id,
234
self.get_transaction())
245
237
def get_revision_reconcile(self, revision_id):
250
242
be used by reconcile, or reconcile-alike commands that are correcting
251
243
or testing the revision graph.
253
xml_file = self.get_revision_xml_file(revision_id)
245
if not revision_id or not isinstance(revision_id, basestring):
246
raise InvalidRevisionId(revision_id=revision_id, branch=self)
247
return self._revision_store.get_revision(revision_id,
248
self.get_transaction())
256
r = bzrlib.xml5.serializer_v5.read_revision(xml_file)
257
except SyntaxError, e:
258
raise bzrlib.errors.BzrError('failed to unpack revision_xml',
262
assert r.revision_id == revision_id
251
def get_revision_xml(self, revision_id):
252
rev = self.get_revision(revision_id)
254
# the current serializer..
255
self._revision_store._serializer.write_revision(rev, rev_tmp)
257
return rev_tmp.getvalue()
266
260
def get_revision(self, revision_id):
284
278
consistency and is only applicable to inventory-weave-for-ancestry
285
279
using repository formats & fetchers.
287
weave_parents = inventory.parent_names(revision.revision_id)
288
weave_names = inventory.names()
281
weave_parents = inventory.get_parents(revision.revision_id)
282
weave_names = inventory.versions()
289
283
for parent_id in revision.parent_ids:
290
284
if parent_id in weave_names:
291
285
# this parent must not be a ghost.
293
287
# but it is a ghost
294
288
raise errors.CorruptRepository(self)
297
def get_revision_sha1(self, revision_id):
298
"""Hash the stored value of a revision, and return it."""
299
# In the future, revision entries will be signed. At that
300
# point, it is probably best *not* to include the signature
301
# in the revision hash. Because that lets you re-sign
302
# the revision, (add signatures/remove signatures) and still
303
# have all hash pointers stay consistent.
304
# But for now, just hash the contents.
305
return bzrlib.osutils.sha_file(self.get_revision_xml_file(revision_id))
307
290
@needs_write_lock
308
291
def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
309
self.revision_store.add(StringIO(gpg_strategy.sign(plaintext)),
292
signature = gpg_strategy.sign(plaintext)
293
self._revision_store.add_revision_signature_text(revision_id,
295
self.get_transaction())
312
297
def fileid_involved_between_revs(self, from_revid, to_revid):
313
298
"""Find file_id(s) which are involved in the changes between revisions.
326
311
# won't be fixed, because AD never saw revision C
327
312
# to cause a conflict which would force a reweave.
328
313
w = self.get_inventory_weave()
329
from_set = set(w.inclusions([w.lookup(from_revid)]))
330
to_set = set(w.inclusions([w.lookup(to_revid)]))
331
included = to_set.difference(from_set)
332
changed = map(w.idx_to_name, included)
314
from_set = set(w.get_ancestry(from_revid))
315
to_set = set(w.get_ancestry(to_revid))
316
changed = to_set.difference(from_set)
333
317
return self._fileid_involved_by_set(changed)
335
319
def fileid_involved(self, last_revid=None):
378
361
w = self.get_inventory_weave()
380
for line in w._weave:
382
# it is ugly, but it is due to the weave structure
383
if not isinstance(line, basestring): continue
364
for lineno, insert, deletes, line in w.walk(changes):
385
365
start = line.find('file_id="')+9
386
366
if start < 9: continue
387
367
end = line.find('"', start)
438
def get_revision_graph_with_ghosts(self, revision_ids=None):
439
"""Return a graph of the revisions with ghosts marked as applicable.
441
:param revision_ids: an iterable of revisions to graph or None for all.
442
:return: a Graph object with the graph reachable from revision_ids.
446
pending = set(self.all_revision_ids())
449
pending = set(revision_ids)
450
required = set(revision_ids)
453
revision_id = pending.pop()
455
rev = self.get_revision(revision_id)
456
except errors.NoSuchRevision:
457
if revision_id in required:
460
result.add_ghost(revision_id)
462
for parent_id in rev.parent_ids:
463
# is this queued or done ?
464
if (parent_id not in pending and
465
parent_id not in done):
467
pending.add(parent_id)
468
result.add_node(revision_id, rev.parent_ids)
458
473
def get_revision_inventory(self, revision_id):
459
474
"""Return inventory of a past revision."""
460
475
# TODO: Unify this with get_inventory()
501
516
if not self.has_revision(revision_id):
502
517
raise errors.NoSuchRevision(self, revision_id)
503
518
w = self.get_inventory_weave()
504
return [None] + map(w.idx_to_name,
505
w.inclusions([w.lookup(revision_id)]))
519
return [None] + w.get_ancestry(revision_id)
508
522
def print_file(self, file, revision_id):
572
586
plaintext = Testament.from_revision(self, revision_id).as_short_text()
573
587
self.store_revision_signature(gpg_strategy, plaintext, revision_id)
590
def has_signature_for_revision_id(self, revision_id):
591
"""Query for a revision signature for revision_id in the repository."""
592
return self._revision_store.has_signature(revision_id,
593
self.get_transaction())
596
def get_signature_text(self, revision_id):
597
"""Return the text for a signature."""
598
return self._revision_store.get_signature_text(revision_id,
599
self.get_transaction())
576
602
class AllInOneRepository(Repository):
577
603
"""Legacy support - the repository behaviour for all-in-one branches."""
579
def __init__(self, _format, a_bzrdir, revision_store):
605
def __init__(self, _format, a_bzrdir, _revision_store, control_store, text_store):
580
606
# we reuse one control files instance.
581
607
dir_mode = a_bzrdir._control_files._dir_mode
582
608
file_mode = a_bzrdir._control_files._file_mode
614
640
# not broken out yet because the controlweaves|inventory_store
615
641
# and text_store | weave_store bits are still different.
616
642
if isinstance(_format, RepositoryFormat4):
643
# cannot remove these - there is still no consistent api
644
# which allows access to this old info.
617
645
self.inventory_store = get_store('inventory-store')
618
self.text_store = get_store('text-store')
619
elif isinstance(_format, RepositoryFormat5):
620
self.control_weaves = get_weave('')
621
self.weave_store = get_weave('weaves')
622
elif isinstance(_format, RepositoryFormat6):
623
self.control_weaves = get_weave('')
624
self.weave_store = get_weave('weaves', prefixed=True)
626
raise errors.BzrError('unreachable code: unexpected repository'
628
revision_store.register_suffix('sig')
629
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, revision_store)
646
text_store = get_store('text-store')
647
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
632
650
class MetaDirRepository(Repository):
633
651
"""Repositories in the new meta-dir layout."""
635
def __init__(self, _format, a_bzrdir, control_files, revision_store):
653
def __init__(self, _format, a_bzrdir, control_files, _revision_store, control_store, text_store):
636
654
super(MetaDirRepository, self).__init__(_format,
641
661
dir_mode = self.control_files._dir_mode
642
662
file_mode = self.control_files._file_mode
655
675
ws.enable_cache = True
658
if isinstance(self._format, RepositoryFormat7):
659
self.control_weaves = get_weave('')
660
self.weave_store = get_weave('weaves', prefixed=True)
661
elif isinstance(self._format, RepositoryFormatKnit1):
662
self.control_weaves = get_weave('')
663
self.weave_store = get_weave('knits', prefixed=True)
665
raise errors.BzrError('unreachable code: unexpected repository'
679
class KnitRepository(MetaDirRepository):
680
"""Knit format repository."""
683
def all_revision_ids(self):
684
"""See Repository.all_revision_ids()."""
685
return self._revision_store.all_revision_ids(self.get_transaction())
669
688
class RepositoryFormat(object):
725
748
"""Return the revision store object for this a_bzrdir."""
726
749
raise NotImplementedError(self._get_revision_store)
728
def _get_rev_store(self,
751
def _get_text_rev_store(self,
734
758
"""Common logic for getting a revision store for a repository.
736
see self._get_revision_store for the method to
760
see self._get_revision_store for the subclass-overridable method to
737
761
get the store for a repository.
740
name = safe_unicode(name)
743
dir_mode = control_files._dir_mode
744
file_mode = control_files._file_mode
745
revision_store =TextStore(transport.clone(name),
747
compressed=compressed,
750
revision_store.register_suffix('sig')
751
return revision_store
763
from bzrlib.store.revision.text import TextRevisionStore
764
dir_mode = control_files._dir_mode
765
file_mode = control_files._file_mode
766
text_store =TextStore(transport.clone(name),
768
compressed=compressed,
771
_revision_store = TextRevisionStore(text_store, serializer)
772
return _revision_store
774
def _get_versioned_file_store(self,
779
versionedfile_class=WeaveFile):
780
weave_transport = control_files._transport.clone(name)
781
dir_mode = control_files._dir_mode
782
file_mode = control_files._file_mode
783
return VersionedFileStore(weave_transport, prefixed=prefixed,
786
versionedfile_class=versionedfile_class)
753
788
def initialize(self, a_bzrdir, shared=False):
754
789
"""Initialize a repository of this format in a_bzrdir.
834
869
control_files.unlock()
835
870
return self.open(a_bzrdir, _found=True)
872
def _get_control_store(self, repo_transport, control_files):
873
"""Return the control store for this repository."""
874
return self._get_versioned_file_store('',
879
def _get_text_store(self, transport, control_files):
880
"""Get a store for file texts for this format."""
881
raise NotImplementedError(self._get_text_store)
837
883
def open(self, a_bzrdir, _found=False):
838
884
"""See RepositoryFormat.open()."""
843
889
repo_transport = a_bzrdir.get_repository_transport(None)
844
890
control_files = a_bzrdir._control_files
845
revision_store = self._get_revision_store(repo_transport, control_files)
891
text_store = self._get_text_store(repo_transport, control_files)
892
control_store = self._get_control_store(repo_transport, control_files)
893
_revision_store = self._get_revision_store(repo_transport, control_files)
846
894
return AllInOneRepository(_format=self,
847
895
a_bzrdir=a_bzrdir,
848
revision_store=revision_store)
896
_revision_store=_revision_store,
897
control_store=control_store,
898
text_store=text_store)
851
901
class RepositoryFormat4(PreSplitOutRepositoryFormat):
930
def _get_control_store(self, repo_transport, control_files):
931
"""Format 4 repositories have no formal control store at this point.
933
This will cause any control-file-needing apis to fail - this is desired.
880
937
def _get_revision_store(self, repo_transport, control_files):
881
938
"""See RepositoryFormat._get_revision_store()."""
882
return self._get_rev_store(repo_transport,
939
from bzrlib.xml4 import serializer_v4
940
return self._get_text_rev_store(repo_transport,
943
serializer=serializer_v4)
945
def _get_text_store(self, transport, control_files):
946
"""See RepositoryFormat._get_text_store()."""
887
949
class RepositoryFormat5(PreSplitOutRepositoryFormat):
900
962
def _get_revision_store(self, repo_transport, control_files):
901
963
"""See RepositoryFormat._get_revision_store()."""
902
964
"""Return the revision store object for this a_bzrdir."""
903
return self._get_rev_store(repo_transport,
965
return self._get_text_rev_store(repo_transport,
970
def _get_text_store(self, transport, control_files):
971
"""See RepositoryFormat._get_text_store()."""
972
return self._get_versioned_file_store('weaves', transport, control_files, prefixed=False)
909
975
class RepositoryFormat6(PreSplitOutRepositoryFormat):
922
988
def _get_revision_store(self, repo_transport, control_files):
923
989
"""See RepositoryFormat._get_revision_store()."""
924
return self._get_rev_store(repo_transport,
990
return self._get_text_rev_store(repo_transport,
996
def _get_text_store(self, transport, control_files):
997
"""See RepositoryFormat._get_text_store()."""
998
return self._get_versioned_file_store('weaves', transport, control_files)
931
1001
class MetaDirRepositoryFormat(RepositoryFormat):
944
1014
control_files.create_lock()
945
1015
return control_files
947
def _get_revision_store(self, repo_transport, control_files):
948
"""See RepositoryFormat._get_revision_store()."""
949
return self._get_rev_store(repo_transport,
956
def open(self, a_bzrdir, _found=False, _override_transport=None):
957
"""See RepositoryFormat.open().
959
:param _override_transport: INTERNAL USE ONLY. Allows opening the
960
repository at a slightly different url
961
than normal. I.e. during 'upgrade'.
964
format = RepositoryFormat.find_format(a_bzrdir)
965
assert format.__class__ == self.__class__
966
if _override_transport is not None:
967
repo_transport = _override_transport
969
repo_transport = a_bzrdir.get_repository_transport(None)
970
control_files = LockableFiles(repo_transport, 'lock', LockDir)
971
revision_store = self._get_revision_store(repo_transport, control_files)
972
return MetaDirRepository(_format=self,
974
control_files=control_files,
975
revision_store=revision_store)
977
1017
def _upload_blank_content(self, a_bzrdir, dirs, files, utf8_files, shared):
978
1018
"""Upload the initial blank content."""
979
1019
control_files = self._create_control_files(a_bzrdir)
1003
1043
- an optional 'no-working-trees' flag
1046
def _get_control_store(self, repo_transport, control_files):
1047
"""Return the control store for this repository."""
1048
return self._get_versioned_file_store('',
1006
1053
def get_format_string(self):
1007
1054
"""See RepositoryFormat.get_format_string()."""
1008
1055
return "Bazaar-NG Repository format 7"
1057
def _get_revision_store(self, repo_transport, control_files):
1058
"""See RepositoryFormat._get_revision_store()."""
1059
return self._get_text_rev_store(repo_transport,
1066
def _get_text_store(self, transport, control_files):
1067
"""See RepositoryFormat._get_text_store()."""
1068
return self._get_versioned_file_store('weaves',
1010
1072
def initialize(self, a_bzrdir, shared=False):
1011
1073
"""Create a weave repository.
1030
1092
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1031
1093
return self.open(a_bzrdir=a_bzrdir, _found=True)
1095
def open(self, a_bzrdir, _found=False, _override_transport=None):
1096
"""See RepositoryFormat.open().
1098
:param _override_transport: INTERNAL USE ONLY. Allows opening the
1099
repository at a slightly different url
1100
than normal. I.e. during 'upgrade'.
1103
format = RepositoryFormat.find_format(a_bzrdir)
1104
assert format.__class__ == self.__class__
1105
if _override_transport is not None:
1106
repo_transport = _override_transport
1108
repo_transport = a_bzrdir.get_repository_transport(None)
1109
control_files = LockableFiles(repo_transport, 'lock', LockDir)
1110
text_store = self._get_text_store(repo_transport, control_files)
1111
control_store = self._get_control_store(repo_transport, control_files)
1112
_revision_store = self._get_revision_store(repo_transport, control_files)
1113
return MetaDirRepository(_format=self,
1115
control_files=control_files,
1116
_revision_store=_revision_store,
1117
control_store=control_store,
1118
text_store=text_store)
1034
1121
class RepositoryFormatKnit1(MetaDirRepositoryFormat):
1035
1122
"""Bzr repository knit format 1.
1045
1132
- a LockDir lock
1135
def _get_control_store(self, repo_transport, control_files):
1136
"""Return the control store for this repository."""
1137
return self._get_versioned_file_store('',
1141
versionedfile_class=KnitVersionedFile)
1048
1143
def get_format_string(self):
1049
1144
"""See RepositoryFormat.get_format_string()."""
1050
1145
return "Bazaar-NG Knit Repository Format 1"
1147
def _get_revision_store(self, repo_transport, control_files):
1148
"""See RepositoryFormat._get_revision_store()."""
1149
from bzrlib.store.revision.knit import KnitRevisionStore
1150
versioned_file_store = VersionedFileStore(
1152
file_mode = control_files._file_mode,
1155
versionedfile_class=KnitVersionedFile)
1156
return KnitRevisionStore(versioned_file_store)
1158
def _get_text_store(self, transport, control_files):
1159
"""See RepositoryFormat._get_text_store()."""
1160
return self._get_versioned_file_store('knits',
1163
versionedfile_class=KnitVersionedFile)
1052
1165
def initialize(self, a_bzrdir, shared=False):
1053
1166
"""Create a knit format 1 repository.
1066
1179
empty_weave = sio.getvalue()
1068
1181
mutter('creating repository in %s.', a_bzrdir.transport.base)
1069
dirs = ['revision-store', 'knits']
1070
files = [('inventory.weave', StringIO(empty_weave)),
1182
dirs = ['revision-store', 'knits', 'control']
1183
files = [('control/inventory.weave', StringIO(empty_weave)),
1072
1185
utf8_files = [('format', self.get_format_string())]
1074
1187
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1188
repo_transport = a_bzrdir.get_repository_transport(None)
1189
control_files = LockableFiles(repo_transport, 'lock', LockDir)
1190
control_store = self._get_control_store(repo_transport, control_files)
1191
transaction = bzrlib.transactions.PassThroughTransaction()
1192
# trigger a write of the inventory store.
1193
control_store.get_weave_or_empty('inventory', transaction)
1194
_revision_store = self._get_revision_store(repo_transport, control_files)
1195
_revision_store.has_revision_id('A', transaction)
1196
_revision_store.get_signature_file(transaction)
1075
1197
return self.open(a_bzrdir=a_bzrdir, _found=True)
1199
def open(self, a_bzrdir, _found=False, _override_transport=None):
1200
"""See RepositoryFormat.open().
1202
:param _override_transport: INTERNAL USE ONLY. Allows opening the
1203
repository at a slightly different url
1204
than normal. I.e. during 'upgrade'.
1207
format = RepositoryFormat.find_format(a_bzrdir)
1208
assert format.__class__ == self.__class__
1209
if _override_transport is not None:
1210
repo_transport = _override_transport
1212
repo_transport = a_bzrdir.get_repository_transport(None)
1213
control_files = LockableFiles(repo_transport, 'lock', LockDir)
1214
text_store = self._get_text_store(repo_transport, control_files)
1215
control_store = self._get_control_store(repo_transport, control_files)
1216
_revision_store = self._get_revision_store(repo_transport, control_files)
1217
return KnitRepository(_format=self,
1219
control_files=control_files,
1220
_revision_store=_revision_store,
1221
control_store=control_store,
1222
text_store=text_store)
1078
1225
# formats which have no format string are not discoverable
1079
1226
# and not independently creatable, so are not registered.
1097
1244
operations with another repository - they will always forward to
1098
1245
InterRepository.get(other).method_name(parameters).
1100
# XXX: FIXME: FUTURE: robertc
1101
# testing of these probably requires a factory in optimiser type, and
1102
# then a test adapter to test each type thoroughly.
1105
1248
_optimisers = set()
1106
1249
"""The available optimised InterRepository types."""
1108
def __init__(self, source, target):
1109
"""Construct a default InterRepository instance. Please use 'get'.
1111
Only subclasses of InterRepository should call
1112
InterRepository.__init__ - clients should call InterRepository.get
1113
instead which will create an optimised InterRepository if possible.
1115
self.source = source
1116
self.target = target
1118
1251
@needs_write_lock
1119
1252
def copy_content(self, revision_id=None, basis=None):
1120
1253
"""Make a complete copy of the content in self into destination.
1164
1297
Returns the copied revision count and the failed revisions in a tuple:
1165
1298
(copied, failures).
1167
from bzrlib.fetch import RepoFetcher
1300
from bzrlib.fetch import GenericRepoFetcher
1168
1301
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1169
1302
self.source, self.source._format, self.target, self.target._format)
1170
f = RepoFetcher(to_repository=self.target,
1171
from_repository=self.source,
1172
last_revision=revision_id,
1303
f = GenericRepoFetcher(to_repository=self.target,
1304
from_repository=self.source,
1305
last_revision=revision_id,
1174
1307
return f.count_copied, f.failed_revisions
1177
def get(klass, repository_source, repository_target):
1178
"""Retrieve a InterRepository worker object for these repositories.
1180
:param repository_source: the repository to be the 'source' member of
1181
the InterRepository instance.
1182
:param repository_target: the repository to be the 'target' member of
1183
the InterRepository instance.
1184
If an optimised InterRepository worker exists it will be used otherwise
1185
a default InterRepository instance will be created.
1187
for provider in klass._optimisers:
1188
if provider.is_compatible(repository_source, repository_target):
1189
return provider(repository_source, repository_target)
1190
return InterRepository(repository_source, repository_target)
1192
1309
def lock_read(self):
1193
1310
"""Take out a logical read lock.
1290
1397
# FIXME do not peek!
1291
1398
if self.source.control_files._transport.listable():
1292
pb = bzrlib.ui.ui_factory.progress_bar()
1293
copy_all(self.source.weave_store,
1294
self.target.weave_store, pb=pb)
1295
pb.update('copying inventory', 0, 1)
1296
self.target.control_weaves.copy_multi(
1297
self.source.control_weaves, ['inventory'])
1298
copy_all(self.source.revision_store,
1299
self.target.revision_store, pb=pb)
1399
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1401
self.target.weave_store.copy_all_ids(
1402
self.source.weave_store,
1404
from_transaction=self.source.get_transaction(),
1405
to_transaction=self.target.get_transaction())
1406
pb.update('copying inventory', 0, 1)
1407
self.target.control_weaves.copy_multi(
1408
self.source.control_weaves, ['inventory'],
1409
from_transaction=self.source.get_transaction(),
1410
to_transaction=self.target.get_transaction())
1411
self.target._revision_store.text_store.copy_all_ids(
1412
self.source._revision_store.text_store,
1301
1417
self.target.fetch(self.source, revision_id=revision_id)
1303
1419
@needs_write_lock
1304
1420
def fetch(self, revision_id=None, pb=None):
1305
1421
"""See InterRepository.fetch()."""
1306
from bzrlib.fetch import RepoFetcher
1422
from bzrlib.fetch import GenericRepoFetcher
1307
1423
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1308
1424
self.source, self.source._format, self.target, self.target._format)
1309
f = RepoFetcher(to_repository=self.target,
1310
from_repository=self.source,
1311
last_revision=revision_id,
1425
f = GenericRepoFetcher(to_repository=self.target,
1426
from_repository=self.source,
1427
last_revision=revision_id,
1313
1429
return f.count_copied, f.failed_revisions
1315
1431
@needs_read_lock
1353
1469
return self.source._eliminate_revisions_not_present(required_topo_revisions)
1472
class InterKnitRepo(InterRepository):
1473
"""Optimised code paths between Knit based repositories."""
1475
_matching_repo_format = RepositoryFormatKnit1()
1476
"""Repository format for testing with."""
1479
def is_compatible(source, target):
1480
"""Be compatible with known Knit formats.
1482
We dont test for the stores being of specific types becase that
1483
could lead to confusing results, and there is no need to be
1487
return (isinstance(source._format, (RepositoryFormatKnit1)) and
1488
isinstance(target._format, (RepositoryFormatKnit1)))
1489
except AttributeError:
1493
def fetch(self, revision_id=None, pb=None):
1494
"""See InterRepository.fetch()."""
1495
from bzrlib.fetch import KnitRepoFetcher
1496
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1497
self.source, self.source._format, self.target, self.target._format)
1498
f = KnitRepoFetcher(to_repository=self.target,
1499
from_repository=self.source,
1500
last_revision=revision_id,
1502
return f.count_copied, f.failed_revisions
1505
def missing_revision_ids(self, revision_id=None):
1506
"""See InterRepository.missing_revision_ids()."""
1507
if revision_id is not None:
1508
source_ids = self.source.get_ancestry(revision_id)
1509
assert source_ids.pop(0) == None
1511
source_ids = self.source._all_possible_ids()
1512
source_ids_set = set(source_ids)
1513
# source_ids is the worst possible case we may need to pull.
1514
# now we want to filter source_ids against what we actually
1515
# have in target, but dont try to check for existence where we know
1516
# we do not have a revision as that would be pointless.
1517
target_ids = set(self.target._all_possible_ids())
1518
possibly_present_revisions = target_ids.intersection(source_ids_set)
1519
actually_present_revisions = set(self.target._eliminate_revisions_not_present(possibly_present_revisions))
1520
required_revisions = source_ids_set.difference(actually_present_revisions)
1521
required_topo_revisions = [rev_id for rev_id in source_ids if rev_id in required_revisions]
1522
if revision_id is not None:
1523
# we used get_ancestry to determine source_ids then we are assured all
1524
# revisions referenced are present as they are installed in topological order.
1525
# and the tip revision was validated by get_ancestry.
1526
return required_topo_revisions
1528
# if we just grabbed the possibly available ids, then
1529
# we only have an estimate of whats available and need to validate
1530
# that against the revision records.
1531
return self.source._eliminate_revisions_not_present(required_topo_revisions)
1356
1533
InterRepository.register_optimiser(InterWeaveRepo)
1534
InterRepository.register_optimiser(InterKnitRepo)
1359
1537
class RepositoryTestProviderAdapter(object):