45
55
from bzrlib.store.text import TextStore
46
56
from bzrlib.trace import mutter
57
from bzrlib.tuned_gzip import GzipFile, bytes_to_gzip
58
from bzrlib.versionedfile import (
60
FulltextContentFactory,
49
65
class AllInOneRepository(Repository):
50
66
"""Legacy support - the repository behaviour for all-in-one branches."""
52
_serializer = xml5.serializer_v5
54
def __init__(self, _format, a_bzrdir, _revision_store, control_store, text_store):
69
def _serializer(self):
70
return xml5.serializer_v5
72
def _escape(self, file_or_path):
73
if not isinstance(file_or_path, basestring):
74
file_or_path = '/'.join(file_or_path)
75
if file_or_path == '':
77
return urlutils.escape(osutils.safe_unicode(file_or_path))
79
def __init__(self, _format, a_bzrdir):
55
80
# we reuse one control files instance.
56
dir_mode = a_bzrdir._control_files._dir_mode
57
file_mode = a_bzrdir._control_files._file_mode
81
dir_mode = a_bzrdir._get_dir_mode()
82
file_mode = a_bzrdir._get_file_mode()
59
84
def get_store(name, compressed=True, prefixed=False):
60
85
# FIXME: This approach of assuming stores are all entirely compressed
61
# or entirely uncompressed is tidy, but breaks upgrade from
62
# some existing branches where there's a mixture; we probably
86
# or entirely uncompressed is tidy, but breaks upgrade from
87
# some existing branches where there's a mixture; we probably
63
88
# still want the option to look for both.
64
relpath = a_bzrdir._control_files._escape(name)
65
store = TextStore(a_bzrdir._control_files._transport.clone(relpath),
89
relpath = self._escape(name)
90
store = TextStore(a_bzrdir.transport.clone(relpath),
66
91
prefixed=prefixed, compressed=compressed,
68
93
file_mode=file_mode)
71
96
# not broken out yet because the controlweaves|inventory_store
72
# and text_store | weave_store bits are still different.
97
# and texts bits are still different.
73
98
if isinstance(_format, RepositoryFormat4):
74
# cannot remove these - there is still no consistent api
99
# cannot remove these - there is still no consistent api
75
100
# which allows access to this old info.
76
101
self.inventory_store = get_store('inventory-store')
77
text_store = get_store('text-store')
78
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
79
if control_store is not None:
80
control_store.get_scope = self.get_transaction
81
text_store.get_scope = self.get_transaction
102
self._text_store = get_store('text-store')
103
super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files)
84
106
def _all_possible_ids(self):
85
107
"""Return all the possible revisions that we could find."""
86
108
if 'evil' in debug.debug_flags:
87
109
mutter_callsite(3, "_all_possible_ids scales with size of history.")
88
return self.get_inventory_weave().versions()
110
return [key[-1] for key in self.inventories.keys()]
91
113
def _all_revision_ids(self):
92
"""Returns a list of all the revision ids in the repository.
114
"""Returns a list of all the revision ids in the repository.
94
These are in as much topological order as the underlying store can
116
These are in as much topological order as the underlying store can
95
117
present: for weaves ghosts may lead to a lack of correctness until
96
118
the reweave updates the parents list.
98
if self._revision_store.text_store.listable():
99
return self._revision_store.all_revision_ids(self.get_transaction())
100
result = self._all_possible_ids()
101
# TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
102
# ids. (It should, since _revision_store's API should change to
103
# return utf8 revision_ids)
104
return self._eliminate_revisions_not_present(result)
106
def _check_revision_parents(self, revision, inventory):
107
"""Private to Repository and Fetch.
109
This checks the parentage of revision in an inventory weave for
110
consistency and is only applicable to inventory-weave-for-ancestry
111
using repository formats & fetchers.
113
weave_parents = inventory.get_parent_map(
114
[revision.revision_id])[revision.revision_id]
115
parent_map = inventory.get_parent_map(revision.parent_ids)
116
for parent_id in revision.parent_ids:
117
if parent_id in parent_map:
118
# this parent must not be a ghost.
119
if not parent_id in weave_parents:
121
raise errors.CorruptRepository(self)
120
return [key[-1] for key in self.revisions.keys()]
122
def _activate_new_inventory(self):
123
"""Put a replacement inventory.new into use as inventories."""
124
# Copy the content across
125
t = self.bzrdir._control_files._transport
126
t.copy('inventory.new.weave', 'inventory.weave')
127
# delete the temp inventory
128
t.delete('inventory.new.weave')
129
# Check we can parse the new weave properly as a sanity check
130
self.inventories.keys()
132
def _backup_inventory(self):
133
t = self.bzrdir._control_files._transport
134
t.copy('inventory.weave', 'inventory.backup.weave')
136
def _temp_inventories(self):
137
t = self.bzrdir._control_files._transport
138
return self._format._get_inventories(t, self, 'inventory.new')
123
140
def get_commit_builder(self, branch, parents, config, timestamp=None,
124
141
timezone=None, committer=None, revprops=None,
125
142
revision_id=None):
126
143
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
127
result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
144
result = CommitBuilder(self, parents, config, timestamp, timezone,
128
145
committer, revprops, revision_id)
129
146
self.start_write_group()
133
150
def get_revisions(self, revision_ids):
134
151
revs = self._get_revisions(revision_ids)
135
# weave corruption can lead to absent revision markers that should be
137
# the following test is reasonably cheap (it needs a single weave read)
138
# and the weave is cached in read transactions. In write transactions
139
# it is not cached but typically we only read a small number of
140
# revisions. For knits when they are introduced we will probably want
141
# to ensure that caching write transactions are in use.
142
inv = self.get_inventory_weave()
144
self._check_revision_parents(rev, inv)
147
def has_revisions(self, revision_ids):
148
"""See Repository.has_revisions()."""
150
transaction = self.get_transaction()
151
for revision_id in revision_ids:
152
if self._revision_store.has_revision_id(revision_id, transaction):
153
result.add(revision_id)
154
def _inventory_add_lines(self, revision_id, parents, lines,
156
"""Store lines in inv_vf and return the sha1 of the inventory."""
157
present_parents = self.get_graph().get_parent_map(parents)
159
for parent in parents:
160
if parent in present_parents:
161
final_parents.append((parent,))
162
return self.inventories.add_lines((revision_id,), final_parents, lines,
163
check_content=check_content)[0]
157
165
def is_shared(self):
158
166
"""AllInOne repositories cannot be shared."""
183
191
class WeaveMetaDirRepository(MetaDirVersionedFileRepository):
184
192
"""A subclass of MetaDirRepository to set weave specific policy."""
186
_serializer = xml5.serializer_v5
194
def __init__(self, _format, a_bzrdir, control_files):
195
super(WeaveMetaDirRepository, self).__init__(_format, a_bzrdir, control_files)
196
self._serializer = _format._serializer
189
199
def _all_possible_ids(self):
190
200
"""Return all the possible revisions that we could find."""
191
201
if 'evil' in debug.debug_flags:
192
202
mutter_callsite(3, "_all_possible_ids scales with size of history.")
193
return self.get_inventory_weave().versions()
203
return [key[-1] for key in self.inventories.keys()]
196
206
def _all_revision_ids(self):
197
"""Returns a list of all the revision ids in the repository.
207
"""Returns a list of all the revision ids in the repository.
199
These are in as much topological order as the underlying store can
209
These are in as much topological order as the underlying store can
200
210
present: for weaves ghosts may lead to a lack of correctness until
201
211
the reweave updates the parents list.
203
if self._revision_store.text_store.listable():
204
return self._revision_store.all_revision_ids(self.get_transaction())
205
result = self._all_possible_ids()
206
# TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
207
# ids. (It should, since _revision_store's API should change to
208
# return utf8 revision_ids)
209
return self._eliminate_revisions_not_present(result)
211
def _check_revision_parents(self, revision, inventory):
212
"""Private to Repository and Fetch.
214
This checks the parentage of revision in an inventory weave for
215
consistency and is only applicable to inventory-weave-for-ancestry
216
using repository formats & fetchers.
218
weave_parents = inventory.get_parent_map(
219
[revision.revision_id])[revision.revision_id]
220
parent_map = inventory.get_parent_map(revision.parent_ids)
221
for parent_id in revision.parent_ids:
222
if parent_id in parent_map:
223
# this parent must not be a ghost.
224
if not parent_id in weave_parents:
226
raise errors.CorruptRepository(self)
213
return [key[-1] for key in self.revisions.keys()]
215
def _activate_new_inventory(self):
216
"""Put a replacement inventory.new into use as inventories."""
217
# Copy the content across
219
t.copy('inventory.new.weave', 'inventory.weave')
220
# delete the temp inventory
221
t.delete('inventory.new.weave')
222
# Check we can parse the new weave properly as a sanity check
223
self.inventories.keys()
225
def _backup_inventory(self):
227
t.copy('inventory.weave', 'inventory.backup.weave')
229
def _temp_inventories(self):
231
return self._format._get_inventories(t, self, 'inventory.new')
228
233
def get_commit_builder(self, branch, parents, config, timestamp=None,
229
234
timezone=None, committer=None, revprops=None,
230
235
revision_id=None):
231
236
self._check_ascii_revisionid(revision_id, self.get_commit_builder)
232
result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
237
result = CommitBuilder(self, parents, config, timestamp, timezone,
233
238
committer, revprops, revision_id)
234
239
self.start_write_group()
238
243
def get_revision(self, revision_id):
239
244
"""Return the Revision object for a named revision"""
240
# TODO: jam 20070210 get_revision_reconcile should do this for us
241
245
r = self.get_revision_reconcile(revision_id)
242
# weave corruption can lead to absent revision markers that should be
244
# the following test is reasonably cheap (it needs a single weave read)
245
# and the weave is cached in read transactions. In write transactions
246
# it is not cached but typically we only read a small number of
247
# revisions. For knits when they are introduced we will probably want
248
# to ensure that caching write transactions are in use.
249
inv = self.get_inventory_weave()
250
self._check_revision_parents(r, inv)
253
def has_revisions(self, revision_ids):
254
"""See Repository.has_revisions()."""
256
transaction = self.get_transaction()
257
for revision_id in revision_ids:
258
if self._revision_store.has_revision_id(revision_id, transaction):
259
result.add(revision_id)
248
def _inventory_add_lines(self, revision_id, parents, lines,
250
"""Store lines in inv_vf and return the sha1 of the inventory."""
251
present_parents = self.get_graph().get_parent_map(parents)
253
for parent in parents:
254
if parent in present_parents:
255
final_parents.append((parent,))
256
return self.inventories.add_lines((revision_id,), final_parents, lines,
257
check_content=check_content)[0]
262
259
def revision_graph_can_have_wrong_parents(self):
263
# XXX: This is an old format that we don't support full checking on, so
264
# just claim that checking for this inconsistency is not required.
281
280
if not _internal:
282
281
# always initialized when the bzrdir is.
283
282
return self.open(a_bzrdir, _found=True)
285
284
# Create an empty weave
287
286
weavefile.write_weave_v5(weave.Weave(), sio)
288
287
empty_weave = sio.getvalue()
290
289
mutter('creating repository in %s.', a_bzrdir.transport.base)
291
dirs = ['revision-store', 'weaves']
292
files = [('inventory.weave', StringIO(empty_weave)),
295
291
# FIXME: RBC 20060125 don't peek under the covers
296
292
# NB: no need to escape relative paths that are url safe.
297
293
control_files = lockable_files.LockableFiles(a_bzrdir.transport,
298
'branch-lock', lockable_files.TransportLock)
294
'branch-lock', lockable_files.TransportLock)
299
295
control_files.create_lock()
300
296
control_files.lock_write()
301
control_files._transport.mkdir_multi(dirs,
302
mode=control_files._dir_mode)
297
transport = a_bzrdir.transport
304
for file, content in files:
305
control_files.put(file, content)
299
transport.mkdir_multi(['revision-store', 'weaves'],
300
mode=a_bzrdir._get_dir_mode())
301
transport.put_bytes_non_atomic('inventory.weave', empty_weave,
302
mode=a_bzrdir._get_file_mode())
307
304
control_files.unlock()
308
305
return self.open(a_bzrdir, _found=True)
310
def _get_control_store(self, repo_transport, control_files):
311
"""Return the control store for this repository."""
312
return self._get_versioned_file_store('',
317
def _get_text_store(self, transport, control_files):
318
"""Get a store for file texts for this format."""
319
raise NotImplementedError(self._get_text_store)
321
307
def open(self, a_bzrdir, _found=False):
322
308
"""See RepositoryFormat.open()."""
368
347
"""Format 4 is not supported.
370
349
It is not supported because the model changed from 4 to 5 and the
371
conversion logic is expensive - so doing it on the fly was not
350
conversion logic is expensive - so doing it on the fly was not
376
def _get_control_store(self, repo_transport, control_files):
377
"""Format 4 repositories have no formal control store at this point.
379
This will cause any control-file-needing apis to fail - this is desired.
355
def _get_inventories(self, repo_transport, repo, name='inventory'):
356
# No inventories store written so far.
383
def _get_revision_store(self, repo_transport, control_files):
384
"""See RepositoryFormat._get_revision_store()."""
359
def _get_revisions(self, repo_transport, repo):
385
360
from bzrlib.xml4 import serializer_v4
386
return self._get_text_rev_store(repo_transport,
389
serializer=serializer_v4)
391
def _get_text_store(self, transport, control_files):
392
"""See RepositoryFormat._get_text_store()."""
361
return RevisionTextStore(repo_transport.clone('revision-store'),
362
serializer_v4, True, versionedfile.PrefixMapper(),
363
repo.is_locked, repo.is_write_locked)
365
def _get_signatures(self, repo_transport, repo):
366
return SignatureTextStore(repo_transport.clone('revision-store'),
367
False, versionedfile.PrefixMapper(),
368
repo.is_locked, repo.is_write_locked)
370
def _get_texts(self, repo_transport, repo):
395
374
class RepositoryFormat5(PreSplitOutRepositoryFormat):
404
383
_versionedfile_class = weave.WeaveFile
405
384
_matchingbzrdir = bzrdir.BzrDirFormat5()
408
super(RepositoryFormat5, self).__init__()
386
def _serializer(self):
387
return xml5.serializer_v5
410
389
def get_format_description(self):
411
390
"""See RepositoryFormat.get_format_description()."""
412
391
return "Weave repository format 5"
414
def _get_revision_store(self, repo_transport, control_files):
415
"""See RepositoryFormat._get_revision_store()."""
416
"""Return the revision store object for this a_bzrdir."""
417
return self._get_text_rev_store(repo_transport,
422
def _get_text_store(self, transport, control_files):
423
"""See RepositoryFormat._get_text_store()."""
424
return self._get_versioned_file_store('weaves', transport, control_files, prefixed=False)
393
def network_name(self):
394
"""The network name for this format is the control dirs disk label."""
395
return self._matchingbzrdir.get_format_string()
397
def _get_inventories(self, repo_transport, repo, name='inventory'):
398
mapper = versionedfile.ConstantMapper(name)
399
return versionedfile.ThunkedVersionedFiles(repo_transport,
400
weave.WeaveFile, mapper, repo.is_locked)
402
def _get_revisions(self, repo_transport, repo):
403
return RevisionTextStore(repo_transport.clone('revision-store'),
404
xml5.serializer_v5, False, versionedfile.PrefixMapper(),
405
repo.is_locked, repo.is_write_locked)
407
def _get_signatures(self, repo_transport, repo):
408
return SignatureTextStore(repo_transport.clone('revision-store'),
409
False, versionedfile.PrefixMapper(),
410
repo.is_locked, repo.is_write_locked)
412
def _get_texts(self, repo_transport, repo):
413
mapper = versionedfile.PrefixMapper()
414
base_transport = repo_transport.clone('weaves')
415
return versionedfile.ThunkedVersionedFiles(base_transport,
416
weave.WeaveFile, mapper, repo.is_locked)
427
419
class RepositoryFormat6(PreSplitOutRepositoryFormat):
436
428
_versionedfile_class = weave.WeaveFile
437
429
_matchingbzrdir = bzrdir.BzrDirFormat6()
440
super(RepositoryFormat6, self).__init__()
431
def _serializer(self):
432
return xml5.serializer_v5
442
434
def get_format_description(self):
443
435
"""See RepositoryFormat.get_format_description()."""
444
436
return "Weave repository format 6"
446
def _get_revision_store(self, repo_transport, control_files):
447
"""See RepositoryFormat._get_revision_store()."""
448
return self._get_text_rev_store(repo_transport,
454
def _get_text_store(self, transport, control_files):
455
"""See RepositoryFormat._get_text_store()."""
456
return self._get_versioned_file_store('weaves', transport, control_files)
438
def network_name(self):
439
"""The network name for this format is the control dirs disk label."""
440
return self._matchingbzrdir.get_format_string()
442
def _get_inventories(self, repo_transport, repo, name='inventory'):
443
mapper = versionedfile.ConstantMapper(name)
444
return versionedfile.ThunkedVersionedFiles(repo_transport,
445
weave.WeaveFile, mapper, repo.is_locked)
447
def _get_revisions(self, repo_transport, repo):
448
return RevisionTextStore(repo_transport.clone('revision-store'),
449
xml5.serializer_v5, False, versionedfile.HashPrefixMapper(),
450
repo.is_locked, repo.is_write_locked)
452
def _get_signatures(self, repo_transport, repo):
453
return SignatureTextStore(repo_transport.clone('revision-store'),
454
False, versionedfile.HashPrefixMapper(),
455
repo.is_locked, repo.is_write_locked)
457
def _get_texts(self, repo_transport, repo):
458
mapper = versionedfile.HashPrefixMapper()
459
base_transport = repo_transport.clone('weaves')
460
return versionedfile.ThunkedVersionedFiles(base_transport,
461
weave.WeaveFile, mapper, repo.is_locked)
458
464
class RepositoryFormat7(MetaDirRepositoryFormat):
459
465
"""Bzr repository 7.
485
492
"""See RepositoryFormat.get_format_description()."""
486
493
return "Weave repository format 7"
488
def check_conversion_target(self, target_format):
491
def _get_revision_store(self, repo_transport, control_files):
492
"""See RepositoryFormat._get_revision_store()."""
493
return self._get_text_rev_store(repo_transport,
500
def _get_text_store(self, transport, control_files):
501
"""See RepositoryFormat._get_text_store()."""
502
return self._get_versioned_file_store('weaves',
495
def _get_inventories(self, repo_transport, repo, name='inventory'):
496
mapper = versionedfile.ConstantMapper(name)
497
return versionedfile.ThunkedVersionedFiles(repo_transport,
498
weave.WeaveFile, mapper, repo.is_locked)
500
def _get_revisions(self, repo_transport, repo):
501
return RevisionTextStore(repo_transport.clone('revision-store'),
502
xml5.serializer_v5, True, versionedfile.HashPrefixMapper(),
503
repo.is_locked, repo.is_write_locked)
505
def _get_signatures(self, repo_transport, repo):
506
return SignatureTextStore(repo_transport.clone('revision-store'),
507
True, versionedfile.HashPrefixMapper(),
508
repo.is_locked, repo.is_write_locked)
510
def _get_texts(self, repo_transport, repo):
511
mapper = versionedfile.HashPrefixMapper()
512
base_transport = repo_transport.clone('weaves')
513
return versionedfile.ThunkedVersionedFiles(base_transport,
514
weave.WeaveFile, mapper, repo.is_locked)
506
516
def initialize(self, a_bzrdir, shared=False):
507
517
"""Create a weave repository.
538
548
repo_transport = a_bzrdir.get_repository_transport(None)
539
549
control_files = lockable_files.LockableFiles(repo_transport,
540
550
'lock', lockdir.LockDir)
541
text_store = self._get_text_store(repo_transport, control_files)
542
control_store = self._get_control_store(repo_transport, control_files)
543
_revision_store = self._get_revision_store(repo_transport, control_files)
544
return WeaveMetaDirRepository(_format=self,
546
control_files=control_files,
547
_revision_store=_revision_store,
548
control_store=control_store,
549
text_store=text_store)
552
class WeaveCommitBuilder(CommitBuilder):
553
"""A builder for weave based repos that don't support ghosts."""
555
def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
556
versionedfile = self.repository.weave_store.get_weave_or_empty(
557
file_id, self.repository.get_transaction())
558
result = versionedfile.add_lines(
559
self._new_revision_id, parents, new_lines,
560
nostore_sha=nostore_sha)[0:2]
551
result = WeaveMetaDirRepository(_format=self, a_bzrdir=a_bzrdir,
552
control_files=control_files)
553
result.revisions = self._get_revisions(repo_transport, result)
554
result.signatures = self._get_signatures(repo_transport, result)
555
result.inventories = self._get_inventories(repo_transport, result)
556
result.texts = self._get_texts(repo_transport, result)
557
result.chk_bytes = None
558
result._transport = repo_transport
562
class TextVersionedFiles(VersionedFiles):
563
"""Just-a-bunch-of-files based VersionedFile stores."""
565
def __init__(self, transport, compressed, mapper, is_locked, can_write):
566
self._compressed = compressed
567
self._transport = transport
568
self._mapper = mapper
573
self._is_locked = is_locked
574
self._can_write = can_write
576
def add_lines(self, key, parents, lines):
577
"""Add a revision to the store."""
578
if not self._is_locked():
579
raise errors.ObjectNotLocked(self)
580
if not self._can_write():
581
raise errors.ReadOnlyError(self)
583
raise ValueError('bad idea to put / in %r' % (key,))
584
text = ''.join(lines)
586
text = bytes_to_gzip(text)
587
path = self._map(key)
588
self._transport.put_bytes_non_atomic(path, text, create_parent_dir=True)
590
def insert_record_stream(self, stream):
592
for record in stream:
593
# Raise an error when a record is missing.
594
if record.storage_kind == 'absent':
595
raise errors.RevisionNotPresent([record.key[0]], self)
596
# adapt to non-tuple interface
597
if record.storage_kind == 'fulltext':
598
self.add_lines(record.key, None,
599
osutils.split_lines(record.get_bytes_as('fulltext')))
601
adapter_key = record.storage_kind, 'fulltext'
603
adapter = adapters[adapter_key]
605
adapter_factory = adapter_registry.get(adapter_key)
606
adapter = adapter_factory(self)
607
adapters[adapter_key] = adapter
608
lines = osutils.split_lines(adapter.get_bytes(
609
record, record.get_bytes_as(record.storage_kind)))
611
self.add_lines(record.key, None, lines)
612
except RevisionAlreadyPresent:
615
def _load_text(self, key):
616
if not self._is_locked():
617
raise errors.ObjectNotLocked(self)
618
path = self._map(key)
620
text = self._transport.get_bytes(path)
621
compressed = self._compressed
622
except errors.NoSuchFile:
624
# try without the .gz
627
text = self._transport.get_bytes(path)
629
except errors.NoSuchFile:
634
text = GzipFile(mode='rb', fileobj=StringIO(text)).read()
638
return self._mapper.map(key) + self._ext
641
class RevisionTextStore(TextVersionedFiles):
642
"""Legacy thunk for format 4 repositories."""
644
def __init__(self, transport, serializer, compressed, mapper, is_locked,
646
"""Create a RevisionTextStore at transport with serializer."""
647
TextVersionedFiles.__init__(self, transport, compressed, mapper,
648
is_locked, can_write)
649
self._serializer = serializer
651
def _load_text_parents(self, key):
652
text = self._load_text(key)
655
parents = self._serializer.read_revision_from_string(text).parent_ids
656
return text, tuple((parent,) for parent in parents)
658
def get_parent_map(self, keys):
661
parents = self._load_text_parents(key)[1]
664
result[key] = parents
667
def get_known_graph_ancestry(self, keys):
668
"""Get a KnownGraph instance with the ancestry of keys."""
670
parent_map = self.get_parent_map(keys)
671
kg = _mod_graph.KnownGraph(parent_map)
674
def get_record_stream(self, keys, sort_order, include_delta_closure):
676
text, parents = self._load_text_parents(key)
678
yield AbsentContentFactory(key)
680
yield FulltextContentFactory(key, parents, None, text)
683
if not self._is_locked():
684
raise errors.ObjectNotLocked(self)
686
for quoted_relpath in self._transport.iter_files_recursive():
687
relpath = urllib.unquote(quoted_relpath)
688
path, ext = os.path.splitext(relpath)
691
if not relpath.endswith('.sig'):
692
relpaths.add(relpath)
693
paths = list(relpaths)
694
return set([self._mapper.unmap(path) for path in paths])
697
class SignatureTextStore(TextVersionedFiles):
698
"""Legacy thunk for format 4-7 repositories."""
700
def __init__(self, transport, compressed, mapper, is_locked, can_write):
701
TextVersionedFiles.__init__(self, transport, compressed, mapper,
702
is_locked, can_write)
703
self._ext = '.sig' + self._ext
705
def get_parent_map(self, keys):
708
text = self._load_text(key)
714
def get_record_stream(self, keys, sort_order, include_delta_closure):
716
text = self._load_text(key)
718
yield AbsentContentFactory(key)
720
yield FulltextContentFactory(key, None, None, text)
723
if not self._is_locked():
724
raise errors.ObjectNotLocked(self)
726
for quoted_relpath in self._transport.iter_files_recursive():
727
relpath = urllib.unquote(quoted_relpath)
728
path, ext = os.path.splitext(relpath)
731
if not relpath.endswith('.sig'):
733
relpaths.add(relpath[:-4])
734
paths = list(relpaths)
735
return set([self._mapper.unmap(path) for path in paths])
564
737
_legacy_formats = [RepositoryFormat4(),
565
738
RepositoryFormat5(),