~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Aaron Bentley
  • Date: 2007-07-11 19:44:51 UTC
  • mto: This revision was merged to the branch mainline in revision 2606.
  • Revision ID: abentley@panoramicfeedback.com-20070711194451-3jqhye1nnd02a9uv
Restore original Branch.last_revision behavior, fix bits that care

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
    errors,
25
25
    lockdir,
26
26
    repository,
27
 
    revision,
28
27
)
29
 
from bzrlib.branch import BranchReferenceFormat
 
28
from bzrlib.branch import Branch, BranchReferenceFormat
30
29
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
31
30
from bzrlib.config import BranchConfig, TreeConfig
32
31
from bzrlib.decorators import needs_read_lock, needs_write_lock
33
32
from bzrlib.errors import NoSuchRevision
34
33
from bzrlib.lockable_files import LockableFiles
35
 
from bzrlib.pack import ContainerPushParser
 
34
from bzrlib.revision import NULL_REVISION
36
35
from bzrlib.smart import client, vfs
37
 
from bzrlib.symbol_versioning import (
38
 
    deprecated_method,
39
 
    zero_ninetyone,
40
 
    )
41
 
from bzrlib.revision import NULL_REVISION
42
36
from bzrlib.trace import note
43
37
 
44
38
# Note: RemoteBzrDirFormat is in bzrdir.py
58
52
        self._real_bzrdir = None
59
53
 
60
54
        if _client is None:
61
 
            self._shared_medium = transport.get_shared_medium()
62
 
            self._client = client._SmartClient(self._shared_medium)
 
55
            self._medium = transport.get_smart_client()
 
56
            self._client = client._SmartClient(self._medium)
63
57
        else:
64
58
            self._client = _client
65
 
            self._shared_medium = None
 
59
            self._medium = None
66
60
            return
67
61
 
68
62
        path = self._path_for_remote_call(self._client)
86
80
        self._real_bzrdir.create_repository(shared=shared)
87
81
        return self.open_repository()
88
82
 
89
 
    def destroy_repository(self):
90
 
        """See BzrDir.destroy_repository"""
91
 
        self._ensure_real()
92
 
        self._real_bzrdir.destroy_repository()
93
 
 
94
83
    def create_branch(self):
95
84
        self._ensure_real()
96
85
        real_branch = self._real_bzrdir.create_branch()
97
86
        return RemoteBranch(self, self.find_repository(), real_branch)
98
87
 
99
 
    def destroy_branch(self):
100
 
        """See BzrDir.destroy_branch"""
101
 
        self._ensure_real()
102
 
        self._real_bzrdir.destroy_branch()
103
 
 
104
 
    def create_workingtree(self, revision_id=None, from_branch=None):
 
88
    def create_workingtree(self, revision_id=None):
105
89
        raise errors.NotLocalUrl(self.transport.base)
106
90
 
107
91
    def find_branch_format(self):
198
182
    Instances of this repository are represented by RemoteRepository
199
183
    instances.
200
184
 
201
 
    The RemoteRepositoryFormat is parameterized during construction
 
185
    The RemoteRepositoryFormat is parameterised during construction
202
186
    to reflect the capabilities of the real, remote format. Specifically
203
187
    the attributes rich_root_data and supports_tree_reference are set
204
188
    on a per instance basis, and are not set (and should not be) at
256
240
            self._real_repository = None
257
241
        self.bzrdir = remote_bzrdir
258
242
        if _client is None:
259
 
            self._client = client._SmartClient(self.bzrdir._shared_medium)
 
243
            self._client = client._SmartClient(self.bzrdir._medium)
260
244
        else:
261
245
            self._client = _client
262
246
        self._format = format
264
248
        self._lock_token = None
265
249
        self._lock_count = 0
266
250
        self._leave_lock = False
267
 
        # For tests:
268
 
        # These depend on the actual remote format, so force them off for
269
 
        # maximum compatibility. XXX: In future these should depend on the
270
 
        # remote repository instance, but this is irrelevant until we perform
271
 
        # reconcile via an RPC call.
272
 
        self._reconcile_does_inventory_gc = False
273
 
        self._reconcile_fixes_text_parents = False
274
 
        self._reconcile_backsup_inventory = False
275
 
        self.base = self.bzrdir.transport.base
276
 
 
277
 
    def __str__(self):
278
 
        return "%s(%s)" % (self.__class__.__name__, self.base)
279
 
 
280
 
    __repr__ = __str__
281
 
 
282
 
    def abort_write_group(self):
283
 
        """Complete a write group on the decorated repository.
284
 
        
285
 
        Smart methods peform operations in a single step so this api
286
 
        is not really applicable except as a compatibility thunk
287
 
        for older plugins that don't use e.g. the CommitBuilder
288
 
        facility.
289
 
        """
290
 
        self._ensure_real()
291
 
        return self._real_repository.abort_write_group()
292
 
 
293
 
    def commit_write_group(self):
294
 
        """Complete a write group on the decorated repository.
295
 
        
296
 
        Smart methods peform operations in a single step so this api
297
 
        is not really applicable except as a compatibility thunk
298
 
        for older plugins that don't use e.g. the CommitBuilder
299
 
        facility.
300
 
        """
301
 
        self._ensure_real()
302
 
        return self._real_repository.commit_write_group()
303
251
 
304
252
    def _ensure_real(self):
305
253
        """Ensure that there is a _real_repository set.
311
259
            #self._real_repository = self.bzrdir._real_bzrdir.open_repository()
312
260
            self._set_real_repository(self.bzrdir._real_bzrdir.open_repository())
313
261
 
314
 
    def find_text_key_references(self):
315
 
        """Find the text key references within the repository.
316
 
 
317
 
        :return: a dictionary mapping (file_id, revision_id) tuples to altered file-ids to an iterable of
318
 
        revision_ids. Each altered file-ids has the exact revision_ids that
319
 
        altered it listed explicitly.
320
 
        :return: A dictionary mapping text keys ((fileid, revision_id) tuples)
321
 
            to whether they were referred to by the inventory of the
322
 
            revision_id that they contain. The inventory texts from all present
323
 
            revision ids are assessed to generate this report.
324
 
        """
325
 
        self._ensure_real()
326
 
        return self._real_repository.find_text_key_references()
327
 
 
328
 
    def _generate_text_key_index(self):
329
 
        """Generate a new text key index for the repository.
330
 
 
331
 
        This is an expensive function that will take considerable time to run.
332
 
 
333
 
        :return: A dict mapping (file_id, revision_id) tuples to a list of
334
 
            parents, also (file_id, revision_id) tuples.
335
 
        """
336
 
        self._ensure_real()
337
 
        return self._real_repository._generate_text_key_index()
338
 
 
339
262
    def get_revision_graph(self, revision_id=None):
340
263
        """See Repository.get_revision_graph()."""
341
264
        if revision_id is None:
342
265
            revision_id = ''
343
 
        elif revision.is_null(revision_id):
 
266
        elif revision_id == NULL_REVISION:
344
267
            return {}
345
268
 
346
269
        path = self.bzrdir._path_for_remote_call(self._client)
357
280
            lines = coded.split('\n')
358
281
            revision_graph = {}
359
282
            for line in lines:
360
 
                d = tuple(line.split())
 
283
                d = list(line.split())
361
284
                revision_graph[d[0]] = d[1:]
362
285
                
363
286
            return revision_graph
368
291
 
369
292
    def has_revision(self, revision_id):
370
293
        """See Repository.has_revision()."""
371
 
        if revision_id == NULL_REVISION:
 
294
        if revision_id is None:
372
295
            # The null revision is always present.
373
296
            return True
374
297
        path = self.bzrdir._path_for_remote_call(self._client)
376
299
        assert response[0] in ('yes', 'no'), 'unexpected response code %s' % (response,)
377
300
        return response[0] == 'yes'
378
301
 
379
 
    def has_revisions(self, revision_ids):
380
 
        """See Repository.has_revisions()."""
381
 
        result = set()
382
 
        for revision_id in revision_ids:
383
 
            if self.has_revision(revision_id):
384
 
                result.add(revision_id)
385
 
        return result
386
 
 
387
 
    def has_same_location(self, other):
388
 
        return (self.__class__ == other.__class__ and
389
 
                self.bzrdir.transport.base == other.bzrdir.transport.base)
390
 
        
391
302
    def get_graph(self, other_repository=None):
392
303
        """Return the graph for this repository format"""
393
 
        self._ensure_real()
394
304
        return self._real_repository.get_graph(other_repository)
395
305
 
396
306
    def gather_stats(self, revid=None, committers=None):
397
307
        """See Repository.gather_stats()."""
398
308
        path = self.bzrdir._path_for_remote_call(self._client)
399
 
        # revid can be None to indicate no revisions, not just NULL_REVISION
400
 
        if revid is None or revision.is_null(revid):
 
309
        if revid in (None, NULL_REVISION):
401
310
            fmt_revid = ''
402
311
        else:
403
312
            fmt_revid = revid
424
333
 
425
334
        return result
426
335
 
427
 
    def find_branches(self, using=False):
428
 
        """See Repository.find_branches()."""
429
 
        # should be an API call to the server.
430
 
        self._ensure_real()
431
 
        return self._real_repository.find_branches(using=using)
432
 
 
433
336
    def get_physical_lock_status(self):
434
337
        """See Repository.get_physical_lock_status()."""
435
 
        # should be an API call to the server.
436
 
        self._ensure_real()
437
 
        return self._real_repository.get_physical_lock_status()
438
 
 
439
 
    def is_in_write_group(self):
440
 
        """Return True if there is an open write group.
441
 
 
442
 
        write groups are only applicable locally for the smart server..
443
 
        """
444
 
        if self._real_repository:
445
 
            return self._real_repository.is_in_write_group()
446
 
 
447
 
    def is_locked(self):
448
 
        return self._lock_count >= 1
 
338
        return False
449
339
 
450
340
    def is_shared(self):
451
341
        """See Repository.is_shared()."""
454
344
        assert response[0] in ('yes', 'no'), 'unexpected response code %s' % (response,)
455
345
        return response[0] == 'yes'
456
346
 
457
 
    def is_write_locked(self):
458
 
        return self._lock_mode == 'w'
459
 
 
460
347
    def lock_read(self):
461
348
        # wrong eventually - want a local lock cache context
462
349
        if not self._lock_mode:
479
366
            raise errors.LockContention('(remote lock)')
480
367
        elif response[0] == 'UnlockableTransport':
481
368
            raise errors.UnlockableTransport(self.bzrdir.root_transport)
482
 
        elif response[0] == 'LockFailed':
483
 
            raise errors.LockFailed(response[1], response[2])
484
369
        else:
485
370
            raise errors.UnexpectedSmartServerResponse(response)
486
371
 
487
372
    def lock_write(self, token=None):
488
373
        if not self._lock_mode:
489
374
            self._lock_token = self._remote_lock_write(token)
490
 
            # if self._lock_token is None, then this is something like packs or
491
 
            # svn where we don't get to lock the repo, or a weave style repository
492
 
            # where we cannot lock it over the wire and attempts to do so will
493
 
            # fail.
 
375
            assert self._lock_token, 'Remote server did not return a token!'
494
376
            if self._real_repository is not None:
495
377
                self._real_repository.lock_write(token=self._lock_token)
496
378
            if token is not None:
503
385
            raise errors.ReadOnlyError(self)
504
386
        else:
505
387
            self._lock_count += 1
506
 
        return self._lock_token or None
 
388
        return self._lock_token
507
389
 
508
390
    def leave_lock_in_place(self):
509
 
        if not self._lock_token:
510
 
            raise NotImplementedError(self.leave_lock_in_place)
511
391
        self._leave_lock = True
512
392
 
513
393
    def dont_leave_lock_in_place(self):
514
 
        if not self._lock_token:
515
 
            raise NotImplementedError(self.dont_leave_lock_in_place)
516
394
        self._leave_lock = False
517
395
 
518
396
    def _set_real_repository(self, repository):
530
408
        elif self._lock_mode == 'r':
531
409
            self._real_repository.lock_read()
532
410
 
533
 
    def start_write_group(self):
534
 
        """Start a write group on the decorated repository.
535
 
        
536
 
        Smart methods peform operations in a single step so this api
537
 
        is not really applicable except as a compatibility thunk
538
 
        for older plugins that don't use e.g. the CommitBuilder
539
 
        facility.
540
 
        """
541
 
        self._ensure_real()
542
 
        return self._real_repository.start_write_group()
543
 
 
544
411
    def _unlock(self, token):
545
412
        path = self.bzrdir._path_for_remote_call(self._client)
546
 
        if not token:
547
 
            # with no token the remote repository is not persistently locked.
548
 
            return
549
413
        response = self._client.call('Repository.unlock', path, token)
550
414
        if response == ('ok',):
551
415
            return
556
420
 
557
421
    def unlock(self):
558
422
        self._lock_count -= 1
559
 
        if self._lock_count > 0:
560
 
            return
561
 
        old_mode = self._lock_mode
562
 
        self._lock_mode = None
563
 
        try:
564
 
            # The real repository is responsible at present for raising an
565
 
            # exception if it's in an unfinished write group.  However, it
566
 
            # normally will *not* actually remove the lock from disk - that's
567
 
            # done by the server on receiving the Repository.unlock call.
568
 
            # This is just to let the _real_repository stay up to date.
 
423
        if not self._lock_count:
 
424
            mode = self._lock_mode
 
425
            self._lock_mode = None
569
426
            if self._real_repository is not None:
570
427
                self._real_repository.unlock()
571
 
        finally:
572
 
            # The rpc-level lock should be released even if there was a
573
 
            # problem releasing the vfs-based lock.
574
 
            if old_mode == 'w':
 
428
            if mode != 'w':
575
429
                # Only write-locked repositories need to make a remote method
576
430
                # call to perfom the unlock.
577
 
                old_token = self._lock_token
578
 
                self._lock_token = None
579
 
                if not self._leave_lock:
580
 
                    self._unlock(old_token)
 
431
                return
 
432
            assert self._lock_token, 'Locked, but no token!'
 
433
            token = self._lock_token
 
434
            self._lock_token = None
 
435
            if not self._leave_lock:
 
436
                self._unlock(token)
581
437
 
582
438
    def break_lock(self):
583
439
        # should hand off to the network
585
441
        return self._real_repository.break_lock()
586
442
 
587
443
    def _get_tarball(self, compression):
588
 
        """Return a TemporaryFile containing a repository tarball.
589
 
        
590
 
        Returns None if the server does not support sending tarballs.
591
 
        """
 
444
        """Return a TemporaryFile containing a repository tarball"""
592
445
        import tempfile
593
446
        path = self.bzrdir._path_for_remote_call(self._client)
594
447
        response, protocol = self._client.call_expecting_body(
595
448
            'Repository.tarball', path, compression)
 
449
        assert response[0] in ('ok', 'failure'), \
 
450
            'unexpected response code %s' % (response,)
596
451
        if response[0] == 'ok':
597
452
            # Extract the tarball and return it
598
453
            t = tempfile.NamedTemporaryFile()
600
455
            t.write(protocol.read_body_bytes())
601
456
            t.seek(0)
602
457
            return t
603
 
        if (response == ('error', "Generic bzr smart protocol error: "
604
 
                "bad request 'Repository.tarball'") or
605
 
              response == ('error', "Generic bzr smart protocol error: "
606
 
                "bad request u'Repository.tarball'")):
607
 
            protocol.cancel_read_body()
608
 
            return None
609
 
        raise errors.UnexpectedSmartServerResponse(response)
 
458
        else:
 
459
            raise errors.SmartServerError(error_code=response)
610
460
 
611
461
    def sprout(self, to_bzrdir, revision_id=None):
612
462
        # TODO: Option to control what format is created?
613
 
        self._ensure_real()
614
 
        dest_repo = self._real_repository._format.initialize(to_bzrdir,
615
 
                                                             shared=False)
616
 
        dest_repo.fetch(self, revision_id=revision_id)
617
 
        return dest_repo
 
463
        to_repo = to_bzrdir.create_repository()
 
464
        self._copy_repository_tarball(to_repo, revision_id)
 
465
        return to_repo
618
466
 
619
467
    ### These methods are just thin shims to the VFS object for now.
620
468
 
622
470
        self._ensure_real()
623
471
        return self._real_repository.revision_tree(revision_id)
624
472
 
625
 
    def get_serializer_format(self):
626
 
        self._ensure_real()
627
 
        return self._real_repository.get_serializer_format()
628
 
 
629
473
    def get_commit_builder(self, branch, parents, config, timestamp=None,
630
474
                           timezone=None, committer=None, revprops=None,
631
475
                           revision_id=None):
635
479
        builder = self._real_repository.get_commit_builder(branch, parents,
636
480
                config, timestamp=timestamp, timezone=timezone,
637
481
                committer=committer, revprops=revprops, revision_id=revision_id)
 
482
        # Make the builder use this RemoteRepository rather than the real one.
 
483
        builder.repository = self
638
484
        return builder
639
485
 
640
486
    @needs_write_lock
653
499
        self._ensure_real()
654
500
        return self._real_repository.get_inventory(revision_id)
655
501
 
656
 
    def iter_inventories(self, revision_ids):
657
 
        self._ensure_real()
658
 
        return self._real_repository.iter_inventories(revision_ids)
659
 
 
660
502
    @needs_read_lock
661
503
    def get_revision(self, revision_id):
662
504
        self._ensure_real()
681
523
        return False
682
524
 
683
525
    def fetch(self, source, revision_id=None, pb=None):
684
 
        if self.has_same_location(source):
685
 
            # check that last_revision is in 'from' and then return a
686
 
            # no-operation.
687
 
            if (revision_id is not None and
688
 
                not revision.is_null(revision_id)):
689
 
                self.get_revision(revision_id)
690
 
            return 0, []
691
526
        self._ensure_real()
692
527
        return self._real_repository.fetch(
693
528
            source, revision_id=revision_id, pb=pb)
694
529
 
695
 
    def create_bundle(self, target, base, fileobj, format=None):
696
 
        self._ensure_real()
697
 
        self._real_repository.create_bundle(target, base, fileobj, format)
698
 
 
699
530
    @property
700
531
    def control_weaves(self):
701
532
        self._ensure_real()
715
546
        self._ensure_real()
716
547
        return self._real_repository.fileids_altered_by_revision_ids(revision_ids)
717
548
 
718
 
    def _get_versioned_file_checker(self, revisions, revision_versions_cache):
719
 
        self._ensure_real()
720
 
        return self._real_repository._get_versioned_file_checker(
721
 
            revisions, revision_versions_cache)
722
 
        
723
 
    def iter_files_bytes(self, desired_files):
724
 
        """See Repository.iter_file_bytes.
725
 
        """
726
 
        self._ensure_real()
727
 
        return self._real_repository.iter_files_bytes(desired_files)
728
 
 
729
549
    @needs_read_lock
730
550
    def get_signature_text(self, revision_id):
731
551
        self._ensure_real()
775
595
        return self._real_repository.get_revision_reconcile(revision_id)
776
596
 
777
597
    @needs_read_lock
778
 
    def check(self, revision_ids=None):
 
598
    def check(self, revision_ids):
779
599
        self._ensure_real()
780
 
        return self._real_repository.check(revision_ids=revision_ids)
 
600
        return self._real_repository.check(revision_ids)
781
601
 
782
602
    def copy_content_into(self, destination, revision_id=None):
783
603
        self._ensure_real()
784
604
        return self._real_repository.copy_content_into(
785
605
            destination, revision_id=revision_id)
786
606
 
787
 
    def _copy_repository_tarball(self, to_bzrdir, revision_id=None):
 
607
    def _copy_repository_tarball(self, destination, revision_id=None):
788
608
        # get a tarball of the remote repository, and copy from that into the
789
609
        # destination
790
610
        from bzrlib import osutils
791
611
        import tarfile
792
612
        import tempfile
 
613
        from StringIO import StringIO
793
614
        # TODO: Maybe a progress bar while streaming the tarball?
794
615
        note("Copying repository content as tarball...")
795
616
        tar_file = self._get_tarball('bz2')
796
 
        if tar_file is None:
797
 
            return None
798
 
        destination = to_bzrdir.create_repository()
799
617
        try:
800
618
            tar = tarfile.open('repository', fileobj=tar_file,
801
619
                mode='r|bz2')
809
627
                osutils.rmtree(tmpdir)
810
628
        finally:
811
629
            tar_file.close()
812
 
        return destination
 
630
        # TODO: if the server doesn't support this operation, maybe do it the
 
631
        # slow way using the _real_repository?
 
632
        #
813
633
        # TODO: Suggestion from john: using external tar is much faster than
814
634
        # python's tarfile library, but it may not work on windows.
815
635
 
816
 
    @needs_write_lock
817
 
    def pack(self):
818
 
        """Compress the data within the repository.
819
 
 
820
 
        This is not currently implemented within the smart server.
821
 
        """
822
 
        self._ensure_real()
823
 
        return self._real_repository.pack()
824
 
 
825
636
    def set_make_working_trees(self, new_value):
826
637
        raise NotImplementedError(self.set_make_working_trees)
827
638
 
853
664
        return self._real_repository.store_revision_signature(
854
665
            gpg_strategy, plaintext, revision_id)
855
666
 
856
 
    def add_signature_text(self, revision_id, signature):
857
 
        self._ensure_real()
858
 
        return self._real_repository.add_signature_text(revision_id, signature)
859
 
 
860
667
    def has_signature_for_revision_id(self, revision_id):
861
668
        self._ensure_real()
862
669
        return self._real_repository.has_signature_for_revision_id(revision_id)
863
670
 
864
 
    def get_data_stream(self, revision_ids):
865
 
        REQUEST_NAME = 'Repository.stream_revisions_chunked'
866
 
        path = self.bzrdir._path_for_remote_call(self._client)
867
 
        response, protocol = self._client.call_expecting_body(
868
 
            REQUEST_NAME, path, *revision_ids)
869
 
 
870
 
        if response == ('ok',):
871
 
            return self._deserialise_stream(protocol)
872
 
        elif (response == ('error', "Generic bzr smart protocol error: "
873
 
                "bad request '%s'" % REQUEST_NAME) or
874
 
              response == ('error', "Generic bzr smart protocol error: "
875
 
                "bad request u'%s'" % REQUEST_NAME)):
876
 
            protocol.cancel_read_body()
877
 
            self._ensure_real()
878
 
            return self._real_repository.get_data_stream(revision_ids)
879
 
        else:
880
 
            raise errors.UnexpectedSmartServerResponse(response)
881
 
 
882
 
    def _deserialise_stream(self, protocol):
883
 
        stream = protocol.read_streamed_body()
884
 
        container_parser = ContainerPushParser()
885
 
        for bytes in stream:
886
 
            container_parser.accept_bytes(bytes)
887
 
            records = container_parser.read_pending_records()
888
 
            for record_names, record_bytes in records:
889
 
                if len(record_names) != 1:
890
 
                    # These records should have only one name, and that name
891
 
                    # should be a one-element tuple.
892
 
                    raise errors.SmartProtocolError(
893
 
                        'Repository data stream had invalid record name %r'
894
 
                        % (record_names,))
895
 
                name_tuple = record_names[0]
896
 
                yield name_tuple, record_bytes
897
 
 
898
 
    def insert_data_stream(self, stream):
899
 
        self._ensure_real()
900
 
        self._real_repository.insert_data_stream(stream)
901
 
 
902
 
    def item_keys_introduced_by(self, revision_ids, _files_pb=None):
903
 
        self._ensure_real()
904
 
        return self._real_repository.item_keys_introduced_by(revision_ids,
905
 
            _files_pb=_files_pb)
906
 
 
907
 
    def revision_graph_can_have_wrong_parents(self):
908
 
        # The answer depends on the remote repo format.
909
 
        self._ensure_real()
910
 
        return self._real_repository.revision_graph_can_have_wrong_parents()
911
 
 
912
 
    def _find_inconsistent_revision_parents(self):
913
 
        self._ensure_real()
914
 
        return self._real_repository._find_inconsistent_revision_parents()
915
 
 
916
 
    def _check_for_inconsistent_revision_parents(self):
917
 
        self._ensure_real()
918
 
        return self._real_repository._check_for_inconsistent_revision_parents()
919
 
 
920
 
    def _make_parents_provider(self):
921
 
        self._ensure_real()
922
 
        return self._real_repository._make_parents_provider()
923
 
 
924
671
 
925
672
class RemoteBranchLockableFiles(LockableFiles):
926
673
    """A 'LockableFiles' implementation that talks to a smart server.
980
727
        assert isinstance(a_bzrdir, RemoteBzrDir)
981
728
        return a_bzrdir.create_branch()
982
729
 
983
 
    def supports_tags(self):
984
 
        # Remote branches might support tags, but we won't know until we
985
 
        # access the real remote branch.
986
 
        return True
987
 
 
988
730
 
989
731
class RemoteBranch(branch.Branch):
990
732
    """Branch stored on a server accessed by HPSS RPC.
1003
745
        # We intentionally don't call the parent class's __init__, because it
1004
746
        # will try to assign to self.tags, which is a property in this subclass.
1005
747
        # And the parent's __init__ doesn't do much anyway.
1006
 
        self._revision_id_to_revno_cache = None
1007
748
        self._revision_history_cache = None
1008
749
        self.bzrdir = remote_bzrdir
1009
750
        if _client is not None:
1010
751
            self._client = _client
1011
752
        else:
1012
 
            self._client = client._SmartClient(self.bzrdir._shared_medium)
 
753
            self._client = client._SmartClient(self.bzrdir._medium)
1013
754
        self.repository = remote_repository
1014
755
        if real_branch is not None:
1015
756
            self._real_branch = real_branch
1095
836
            self.repository.unlock()
1096
837
        path = self.bzrdir._path_for_remote_call(self._client)
1097
838
        response = self._client.call('Branch.lock_write', path, branch_token,
1098
 
                                     repo_token or '')
 
839
                                     repo_token)
1099
840
        if response[0] == 'ok':
1100
841
            ok, branch_token, repo_token = response
1101
842
            return branch_token, repo_token
1107
848
            raise errors.UnlockableTransport(self.bzrdir.root_transport)
1108
849
        elif response[0] == 'ReadOnlyError':
1109
850
            raise errors.ReadOnlyError(self)
1110
 
        elif response[0] == 'LockFailed':
1111
 
            raise errors.LockFailed(response[1], response[2])
1112
851
        else:
1113
852
            raise errors.UnexpectedSmartServerResponse(response)
1114
853
            
1148
887
                if token != self._lock_token:
1149
888
                    raise errors.TokenMismatch(token, self._lock_token)
1150
889
            self._lock_count += 1
1151
 
        return self._lock_token or None
 
890
        return self._lock_token
1152
891
 
1153
892
    def _unlock(self, branch_token, repo_token):
1154
893
        path = self.bzrdir._path_for_remote_call(self._client)
1155
894
        response = self._client.call('Branch.unlock', path, branch_token,
1156
 
                                     repo_token or '')
 
895
                                     repo_token)
1157
896
        if response == ('ok',):
1158
897
            return
1159
898
        elif response[0] == 'TokenMismatch':
1169
908
            mode = self._lock_mode
1170
909
            self._lock_mode = None
1171
910
            if self._real_branch is not None:
1172
 
                if (not self._leave_lock and mode == 'w' and
1173
 
                    self._repo_lock_token):
 
911
                if not self._leave_lock:
1174
912
                    # If this RemoteBranch will remove the physical lock for the
1175
913
                    # repository, make sure the _real_branch doesn't do it
1176
914
                    # first.  (Because the _real_branch's repository is set to
1194
932
        return self._real_branch.break_lock()
1195
933
 
1196
934
    def leave_lock_in_place(self):
1197
 
        if not self._lock_token:
1198
 
            raise NotImplementedError(self.leave_lock_in_place)
1199
935
        self._leave_lock = True
1200
936
 
1201
937
    def dont_leave_lock_in_place(self):
1202
 
        if not self._lock_token:
1203
 
            raise NotImplementedError(self.dont_leave_lock_in_place)
1204
938
        self._leave_lock = False
1205
939
 
1206
940
    def last_revision_info(self):
1260
994
        # format, because RemoteBranches can't be created at arbitrary URLs.
1261
995
        # XXX: if to_bzrdir is a RemoteBranch, this should perhaps do
1262
996
        # to_bzrdir.create_branch...
1263
 
        self._ensure_real()
1264
 
        result = self._real_branch._format.initialize(to_bzrdir)
 
997
        result = branch.BranchFormat.get_default_format().initialize(to_bzrdir)
1265
998
        self.copy_content_into(result, revision_id=revision_id)
1266
999
        result.set_parent(self.bzrdir.root_transport.base)
1267
1000
        return result
1268
1001
 
1269
1002
    @needs_write_lock
 
1003
    def append_revision(self, *revision_ids):
 
1004
        self._ensure_real()
 
1005
        return self._real_branch.append_revision(*revision_ids)
 
1006
 
 
1007
    @needs_write_lock
1270
1008
    def pull(self, source, overwrite=False, stop_revision=None,
1271
1009
             **kwargs):
1272
1010
        # FIXME: This asks the real branch to run the hooks, which means
1309
1047
        self._ensure_real()
1310
1048
        return self._real_branch.set_push_location(location)
1311
1049
 
1312
 
    def update_revisions(self, other, stop_revision=None, overwrite=False):
 
1050
    def update_revisions(self, other, stop_revision=None):
1313
1051
        self._ensure_real()
1314
1052
        return self._real_branch.update_revisions(
1315
 
            other, stop_revision=stop_revision, overwrite=overwrite)
 
1053
            other, stop_revision=stop_revision)
1316
1054
 
1317
1055
 
1318
1056
class RemoteBranchConfig(BranchConfig):