~bzr-pqm/bzr/bzr.dev

2402.1.2 by Andrew Bennetts
Deal with review comments.
1
# Copyright (C) 2006, 2007 Canonical Ltd
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
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
17
"""VFS operations for the smart server.
18
19
This module defines the smart server methods that are low-level file operations
20
-- i.e. methods that operate directly on files and directories, rather than
21
higher-level concepts like branches and revisions.
22
23
These methods, plus 'hello' and 'get_bundle', are version 1 of the smart server
24
protocol, as implemented in bzr 0.11 and later.
25
"""
26
27
import os
28
29
from bzrlib import errors
30
from bzrlib.smart import request
31
32
33
def _deserialise_optional_mode(mode):
34
    # XXX: FIXME this should be on the protocol object.  Later protocol versions
35
    # might serialise modes differently.
36
    if mode == '':
37
        return None
38
    else:
39
        return int(mode)
40
41
42
def vfs_enabled():
43
    """Is the VFS enabled ?
44
2402.1.2 by Andrew Bennetts
Deal with review comments.
45
    the VFS is disabled when the BZR_NO_SMART_VFS environment variable is set.
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
46
47
    :return: True if it is enabled.
48
    """
2402.1.2 by Andrew Bennetts
Deal with review comments.
49
    return not 'BZR_NO_SMART_VFS' in os.environ
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
50
51
52
class VfsRequest(request.SmartServerRequest):
53
    """Base class for VFS requests.
54
    
55
    VFS requests are disabled if vfs_enabled() returns False.
56
    """
57
58
    def _check_enabled(self):
59
        if not vfs_enabled():
60
            raise errors.DisabledMethod(self.__class__.__name__)
61
62
63
class HasRequest(VfsRequest):
64
65
    def do(self, relpath):
66
        r = self._backing_transport.has(relpath) and 'yes' or 'no'
67
        return request.SmartServerResponse((r,))
68
69
70
class GetRequest(VfsRequest):
71
72
    def do(self, relpath):
73
        backing_bytes = self._backing_transport.get_bytes(relpath)
74
        return request.SmartServerResponse(('ok',), backing_bytes)
75
76
77
class AppendRequest(VfsRequest):
78
79
    def do(self, relpath, mode):
80
        self._relpath = relpath
81
        self._mode = _deserialise_optional_mode(mode)
82
    
83
    def do_body(self, body_bytes):
84
        old_length = self._backing_transport.append_bytes(
85
            self._relpath, body_bytes, self._mode)
86
        return request.SmartServerResponse(('appended', '%d' % old_length))
87
88
89
class DeleteRequest(VfsRequest):
90
91
    def do(self, relpath):
92
        self._backing_transport.delete(relpath)
93
        return request.SmartServerResponse(('ok', ))
94
95
96
class IterFilesRecursiveRequest(VfsRequest):
97
98
    def do(self, relpath):
99
        transport = self._backing_transport.clone(relpath)
100
        filenames = transport.iter_files_recursive()
101
        return request.SmartServerResponse(('names',) + tuple(filenames))
102
103
104
class ListDirRequest(VfsRequest):
105
106
    def do(self, relpath):
107
        filenames = self._backing_transport.list_dir(relpath)
108
        return request.SmartServerResponse(('names',) + tuple(filenames))
109
110
111
class MkdirRequest(VfsRequest):
112
113
    def do(self, relpath, mode):
114
        self._backing_transport.mkdir(relpath,
115
                                      _deserialise_optional_mode(mode))
116
        return request.SmartServerResponse(('ok',))
117
118
119
class MoveRequest(VfsRequest):
120
121
    def do(self, rel_from, rel_to):
122
        self._backing_transport.move(rel_from, rel_to)
123
        return request.SmartServerResponse(('ok',))
124
125
126
class PutRequest(VfsRequest):
127
128
    def do(self, relpath, mode):
129
        self._relpath = relpath
130
        self._mode = _deserialise_optional_mode(mode)
131
132
    def do_body(self, body_bytes):
133
        self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
134
        return request.SmartServerResponse(('ok',))
135
136
137
class PutNonAtomicRequest(VfsRequest):
138
139
    def do(self, relpath, mode, create_parent, dir_mode):
140
        self._relpath = relpath
141
        self._dir_mode = _deserialise_optional_mode(dir_mode)
142
        self._mode = _deserialise_optional_mode(mode)
143
        # a boolean would be nicer XXX
144
        self._create_parent = (create_parent == 'T')
145
146
    def do_body(self, body_bytes):
147
        self._backing_transport.put_bytes_non_atomic(self._relpath,
148
                body_bytes,
149
                mode=self._mode,
150
                create_parent_dir=self._create_parent,
151
                dir_mode=self._dir_mode)
152
        return request.SmartServerResponse(('ok',))
153
154
155
class ReadvRequest(VfsRequest):
156
157
    def do(self, relpath):
158
        self._relpath = relpath
159
160
    def do_body(self, body_bytes):
161
        """accept offsets for a readv request."""
162
        offsets = self._deserialise_offsets(body_bytes)
163
        backing_bytes = ''.join(bytes for offset, bytes in
164
            self._backing_transport.readv(self._relpath, offsets))
165
        return request.SmartServerResponse(('readv',), backing_bytes)
166
167
    def _deserialise_offsets(self, text):
168
        # XXX: FIXME this should be on the protocol object.
169
        offsets = []
170
        for line in text.split('\n'):
171
            if not line:
172
                continue
173
            start, length = line.split(',')
174
            offsets.append((int(start), int(length)))
175
        return offsets
176
177
178
class RenameRequest(VfsRequest):
179
180
    def do(self, rel_from, rel_to):
181
        self._backing_transport.rename(rel_from, rel_to)
182
        return request.SmartServerResponse(('ok', ))
183
184
185
class RmdirRequest(VfsRequest):
186
187
    def do(self, relpath):
188
        self._backing_transport.rmdir(relpath)
189
        return request.SmartServerResponse(('ok', ))
190
191
192
class StatRequest(VfsRequest):
193
194
    def do(self, relpath):
195
        stat = self._backing_transport.stat(relpath)
196
        return request.SmartServerResponse(
197
            ('stat', str(stat.st_size), oct(stat.st_mode)))
198