~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

Merge with stored_kind

Show diffs side-by-side

added added

removed removed

Lines of Context:
723
723
        self._ensure_real()
724
724
        return self._real_repository.get_revision(revision_id)
725
725
 
726
 
    @property
727
 
    def weave_store(self):
728
 
        self._ensure_real()
729
 
        return self._real_repository.weave_store
730
 
 
731
726
    def get_transaction(self):
732
727
        self._ensure_real()
733
728
        return self._real_repository.get_transaction()
782
777
        self._ensure_real()
783
778
        self._real_repository.create_bundle(target, base, fileobj, format)
784
779
 
785
 
    @property
786
 
    def control_weaves(self):
787
 
        self._ensure_real()
788
 
        return self._real_repository.control_weaves
789
 
 
790
780
    @needs_read_lock
791
781
    def get_ancestry(self, revision_id, topo_sorted=True):
792
782
        self._ensure_real()
793
783
        return self._real_repository.get_ancestry(revision_id, topo_sorted)
794
784
 
795
 
    @needs_read_lock
796
 
    def get_inventory_weave(self):
797
 
        self._ensure_real()
798
 
        return self._real_repository.get_inventory_weave()
799
 
 
800
785
    def fileids_altered_by_revision_ids(self, revision_ids):
801
786
        self._ensure_real()
802
787
        return self._real_repository.fileids_altered_by_revision_ids(revision_ids)
1029
1014
        # TODO: Suggestion from john: using external tar is much faster than
1030
1015
        # python's tarfile library, but it may not work on windows.
1031
1016
 
 
1017
    @property
 
1018
    def inventories(self):
 
1019
        """Decorate the real repository for now.
 
1020
 
 
1021
        In the long term a full blown network facility is needed to
 
1022
        avoid creating a real repository object locally.
 
1023
        """
 
1024
        self._ensure_real()
 
1025
        return self._real_repository.inventories
 
1026
 
1032
1027
    @needs_write_lock
1033
1028
    def pack(self):
1034
1029
        """Compress the data within the repository.
1038
1033
        self._ensure_real()
1039
1034
        return self._real_repository.pack()
1040
1035
 
 
1036
    @property
 
1037
    def revisions(self):
 
1038
        """Decorate the real repository for now.
 
1039
 
 
1040
        In the short term this should become a real object to intercept graph
 
1041
        lookups.
 
1042
 
 
1043
        In the long term a full blown network facility is needed.
 
1044
        """
 
1045
        self._ensure_real()
 
1046
        return self._real_repository.revisions
 
1047
 
1041
1048
    def set_make_working_trees(self, new_value):
1042
1049
        self._ensure_real()
1043
1050
        self._real_repository.set_make_working_trees(new_value)
1044
1051
 
 
1052
    @property
 
1053
    def signatures(self):
 
1054
        """Decorate the real repository for now.
 
1055
 
 
1056
        In the long term a full blown network facility is needed to avoid
 
1057
        creating a real repository object locally.
 
1058
        """
 
1059
        self._ensure_real()
 
1060
        return self._real_repository.signatures
 
1061
 
1045
1062
    @needs_write_lock
1046
1063
    def sign_revision(self, revision_id, gpg_strategy):
1047
1064
        self._ensure_real()
1048
1065
        return self._real_repository.sign_revision(revision_id, gpg_strategy)
1049
1066
 
 
1067
    @property
 
1068
    def texts(self):
 
1069
        """Decorate the real repository for now.
 
1070
 
 
1071
        In the long term a full blown network facility is needed to avoid
 
1072
        creating a real repository object locally.
 
1073
        """
 
1074
        self._ensure_real()
 
1075
        return self._real_repository.texts
 
1076
 
1050
1077
    @needs_read_lock
1051
1078
    def get_revisions(self, revision_ids):
1052
1079
        self._ensure_real()
1078
1105
        self._ensure_real()
1079
1106
        return self._real_repository.has_signature_for_revision_id(revision_id)
1080
1107
 
1081
 
    def get_data_stream_for_search(self, search):
1082
 
        medium = self._client._medium
1083
 
        if medium._is_remote_before((1, 2)):
1084
 
            self._ensure_real()
1085
 
            return self._real_repository.get_data_stream_for_search(search)
1086
 
        REQUEST_NAME = 'Repository.stream_revisions_chunked'
1087
 
        path = self.bzrdir._path_for_remote_call(self._client)
1088
 
        body = self._serialise_search_recipe(search.get_recipe())
1089
 
        try:
1090
 
            result = self._client.call_with_body_bytes_expecting_body(
1091
 
                REQUEST_NAME, (path,), body)
1092
 
            response, protocol = result
1093
 
        except errors.UnknownSmartMethod:
1094
 
            # Server does not support this method, so fall back to VFS.
1095
 
            # Worse, we have to force a disconnection, because the server now
1096
 
            # doesn't realise it has a body on the wire to consume, so the
1097
 
            # only way to recover is to abandon the connection.
1098
 
            warning(
1099
 
                'Server is too old for streaming pull, reconnecting.  '
1100
 
                '(Upgrade the server to Bazaar 1.2 to avoid this)')
1101
 
            medium.disconnect()
1102
 
            # To avoid having to disconnect repeatedly, we keep track of the
1103
 
            # fact the server doesn't understand this remote method.
1104
 
            medium._remember_remote_is_before((1, 2))
1105
 
            self._ensure_real()
1106
 
            return self._real_repository.get_data_stream_for_search(search)
1107
 
 
1108
 
        if response == ('ok',):
1109
 
            return self._deserialise_stream(protocol)
1110
 
        if response == ('NoSuchRevision', ):
1111
 
            # We cannot easily identify the revision that is missing in this
1112
 
            # situation without doing much more network IO. For now, bail.
1113
 
            raise NoSuchRevision(self, "unknown")
1114
 
        else:
1115
 
            raise errors.UnexpectedSmartServerResponse(response)
1116
 
 
1117
 
    def _deserialise_stream(self, protocol):
1118
 
        stream = protocol.read_streamed_body()
1119
 
        container_parser = ContainerPushParser()
1120
 
        for bytes in stream:
1121
 
            container_parser.accept_bytes(bytes)
1122
 
            records = container_parser.read_pending_records()
1123
 
            for record_names, record_bytes in records:
1124
 
                if len(record_names) != 1:
1125
 
                    # These records should have only one name, and that name
1126
 
                    # should be a one-element tuple.
1127
 
                    raise errors.SmartProtocolError(
1128
 
                        'Repository data stream had invalid record name %r'
1129
 
                        % (record_names,))
1130
 
                name_tuple = record_names[0]
1131
 
                yield name_tuple, record_bytes
1132
 
 
1133
 
    def insert_data_stream(self, stream):
1134
 
        self._ensure_real()
1135
 
        self._real_repository.insert_data_stream(stream)
1136
 
 
1137
1108
    def item_keys_introduced_by(self, revision_ids, _files_pb=None):
1138
1109
        self._ensure_real()
1139
1110
        return self._real_repository.item_keys_introduced_by(revision_ids,
1230
1201
        # And the parent's __init__ doesn't do much anyway.
1231
1202
        self._revision_id_to_revno_cache = None
1232
1203
        self._revision_history_cache = None
 
1204
        self._last_revision_info_cache = None
1233
1205
        self.bzrdir = remote_bzrdir
1234
1206
        if _client is not None:
1235
1207
            self._client = _client
1293
1265
            if self._lock_mode == 'r':
1294
1266
                self._real_branch.lock_read()
1295
1267
 
 
1268
    def _clear_cached_state(self):
 
1269
        super(RemoteBranch, self)._clear_cached_state()
 
1270
        if self._real_branch is not None:
 
1271
            self._real_branch._clear_cached_state()
 
1272
 
 
1273
    def _clear_cached_state_of_remote_branch_only(self):
 
1274
        """Like _clear_cached_state, but doesn't clear the cache of
 
1275
        self._real_branch.
 
1276
 
 
1277
        This is useful when falling back to calling a method of
 
1278
        self._real_branch that changes state.  In that case the underlying
 
1279
        branch changes, so we need to invalidate this RemoteBranch's cache of
 
1280
        it.  However, there's no need to invalidate the _real_branch's cache
 
1281
        too, in fact doing so might harm performance.
 
1282
        """
 
1283
        super(RemoteBranch, self)._clear_cached_state()
 
1284
        
1296
1285
    @property
1297
1286
    def control_files(self):
1298
1287
        # Defer actually creating RemoteBranchLockableFiles until its needed,
1444
1433
            raise NotImplementedError(self.dont_leave_lock_in_place)
1445
1434
        self._leave_lock = False
1446
1435
 
1447
 
    def last_revision_info(self):
1448
 
        """See Branch.last_revision_info()."""
 
1436
    def _last_revision_info(self):
1449
1437
        path = self.bzrdir._path_for_remote_call(self._client)
1450
1438
        response = self._client.call('Branch.last_revision_info', path)
1451
1439
        if response[0] != 'ok':
1460
1448
        response_tuple, response_handler = self._client.call_expecting_body(
1461
1449
            'Branch.revision_history', path)
1462
1450
        if response_tuple[0] != 'ok':
1463
 
            raise UnexpectedSmartServerResponse(response_tuple)
 
1451
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1464
1452
        result = response_handler.read_body_bytes().split('\x00')
1465
1453
        if result == ['']:
1466
1454
            return []
1467
1455
        return result
1468
1456
 
 
1457
    def _set_last_revision_descendant(self, revision_id, other_branch,
 
1458
            allow_diverged=False, allow_overwrite_descendant=False):
 
1459
        path = self.bzrdir._path_for_remote_call(self._client)
 
1460
        try:
 
1461
            response = self._client.call('Branch.set_last_revision_ex',
 
1462
                path, self._lock_token, self._repo_lock_token, revision_id,
 
1463
                int(allow_diverged), int(allow_overwrite_descendant))
 
1464
        except errors.ErrorFromSmartServer, err:
 
1465
            if err.error_verb == 'NoSuchRevision':
 
1466
                raise NoSuchRevision(self, revision_id)
 
1467
            elif err.error_verb == 'Diverged':
 
1468
                raise errors.DivergedBranches(self, other_branch)
 
1469
            raise
 
1470
        self._clear_cached_state()
 
1471
        if len(response) != 3 and response[0] != 'ok':
 
1472
            raise errors.UnexpectedSmartServerResponse(response)
 
1473
        new_revno, new_revision_id = response[1:]
 
1474
        self._last_revision_info_cache = new_revno, new_revision_id
 
1475
        self._real_branch._last_revision_info_cache = new_revno, new_revision_id
 
1476
 
 
1477
    def _set_last_revision(self, revision_id):
 
1478
        path = self.bzrdir._path_for_remote_call(self._client)
 
1479
        self._clear_cached_state()
 
1480
        try:
 
1481
            response = self._client.call('Branch.set_last_revision',
 
1482
                path, self._lock_token, self._repo_lock_token, revision_id)
 
1483
        except errors.ErrorFromSmartServer, err:
 
1484
            if err.error_verb == 'NoSuchRevision':
 
1485
                raise NoSuchRevision(self, revision_id)
 
1486
            raise
 
1487
        if response != ('ok',):
 
1488
            raise errors.UnexpectedSmartServerResponse(response)
 
1489
 
1469
1490
    @needs_write_lock
1470
1491
    def set_revision_history(self, rev_history):
1471
1492
        # Send just the tip revision of the history; the server will generate
1472
1493
        # the full history from that.  If the revision doesn't exist in this
1473
1494
        # branch, NoSuchRevision will be raised.
1474
 
        path = self.bzrdir._path_for_remote_call(self._client)
1475
1495
        if rev_history == []:
1476
1496
            rev_id = 'null:'
1477
1497
        else:
1478
1498
            rev_id = rev_history[-1]
1479
 
        self._clear_cached_state()
1480
 
        try:
1481
 
            response = self._client.call('Branch.set_last_revision',
1482
 
                path, self._lock_token, self._repo_lock_token, rev_id)
1483
 
        except errors.ErrorFromSmartServer, err:
1484
 
            if err.error_verb == 'NoSuchRevision':
1485
 
                raise NoSuchRevision(self, rev_id)
1486
 
            raise
1487
 
        if response != ('ok',):
1488
 
            raise errors.UnexpectedSmartServerResponse(response)
 
1499
        self._set_last_revision(rev_id)
1489
1500
        self._cache_revision_history(rev_history)
1490
1501
 
1491
1502
    def get_parent(self):
1510
1521
    @needs_write_lock
1511
1522
    def pull(self, source, overwrite=False, stop_revision=None,
1512
1523
             **kwargs):
 
1524
        self._clear_cached_state_of_remote_branch_only()
1513
1525
        self._ensure_real()
1514
1526
        return self._real_branch.pull(
1515
1527
            source, overwrite=overwrite, stop_revision=stop_revision,
1534
1546
                path, self._lock_token, self._repo_lock_token, str(revno), revision_id)
1535
1547
        except errors.UnknownSmartMethod:
1536
1548
            self._ensure_real()
1537
 
            self._clear_cached_state()
1538
 
            return self._real_branch.set_last_revision_info(revno, revision_id)
 
1549
            self._clear_cached_state_of_remote_branch_only()
 
1550
            self._real_branch.set_last_revision_info(revno, revision_id)
 
1551
            self._last_revision_info_cache = revno, revision_id
 
1552
            return
1539
1553
        except errors.ErrorFromSmartServer, err:
1540
1554
            if err.error_verb == 'NoSuchRevision':
1541
1555
                raise NoSuchRevision(self, err.error_args[0])
1542
1556
            raise
1543
1557
        if response == ('ok',):
1544
1558
            self._clear_cached_state()
 
1559
            self._last_revision_info_cache = revno, revision_id
 
1560
            # Update the _real_branch's cache too.
 
1561
            if self._real_branch is not None:
 
1562
                cache = self._last_revision_info_cache
 
1563
                self._real_branch._last_revision_info_cache = cache
1545
1564
        else:
1546
1565
            raise errors.UnexpectedSmartServerResponse(response)
1547
1566
 
 
1567
    @needs_write_lock
1548
1568
    def generate_revision_history(self, revision_id, last_rev=None,
1549
1569
                                  other_branch=None):
 
1570
        medium = self._client._medium
 
1571
        if not medium._is_remote_before((1, 6)):
 
1572
            try:
 
1573
                self._set_last_revision_descendant(revision_id, other_branch,
 
1574
                    allow_diverged=True, allow_overwrite_descendant=True)
 
1575
                return
 
1576
            except errors.UnknownSmartMethod:
 
1577
                medium._remember_remote_is_before((1, 6))
 
1578
        self._clear_cached_state_of_remote_branch_only()
1550
1579
        self._ensure_real()
1551
 
        return self._real_branch.generate_revision_history(
 
1580
        self._real_branch.generate_revision_history(
1552
1581
            revision_id, last_rev=last_rev, other_branch=other_branch)
1553
1582
 
1554
1583
    @property
1560
1589
        self._ensure_real()
1561
1590
        return self._real_branch.set_push_location(location)
1562
1591
 
 
1592
    @needs_write_lock
1563
1593
    def update_revisions(self, other, stop_revision=None, overwrite=False,
1564
1594
                         graph=None):
1565
 
        self._ensure_real()
1566
 
        return self._real_branch.update_revisions(
1567
 
            other, stop_revision=stop_revision, overwrite=overwrite,
1568
 
            graph=graph)
 
1595
        """See Branch.update_revisions."""
 
1596
        other.lock_read()
 
1597
        try:
 
1598
            if stop_revision is None:
 
1599
                stop_revision = other.last_revision()
 
1600
                if revision.is_null(stop_revision):
 
1601
                    # if there are no commits, we're done.
 
1602
                    return
 
1603
            self.fetch(other, stop_revision)
 
1604
 
 
1605
            if overwrite:
 
1606
                # Just unconditionally set the new revision.  We don't care if
 
1607
                # the branches have diverged.
 
1608
                self._set_last_revision(stop_revision)
 
1609
            else:
 
1610
                medium = self._client._medium
 
1611
                if not medium._is_remote_before((1, 6)):
 
1612
                    try:
 
1613
                        self._set_last_revision_descendant(stop_revision, other)
 
1614
                        return
 
1615
                    except errors.UnknownSmartMethod:
 
1616
                        medium._remember_remote_is_before((1, 6))
 
1617
                # Fallback for pre-1.6 servers: check for divergence
 
1618
                # client-side, then do _set_last_revision.
 
1619
                last_rev = revision.ensure_null(self.last_revision())
 
1620
                if graph is None:
 
1621
                    graph = self.repository.get_graph()
 
1622
                if self._check_if_descendant_or_diverged(
 
1623
                        stop_revision, last_rev, graph, other):
 
1624
                    # stop_revision is a descendant of last_rev, but we aren't
 
1625
                    # overwriting, so we're done.
 
1626
                    return
 
1627
                self._set_last_revision(stop_revision)
 
1628
        finally:
 
1629
            other.unlock()
1569
1630
 
1570
1631
 
1571
1632
def _extract_tar(tar, to_dir):