/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

  • Committer: Andrew Bennetts
  • Date: 2008-04-02 00:14:00 UTC
  • mfrom: (3324 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3756.
  • Revision ID: andrew.bennetts@canonical.com-20080402001400-r1pqse38i03dl97w
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
    errors,
25
25
    registry,
26
26
    revision,
 
27
    urlutils,
27
28
    )
28
29
from bzrlib.lazy_import import lazy_import
29
30
lazy_import(globals(), """
32
33
 
33
34
 
34
35
class SmartServerRequest(object):
35
 
    """Base class for request handlers."""
 
36
    """Base class for request handlers.
 
37
    
 
38
    To define a new request, subclass this class and override the `do` method
 
39
    (and if appropriate, `do_body` as well).  Request implementors should take
 
40
    care to call `translate_client_path` and `transport_from_client_path` as
 
41
    appropriate when dealing with paths received from the client.
 
42
    """
36
43
 
37
 
    def __init__(self, backing_transport):
 
44
    def __init__(self, backing_transport, root_client_path='/'):
38
45
        """Constructor.
39
46
 
40
47
        :param backing_transport: the base transport to be used when performing
41
48
            this request.
 
49
        :param root_client_path: the client path that maps to the root of
 
50
            backing_transport.  This is used to interpret relpaths received
 
51
            from the client.  Clients will not be able to refer to paths above
 
52
            this root.  If root_client_path is None, then no translation will
 
53
            be performed on client paths.  Default is '/'.
42
54
        """
43
55
        self._backing_transport = backing_transport
 
56
        if root_client_path is not None:
 
57
            if not root_client_path.startswith('/'):
 
58
                root_client_path = '/' + root_client_path
 
59
            if not root_client_path.endswith('/'):
 
60
                root_client_path += '/'
 
61
        self._root_client_path = root_client_path
44
62
 
45
63
    def _check_enabled(self):
46
64
        """Raises DisabledMethod if this method is disabled."""
79
97
        # this NotImplementedError and translate it into a 'bad request' error
80
98
        # to send to the client.
81
99
        raise NotImplementedError(self.do_body)
 
100
    
 
101
    def translate_client_path(self, client_path):
 
102
        """Translate a path received from a network client into a local
 
103
        relpath.
 
104
 
 
105
        All paths received from the client *must* be translated.
 
106
 
 
107
        :param client_path: the path from the client.
 
108
        :returns: a relpath that may be used with self._backing_transport
 
109
            (unlike the untranslated client_path, which must not be used with
 
110
            the backing transport).
 
111
        """
 
112
        if self._root_client_path is None:
 
113
            # no translation necessary!
 
114
            return client_path
 
115
        if not client_path.startswith('/'):
 
116
            client_path = '/' + client_path
 
117
        if client_path.startswith(self._root_client_path):
 
118
            path = client_path[len(self._root_client_path):]
 
119
            relpath = urlutils.joinpath('/', path)
 
120
            assert relpath.startswith('/')
 
121
            return '.' + relpath
 
122
        else:
 
123
            raise errors.PathNotChild(client_path, self._root_client_path)
 
124
 
 
125
    def transport_from_client_path(self, client_path):
 
126
        """Get a backing transport corresponding to the location referred to by
 
127
        a network client.
 
128
 
 
129
        :seealso: translate_client_path
 
130
        :returns: a transport cloned from self._backing_transport
 
131
        """
 
132
        relpath = self.translate_client_path(client_path)
 
133
        return self._backing_transport.clone(relpath)
82
134
 
83
135
 
84
136
class SmartServerResponse(object):
111
163
                other.body_stream is self.body_stream)
112
164
 
113
165
    def __repr__(self):
114
 
        return ("<SmartServerResponse successful=%s args=%r body=%r>"
115
 
                % (self.is_successful(), self.args, self.body))
 
166
        status = {True: 'OK', False: 'ERR'}[self.is_successful()]
 
167
        return "<SmartServerResponse status=%s args=%r body=%r>" % (status,
 
168
            self.args, self.body)
116
169
 
117
170
 
118
171
class FailedSmartServerResponse(SmartServerResponse):
148
201
    # TODO: Better way of representing the body for commands that take it,
149
202
    # and allow it to be streamed into the server.
150
203
 
151
 
    def __init__(self, backing_transport, commands):
 
204
    def __init__(self, backing_transport, commands, root_client_path):
152
205
        """Constructor.
153
206
 
154
207
        :param backing_transport: a Transport to handle requests for.
156
209
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
157
210
        """
158
211
        self._backing_transport = backing_transport
 
212
        self._root_client_path = root_client_path
159
213
        self._commands = commands
160
214
        self._body_bytes = ''
161
215
        self.response = None
185
239
            command = self._commands.get(cmd)
186
240
        except LookupError:
187
241
            raise errors.SmartProtocolError("bad request %r" % (cmd,))
188
 
        self._command = command(self._backing_transport)
 
242
        self._command = command(self._backing_transport, self._root_client_path)
189
243
        self._run_handler_code(self._command.execute, args, {})
190
244
 
191
245
    def _run_handler_code(self, callable, args, kwargs):
252
306
 
253
307
    def do(self, path, revision_id):
254
308
        # open transport relative to our base
255
 
        t = self._backing_transport.clone(path)
 
309
        t = self.transport_from_client_path(path)
256
310
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
257
311
        repo = control.open_repository()
258
312
        tmpf = tempfile.TemporaryFile()