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
25
27
from bzrlib.graph import Graph
28
from bzrlib.inter import InterObject
29
from bzrlib.knit import KnitVersionedFile
26
30
from bzrlib.lockable_files import LockableFiles, TransportLock
27
31
from bzrlib.lockdir import LockDir
28
32
from bzrlib.osutils import safe_unicode
29
33
from bzrlib.revision import NULL_REVISION
30
import bzrlib.errors as errors
31
import bzrlib.gpg as gpg
32
from bzrlib.store import copy_all
33
from bzrlib.store.weave import WeaveStore
34
from bzrlib.store.versioned import VersionedFileStore, WeaveStore
34
35
from bzrlib.store.text import TextStore
35
36
from bzrlib.symbol_versioning import *
36
37
from bzrlib.trace import mutter
37
38
from bzrlib.tree import RevisionTree
39
from bzrlib.tsort import topo_sort
38
40
from bzrlib.testament import Testament
39
41
from bzrlib.tree import EmptyTree
43
from bzrlib.weave import WeaveFile
65
68
inv_text = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
66
69
inv_sha1 = bzrlib.osutils.sha_string(inv_text)
67
self.control_weaves.add_text('inventory', revid,
68
bzrlib.osutils.split_lines(inv_text), parents,
69
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))
95
98
# yes, this is not suitable for adding with ghosts.
96
99
self.add_inventory(rev_id, inv, rev.parent_ids)
99
bzrlib.xml5.serializer_v5.write_revision(rev, rev_tmp)
101
self.revision_store.add(rev_tmp, rev_id)
102
mutter('added revision_id {%s}', rev_id)
100
self._revision_store.add_revision(rev, self.get_transaction())
105
103
def _all_possible_ids(self):
106
104
"""Return all the possible revisions that we could find."""
107
return self.get_inventory_weave().names()
105
return self.get_inventory_weave().versions()
110
108
def all_revision_ids(self):
134
134
"""Construct the current default format repository in a_bzrdir."""
135
135
return RepositoryFormat.get_default_format().initialize(a_bzrdir)
137
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):
138
138
"""instantiate a Repository.
140
140
:param _format: The format of the repository on disk.
149
149
# the following are part of the public API for Repository:
150
150
self.bzrdir = a_bzrdir
151
151
self.control_files = control_files
152
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
154
161
def lock_write(self):
155
162
self.control_files.lock_write()
220
227
self.copy_content_into(result, revision_id, basis)
223
231
def has_revision(self, revision_id):
224
"""True if this branch has a copy of the revision.
226
This does not necessarily imply the revision is merge
227
or on the mainline."""
228
return (revision_id is None
229
or self.revision_store.has_id(revision_id))
232
def get_revision_xml_file(self, revision_id):
233
"""Return XML file object for revision object."""
234
if not revision_id or not isinstance(revision_id, basestring):
235
raise InvalidRevisionId(revision_id=revision_id, branch=self)
237
return self.revision_store.get(revision_id)
238
except (IndexError, KeyError):
239
raise bzrlib.errors.NoSuchRevision(self, revision_id)
242
def get_revision_xml(self, revision_id):
243
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())
246
237
def get_revision_reconcile(self, revision_id):
251
242
be used by reconcile, or reconcile-alike commands that are correcting
252
243
or testing the revision graph.
254
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())
257
r = bzrlib.xml5.serializer_v5.read_revision(xml_file)
258
except SyntaxError, e:
259
raise bzrlib.errors.BzrError('failed to unpack revision_xml',
263
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()
267
260
def get_revision(self, revision_id):
285
278
consistency and is only applicable to inventory-weave-for-ancestry
286
279
using repository formats & fetchers.
288
weave_parents = inventory.parent_names(revision.revision_id)
289
weave_names = inventory.names()
281
weave_parents = inventory.get_parents(revision.revision_id)
282
weave_names = inventory.versions()
290
283
for parent_id in revision.parent_ids:
291
284
if parent_id in weave_names:
292
285
# this parent must not be a ghost.
294
287
# but it is a ghost
295
288
raise errors.CorruptRepository(self)
298
def get_revision_sha1(self, revision_id):
299
"""Hash the stored value of a revision, and return it."""
300
# In the future, revision entries will be signed. At that
301
# point, it is probably best *not* to include the signature
302
# in the revision hash. Because that lets you re-sign
303
# the revision, (add signatures/remove signatures) and still
304
# have all hash pointers stay consistent.
305
# But for now, just hash the contents.
306
return bzrlib.osutils.sha_file(self.get_revision_xml_file(revision_id))
308
290
@needs_write_lock
309
291
def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
310
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())
313
297
def fileid_involved_between_revs(self, from_revid, to_revid):
314
298
"""Find file_id(s) which are involved in the changes between revisions.
327
311
# won't be fixed, because AD never saw revision C
328
312
# to cause a conflict which would force a reweave.
329
313
w = self.get_inventory_weave()
330
from_set = set(w.inclusions([w.lookup(from_revid)]))
331
to_set = set(w.inclusions([w.lookup(to_revid)]))
332
included = to_set.difference(from_set)
333
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)
334
317
return self._fileid_involved_by_set(changed)
336
319
def fileid_involved(self, last_revid=None):
379
361
w = self.get_inventory_weave()
381
for line in w._weave:
383
# it is ugly, but it is due to the weave structure
384
if not isinstance(line, basestring): continue
364
for lineno, insert, deletes, line in w.walk(changes):
386
365
start = line.find('file_id="')+9
387
366
if start < 9: continue
388
367
end = line.find('"', start)
537
516
if not self.has_revision(revision_id):
538
517
raise errors.NoSuchRevision(self, revision_id)
539
518
w = self.get_inventory_weave()
540
return [None] + map(w.idx_to_name,
541
w.inclusions([w.lookup(revision_id)]))
519
return [None] + w.get_ancestry(revision_id)
544
522
def print_file(self, file, revision_id):
608
586
plaintext = Testament.from_revision(self, revision_id).as_short_text()
609
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())
612
602
class AllInOneRepository(Repository):
613
603
"""Legacy support - the repository behaviour for all-in-one branches."""
615
def __init__(self, _format, a_bzrdir, revision_store):
605
def __init__(self, _format, a_bzrdir, _revision_store, control_store, text_store):
616
606
# we reuse one control files instance.
617
607
dir_mode = a_bzrdir._control_files._dir_mode
618
608
file_mode = a_bzrdir._control_files._file_mode
650
640
# not broken out yet because the controlweaves|inventory_store
651
641
# and text_store | weave_store bits are still different.
652
642
if isinstance(_format, RepositoryFormat4):
643
# cannot remove these - there is still no consistent api
644
# which allows access to this old info.
653
645
self.inventory_store = get_store('inventory-store')
654
self.text_store = get_store('text-store')
655
elif isinstance(_format, RepositoryFormat5):
656
self.control_weaves = get_weave('')
657
self.weave_store = get_weave('weaves')
658
elif isinstance(_format, RepositoryFormat6):
659
self.control_weaves = get_weave('')
660
self.weave_store = get_weave('weaves', prefixed=True)
662
raise errors.BzrError('unreachable code: unexpected repository'
664
revision_store.register_suffix('sig')
665
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)
668
650
class MetaDirRepository(Repository):
669
651
"""Repositories in the new meta-dir layout."""
671
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):
672
654
super(MetaDirRepository, self).__init__(_format,
677
661
dir_mode = self.control_files._dir_mode
678
662
file_mode = self.control_files._file_mode
691
675
ws.enable_cache = True
694
if isinstance(self._format, RepositoryFormat7):
695
self.control_weaves = get_weave('')
696
self.weave_store = get_weave('weaves', prefixed=True)
697
elif isinstance(self._format, RepositoryFormatKnit1):
698
self.control_weaves = get_weave('')
699
self.weave_store = get_weave('knits', prefixed=True)
701
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())
705
688
class RepositoryFormat(object):
761
748
"""Return the revision store object for this a_bzrdir."""
762
749
raise NotImplementedError(self._get_revision_store)
764
def _get_rev_store(self,
751
def _get_text_rev_store(self,
770
758
"""Common logic for getting a revision store for a repository.
772
see self._get_revision_store for the method to
760
see self._get_revision_store for the subclass-overridable method to
773
761
get the store for a repository.
776
name = safe_unicode(name)
779
dir_mode = control_files._dir_mode
780
file_mode = control_files._file_mode
781
revision_store =TextStore(transport.clone(name),
783
compressed=compressed,
786
revision_store.register_suffix('sig')
787
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)
789
788
def initialize(self, a_bzrdir, shared=False):
790
789
"""Initialize a repository of this format in a_bzrdir.
870
869
control_files.unlock()
871
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)
873
883
def open(self, a_bzrdir, _found=False):
874
884
"""See RepositoryFormat.open()."""
879
889
repo_transport = a_bzrdir.get_repository_transport(None)
880
890
control_files = a_bzrdir._control_files
881
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)
882
894
return AllInOneRepository(_format=self,
883
895
a_bzrdir=a_bzrdir,
884
revision_store=revision_store)
896
_revision_store=_revision_store,
897
control_store=control_store,
898
text_store=text_store)
887
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.
916
937
def _get_revision_store(self, repo_transport, control_files):
917
938
"""See RepositoryFormat._get_revision_store()."""
918
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()."""
923
949
class RepositoryFormat5(PreSplitOutRepositoryFormat):
936
962
def _get_revision_store(self, repo_transport, control_files):
937
963
"""See RepositoryFormat._get_revision_store()."""
938
964
"""Return the revision store object for this a_bzrdir."""
939
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)
945
975
class RepositoryFormat6(PreSplitOutRepositoryFormat):
958
988
def _get_revision_store(self, repo_transport, control_files):
959
989
"""See RepositoryFormat._get_revision_store()."""
960
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)
967
1001
class MetaDirRepositoryFormat(RepositoryFormat):
980
1014
control_files.create_lock()
981
1015
return control_files
983
def _get_revision_store(self, repo_transport, control_files):
984
"""See RepositoryFormat._get_revision_store()."""
985
return self._get_rev_store(repo_transport,
992
def open(self, a_bzrdir, _found=False, _override_transport=None):
993
"""See RepositoryFormat.open().
995
:param _override_transport: INTERNAL USE ONLY. Allows opening the
996
repository at a slightly different url
997
than normal. I.e. during 'upgrade'.
1000
format = RepositoryFormat.find_format(a_bzrdir)
1001
assert format.__class__ == self.__class__
1002
if _override_transport is not None:
1003
repo_transport = _override_transport
1005
repo_transport = a_bzrdir.get_repository_transport(None)
1006
control_files = LockableFiles(repo_transport, 'lock', LockDir)
1007
revision_store = self._get_revision_store(repo_transport, control_files)
1008
return MetaDirRepository(_format=self,
1010
control_files=control_files,
1011
revision_store=revision_store)
1013
1017
def _upload_blank_content(self, a_bzrdir, dirs, files, utf8_files, shared):
1014
1018
"""Upload the initial blank content."""
1015
1019
control_files = self._create_control_files(a_bzrdir)
1039
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('',
1042
1053
def get_format_string(self):
1043
1054
"""See RepositoryFormat.get_format_string()."""
1044
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',
1046
1072
def initialize(self, a_bzrdir, shared=False):
1047
1073
"""Create a weave repository.
1066
1092
self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1067
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)
1070
1121
class RepositoryFormatKnit1(MetaDirRepositoryFormat):
1071
1122
"""Bzr repository knit format 1.
1081
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)
1084
1143
def get_format_string(self):
1085
1144
"""See RepositoryFormat.get_format_string()."""
1086
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)
1088
1165
def initialize(self, a_bzrdir, shared=False):
1089
1166
"""Create a knit format 1 repository.
1102
1179
empty_weave = sio.getvalue()
1104
1181
mutter('creating repository in %s.', a_bzrdir.transport.base)
1105
dirs = ['revision-store', 'knits']
1106
files = [('inventory.weave', StringIO(empty_weave)),
1182
dirs = ['revision-store', 'knits', 'control']
1183
files = [('control/inventory.weave', StringIO(empty_weave)),
1108
1185
utf8_files = [('format', self.get_format_string())]
1110
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)
1111
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)
1114
1225
# formats which have no format string are not discoverable
1115
1226
# and not independently creatable, so are not registered.
1133
1244
operations with another repository - they will always forward to
1134
1245
InterRepository.get(other).method_name(parameters).
1136
# XXX: FIXME: FUTURE: robertc
1137
# testing of these probably requires a factory in optimiser type, and
1138
# then a test adapter to test each type thoroughly.
1141
1248
_optimisers = set()
1142
1249
"""The available optimised InterRepository types."""
1144
def __init__(self, source, target):
1145
"""Construct a default InterRepository instance. Please use 'get'.
1147
Only subclasses of InterRepository should call
1148
InterRepository.__init__ - clients should call InterRepository.get
1149
instead which will create an optimised InterRepository if possible.
1151
self.source = source
1152
self.target = target
1154
1251
@needs_write_lock
1155
1252
def copy_content(self, revision_id=None, basis=None):
1156
1253
"""Make a complete copy of the content in self into destination.
1200
1297
Returns the copied revision count and the failed revisions in a tuple:
1201
1298
(copied, failures).
1203
from bzrlib.fetch import RepoFetcher
1300
from bzrlib.fetch import GenericRepoFetcher
1204
1301
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1205
1302
self.source, self.source._format, self.target, self.target._format)
1206
f = RepoFetcher(to_repository=self.target,
1207
from_repository=self.source,
1208
last_revision=revision_id,
1303
f = GenericRepoFetcher(to_repository=self.target,
1304
from_repository=self.source,
1305
last_revision=revision_id,
1210
1307
return f.count_copied, f.failed_revisions
1213
def get(klass, repository_source, repository_target):
1214
"""Retrieve a InterRepository worker object for these repositories.
1216
:param repository_source: the repository to be the 'source' member of
1217
the InterRepository instance.
1218
:param repository_target: the repository to be the 'target' member of
1219
the InterRepository instance.
1220
If an optimised InterRepository worker exists it will be used otherwise
1221
a default InterRepository instance will be created.
1223
for provider in klass._optimisers:
1224
if provider.is_compatible(repository_source, repository_target):
1225
return provider(repository_source, repository_target)
1226
return InterRepository(repository_source, repository_target)
1228
1309
def lock_read(self):
1229
1310
"""Take out a logical read lock.
1327
1398
if self.source.control_files._transport.listable():
1328
1399
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1330
copy_all(self.source.weave_store,
1331
self.target.weave_store, pb=pb)
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())
1332
1406
pb.update('copying inventory', 0, 1)
1333
1407
self.target.control_weaves.copy_multi(
1334
self.source.control_weaves, ['inventory'])
1335
copy_all(self.source.revision_store,
1336
self.target.revision_store, pb=pb)
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,
1342
1419
@needs_write_lock
1343
1420
def fetch(self, revision_id=None, pb=None):
1344
1421
"""See InterRepository.fetch()."""
1345
from bzrlib.fetch import RepoFetcher
1422
from bzrlib.fetch import GenericRepoFetcher
1346
1423
mutter("Using fetch logic to copy between %s(%s) and %s(%s)",
1347
1424
self.source, self.source._format, self.target, self.target._format)
1348
f = RepoFetcher(to_repository=self.target,
1349
from_repository=self.source,
1350
last_revision=revision_id,
1425
f = GenericRepoFetcher(to_repository=self.target,
1426
from_repository=self.source,
1427
last_revision=revision_id,
1352
1429
return f.count_copied, f.failed_revisions
1354
1431
@needs_read_lock
1392
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)
1395
1533
InterRepository.register_optimiser(InterWeaveRepo)
1534
InterRepository.register_optimiser(InterKnitRepo)
1398
1537
class RepositoryTestProviderAdapter(object):