31
31
from bzrlib.decorators import needs_read_lock, needs_write_lock
32
32
from bzrlib.errors import NoSuchRevision
33
33
from bzrlib.lockable_files import LockableFiles
34
from bzrlib.pack import ContainerReader
34
35
from bzrlib.revision import NULL_REVISION
35
36
from bzrlib.smart import client, vfs
36
37
from bzrlib.symbol_versioning import (
89
90
real_branch = self._real_bzrdir.create_branch()
90
91
return RemoteBranch(self, self.find_repository(), real_branch)
93
def destroy_branch(self):
94
"""See BzrDir.destroy_branch"""
96
self._real_bzrdir.destroy_branch()
92
98
def create_workingtree(self, revision_id=None):
93
99
raise errors.NotLocalUrl(self.transport.base)
254
260
self._leave_lock = False
256
262
self._reconcile_does_inventory_gc = True
263
self._reconcile_fixes_text_parents = True
264
self.base = self.bzrdir.transport.base
267
return "%s(%s)" % (self.__class__.__name__, self.base)
258
271
def abort_write_group(self):
259
272
"""Complete a write group on the decorated repository.
334
347
def get_graph(self, other_repository=None):
335
348
"""Return the graph for this repository format"""
336
350
return self._real_repository.get_graph(other_repository)
338
352
def gather_stats(self, revid=None, committers=None):
387
401
assert response[0] in ('yes', 'no'), 'unexpected response code %s' % (response,)
388
402
return response[0] == 'yes'
404
def is_write_locked(self):
405
return self._lock_mode == 'w'
390
407
def lock_read(self):
391
408
# wrong eventually - want a local lock cache context
392
409
if not self._lock_mode:
409
426
raise errors.LockContention('(remote lock)')
410
427
elif response[0] == 'UnlockableTransport':
411
428
raise errors.UnlockableTransport(self.bzrdir.root_transport)
429
elif response[0] == 'LockFailed':
430
raise errors.LockFailed(response[1], response[2])
413
432
raise errors.UnexpectedSmartServerResponse(response)
500
519
return self._real_repository.break_lock()
502
521
def _get_tarball(self, compression):
503
"""Return a TemporaryFile containing a repository tarball"""
522
"""Return a TemporaryFile containing a repository tarball.
524
Returns None if the server does not support sending tarballs.
505
527
path = self.bzrdir._path_for_remote_call(self._client)
506
528
response, protocol = self._client.call_expecting_body(
507
529
'Repository.tarball', path, compression)
508
assert response[0] in ('ok', 'failure'), \
509
'unexpected response code %s' % (response,)
510
530
if response[0] == 'ok':
511
531
# Extract the tarball and return it
512
532
t = tempfile.NamedTemporaryFile()
514
534
t.write(protocol.read_body_bytes())
518
raise errors.SmartServerError(error_code=response)
537
if (response == ('error', "Generic bzr smart protocol error: "
538
"bad request 'Repository.tarball'") or
539
response == ('error', "Generic bzr smart protocol error: "
540
"bad request u'Repository.tarball'")):
541
protocol.cancel_read_body()
543
raise errors.UnexpectedSmartServerResponse(response)
520
545
def sprout(self, to_bzrdir, revision_id=None):
521
546
# TODO: Option to control what format is created?
522
to_repo = to_bzrdir.create_repository()
523
self._copy_repository_tarball(to_repo, revision_id)
547
dest_repo = to_bzrdir.create_repository()
548
dest_repo.fetch(self, revision_id=revision_id)
526
551
### These methods are just thin shims to the VFS object for now.
588
613
def fetch(self, source, revision_id=None, pb=None):
614
if self.has_same_location(source):
615
# check that last_revision is in 'from' and then return a
617
if (revision_id is not None and
618
not _mod_revision.is_null(revision_id)):
619
self.get_revision(revision_id)
589
621
self._ensure_real()
590
622
return self._real_repository.fetch(
591
623
source, revision_id=revision_id, pb=pb)
613
645
self._ensure_real()
614
646
return self._real_repository.fileids_altered_by_revision_ids(revision_ids)
648
def get_versioned_file_checker(self, revisions, revision_versions_cache):
650
return self._real_repository.get_versioned_file_checker(
651
revisions, revision_versions_cache)
616
653
def iter_files_bytes(self, desired_files):
617
654
"""See Repository.iter_file_bytes.
668
705
return self._real_repository.get_revision_reconcile(revision_id)
671
def check(self, revision_ids):
708
def check(self, revision_ids=None):
672
709
self._ensure_real()
673
return self._real_repository.check(revision_ids)
710
return self._real_repository.check(revision_ids=revision_ids)
675
712
def copy_content_into(self, destination, revision_id=None):
676
713
self._ensure_real()
677
714
return self._real_repository.copy_content_into(
678
715
destination, revision_id=revision_id)
680
def _copy_repository_tarball(self, destination, revision_id=None):
717
def _copy_repository_tarball(self, to_bzrdir, revision_id=None):
681
718
# get a tarball of the remote repository, and copy from that into the
683
720
from bzrlib import osutils
687
724
# TODO: Maybe a progress bar while streaming the tarball?
688
725
note("Copying repository content as tarball...")
689
726
tar_file = self._get_tarball('bz2')
729
destination = to_bzrdir.create_repository()
691
731
tar = tarfile.open('repository', fileobj=tar_file,
750
788
self._ensure_real()
751
789
return self._real_repository.has_signature_for_revision_id(revision_id)
791
def get_data_stream(self, revision_ids):
792
path = self.bzrdir._path_for_remote_call(self._client)
793
response, protocol = self._client.call_expecting_body(
794
'Repository.stream_knit_data_for_revisions', path, *revision_ids)
795
if response == ('ok',):
796
return self._deserialise_stream(protocol)
797
elif (response == ('error', "Generic bzr smart protocol error: "
798
"bad request 'Repository.stream_knit_data_for_revisions'") or
799
response == ('error', "Generic bzr smart protocol error: "
800
"bad request u'Repository.stream_knit_data_for_revisions'")):
801
protocol.cancel_read_body()
803
return self._real_repository.get_data_stream(revision_ids)
805
raise errors.UnexpectedSmartServerResponse(response)
807
def _deserialise_stream(self, protocol):
808
buffer = StringIO(protocol.read_body_bytes())
809
reader = ContainerReader(buffer)
810
for record_names, read_bytes in reader.iter_records():
812
# These records should have only one name, and that name
813
# should be a one-element tuple.
814
[name_tuple] = record_names
816
raise errors.SmartProtocolError(
817
'Repository data stream had invalid record name %r'
819
yield name_tuple, read_bytes(None)
821
def insert_data_stream(self, stream):
823
self._real_repository.insert_data_stream(stream)
825
def item_keys_introduced_by(self, revision_ids, _files_pb=None):
827
return self._real_repository.item_keys_introduced_by(revision_ids,
830
def revision_graph_can_have_wrong_parents(self):
831
# The answer depends on the remote repo format.
833
return self._real_repository.revision_graph_can_have_wrong_parents()
835
def _find_inconsistent_revision_parents(self):
837
return self._real_repository._find_inconsistent_revision_parents()
839
def _check_for_inconsistent_revision_parents(self):
841
return self._real_repository._check_for_inconsistent_revision_parents()
754
844
class RemoteBranchLockableFiles(LockableFiles):
755
845
"""A 'LockableFiles' implementation that talks to a smart server.
935
1025
raise errors.UnlockableTransport(self.bzrdir.root_transport)
936
1026
elif response[0] == 'ReadOnlyError':
937
1027
raise errors.ReadOnlyError(self)
1028
elif response[0] == 'LockFailed':
1029
raise errors.LockFailed(response[1], response[2])
939
1031
raise errors.UnexpectedSmartServerResponse(response)