/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
1
# Copyright (C) 2006-2008 Canonical Ltd
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
3192.2.2 by Andrew Bennetts
Just use urllib.unquote, as suggested by John's review.
17
import urllib
2414.1.1 by Andrew Bennetts
Add some unicode-related tests from the hpss branch, and a few other nits (also from the hpss branch).
18
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
19
import bzrlib
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
20
from bzrlib.smart import message, protocol
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
21
from bzrlib.trace import warning
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
22
from bzrlib import urlutils, errors
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
23
24
2414.1.4 by Andrew Bennetts
Rename SmartClient to _SmartClient.
25
class _SmartClient(object):
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
26
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
27
    def __init__(self, medium, base, headers=None):
3104.4.4 by Andrew Bennetts
Rename parameter to _SmartClient.__init__ to be less confusing.
28
        """Constructor.
29
3313.2.1 by Andrew Bennetts
Change _SmartClient's API to accept a medium and a base, rather than a _SharedConnection.
30
        :param medium: a SmartClientMedium
31
        :param base: a URL
3104.4.4 by Andrew Bennetts
Rename parameter to _SmartClient.__init__ to be less confusing.
32
        """
3313.2.1 by Andrew Bennetts
Change _SmartClient's API to accept a medium and a base, rather than a _SharedConnection.
33
        self._medium = medium
34
        self._base = base
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
35
        if headers is None:
36
            self._headers = {'Software version': bzrlib.__version__}
37
        else:
38
            self._headers = dict(headers)
39
3245.4.46 by Andrew Bennetts
Apply John's review comments.
40
    def _send_request(self, protocol_version, method, args, body=None,
41
                      readv_body=None):
42
        encoder, response_handler = self._construct_protocol(
43
            protocol_version)
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
44
        encoder.set_headers(self._headers)
45
        if body is not None:
3245.4.46 by Andrew Bennetts
Apply John's review comments.
46
            if readv_body is not None:
47
                raise AssertionError(
48
                    "body and readv_body are mutually exclusive.")
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
49
            encoder.call_with_body_bytes((method, ) + args, body)
50
        elif readv_body is not None:
51
            encoder.call_with_body_readv_array((method, ) + args,
52
                    readv_body)
53
        else:
54
            encoder.call(method, *args)
3245.4.46 by Andrew Bennetts
Apply John's review comments.
55
        return response_handler
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
56
57
    def _call_and_read_response(self, method, args, body=None, readv_body=None,
58
            expect_response_body=True):
3245.4.47 by Andrew Bennetts
Don't automatically send 'hello' requests from RemoteBzrDirFormat.probe_transport unless we have to (i.e. the transport is HTTP).
59
        if self._medium._protocol_version is not None:
3245.4.46 by Andrew Bennetts
Apply John's review comments.
60
            response_handler = self._send_request(
3245.4.47 by Andrew Bennetts
Don't automatically send 'hello' requests from RemoteBzrDirFormat.probe_transport unless we have to (i.e. the transport is HTTP).
61
                self._medium._protocol_version, method, args, body=body,
3245.4.46 by Andrew Bennetts
Apply John's review comments.
62
                readv_body=readv_body)
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
63
            return (response_handler.read_response_tuple(
64
                        expect_body=expect_response_body),
65
                    response_handler)
66
        else:
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
67
            for protocol_version in [3, 2]:
3245.4.46 by Andrew Bennetts
Apply John's review comments.
68
                response_handler = self._send_request(
69
                    protocol_version, method, args, body=body,
70
                    readv_body=readv_body)
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
71
                try:
72
                    response_tuple = response_handler.read_response_tuple(
73
                        expect_body=expect_response_body)
3245.4.43 by Andrew Bennetts
Improve tests for automatic detection of protocol version.
74
                except errors.UnexpectedProtocolVersionMarker, err:
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
75
                    # TODO: We could recover from this without disconnecting if
76
                    # we recognise the protocol version.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
77
                    warning(
78
                        'Server does not understand Bazaar network protocol %d,'
3245.4.62 by Andrew Bennetts
Fix unsubstituted '%d' in reconnection warning.
79
                        ' reconnecting.  (Upgrade the server to avoid this.)'
80
                        % (protocol_version,))
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
81
                    self._medium.disconnect()
82
                    continue
83
                else:
3245.4.47 by Andrew Bennetts
Don't automatically send 'hello' requests from RemoteBzrDirFormat.probe_transport unless we have to (i.e. the transport is HTTP).
84
                    self._medium._protocol_version = protocol_version
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
85
                    return response_tuple, response_handler
3245.4.44 by Andrew Bennetts
Remove auto-detection of protocol v1; it's complex and there's a high risk of false positives. Also remove unused mock object.
86
            raise errors.SmartProtocolError(
87
                'Server is not a Bazaar server: ' + str(err))
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
88
89
    def _construct_protocol(self, version):
3241.2.2 by Andrew Bennetts
Merge from bzr.dev.
90
        request = self._medium.get_request()
3245.4.1 by Andrew Bennetts
Merge in the protocol-v3 implementation so far, integrating with the protocol negotiation in bzrlib.smart.client.
91
        if version == 3:
92
            request_encoder = protocol.ProtocolThreeRequester(request)
93
            response_handler = message.ConventionalResponseHandler()
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
94
            response_proto = protocol.ProtocolThreeDecoder(
95
                response_handler, expect_version_marker=True)
3245.4.26 by Andrew Bennetts
Rename 'setProtoAndMedium' to more accurate 'setProtoAndMediumRequest', add ABCs for Requesters and ResponseHandlers.
96
            response_handler.setProtoAndMediumRequest(response_proto, request)
3245.4.1 by Andrew Bennetts
Merge in the protocol-v3 implementation so far, integrating with the protocol negotiation in bzrlib.smart.client.
97
        elif version == 2:
98
            request_encoder = protocol.SmartClientRequestProtocolTwo(request)
99
            response_handler = request_encoder
3241.2.1 by Andrew Bennetts
Dynamically choose the best client protocol version in bzrlib.smart.client.
100
        else:
3245.4.1 by Andrew Bennetts
Merge in the protocol-v3 implementation so far, integrating with the protocol negotiation in bzrlib.smart.client.
101
            request_encoder = protocol.SmartClientRequestProtocolOne(request)
102
            response_handler = request_encoder
103
        return request_encoder, response_handler
3241.2.1 by Andrew Bennetts
Dynamically choose the best client protocol version in bzrlib.smart.client.
104
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
105
    def call(self, method, *args):
106
        """Call a method on the remote server."""
2414.1.2 by Andrew Bennetts
Deal with review comments.
107
        result, protocol = self.call_expecting_body(method, *args)
2414.1.1 by Andrew Bennetts
Add some unicode-related tests from the hpss branch, and a few other nits (also from the hpss branch).
108
        protocol.cancel_read_body()
109
        return result
110
2414.1.2 by Andrew Bennetts
Deal with review comments.
111
    def call_expecting_body(self, method, *args):
112
        """Call a method and return the result and the protocol object.
113
        
114
        The body can be read like so::
115
116
            result, smart_protocol = smart_client.call_expecting_body(...)
117
            body = smart_protocol.read_body_bytes()
118
        """
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
119
        return self._call_and_read_response(
120
            method, args, expect_response_body=True)
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
121
122
    def call_with_body_bytes(self, method, args, body):
123
        """Call a method on the remote server with body bytes."""
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
124
        if type(method) is not str:
125
            raise TypeError('method must be a byte string, not %r' % (method,))
126
        for arg in args:
127
            if type(arg) is not str:
128
                raise TypeError('args must be byte strings, not %r' % (args,))
129
        if type(body) is not str:
130
            raise TypeError('body must be byte string, not %r' % (body,))
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
131
        response, response_handler = self._call_and_read_response(
132
            method, args, body=body, expect_response_body=False)
133
        return response
2414.1.1 by Andrew Bennetts
Add some unicode-related tests from the hpss branch, and a few other nits (also from the hpss branch).
134
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
135
    def call_with_body_bytes_expecting_body(self, method, args, body):
136
        """Call a method on the remote server with body bytes."""
137
        if type(method) is not str:
138
            raise TypeError('method must be a byte string, not %r' % (method,))
139
        for arg in args:
140
            if type(arg) is not str:
141
                raise TypeError('args must be byte strings, not %r' % (args,))
142
        if type(body) is not str:
143
            raise TypeError('body must be byte string, not %r' % (body,))
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
144
        response, response_handler = self._call_and_read_response(
145
            method, args, body=body, expect_response_body=True)
146
        return (response, response_handler)
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
147
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
148
    def call_with_body_readv_array(self, args, body):
3245.4.42 by Andrew Bennetts
Make _SmartClient automatically detect and use the highest protocol version compatible with the server.
149
        response, response_handler = self._call_and_read_response(
150
                args[0], args[1:], readv_body=body, expect_response_body=True)
151
        return (response, response_handler)
3245.4.24 by Andrew Bennetts
Consistently raise errors from the server as ErrorFromSmartServer exceptions.
152
2414.1.1 by Andrew Bennetts
Add some unicode-related tests from the hpss branch, and a few other nits (also from the hpss branch).
153
    def remote_path_from_transport(self, transport):
2414.1.2 by Andrew Bennetts
Deal with review comments.
154
        """Convert transport into a path suitable for using in a request.
155
        
156
        Note that the resulting remote path doesn't encode the host name or
157
        anything but path, so it is only safe to use it in requests sent over
158
        the medium from the matching transport.
159
        """
3313.2.1 by Andrew Bennetts
Change _SmartClient's API to accept a medium and a base, rather than a _SharedConnection.
160
        base = self._base
3313.3.1 by Andrew Bennetts
Treat http:// and https:// URLs correctly in _SmartClient.remote_path_for_transport.
161
        if (base.startswith('bzr+http://') or base.startswith('bzr+https://')
162
            or base.startswith('http://') or base.startswith('https://')):
3313.2.1 by Andrew Bennetts
Change _SmartClient's API to accept a medium and a base, rather than a _SharedConnection.
163
            medium_base = self._base
3104.4.2 by Andrew Bennetts
All tests passing.
164
        else:
3313.2.1 by Andrew Bennetts
Change _SmartClient's API to accept a medium and a base, rather than a _SharedConnection.
165
            medium_base = urlutils.join(self._base, '/')
3104.4.2 by Andrew Bennetts
All tests passing.
166
            
3192.2.1 by Andrew Bennetts
Don't transmit URL-escaped relpaths in the smart protocol, which is back to how things worked in bzr 1.1 and earlier.
167
        rel_url = urlutils.relative_url(medium_base, transport.base)
3192.2.2 by Andrew Bennetts
Just use urllib.unquote, as suggested by John's review.
168
        return urllib.unquote(rel_url)
3297.3.1 by Andrew Bennetts
Raise UnknownSmartMethod automatically from read_response_tuple.
169