43
43
"""Is the VFS enabled ?
45
the VFS is disabled when the BRZ_NO_SMART_VFS environment variable is set.
45
the VFS is disabled when the BZR_NO_SMART_VFS environment variable is set.
47
:return: ``True`` if it is enabled.
47
:return: True if it is enabled.
49
return 'BRZ_NO_SMART_VFS' not in os.environ
49
return not 'BZR_NO_SMART_VFS' in os.environ
52
52
class VfsRequest(request.SmartServerRequest):
53
53
"""Base class for VFS requests.
55
55
VFS requests are disabled if vfs_enabled() returns False.
58
58
def _check_enabled(self):
59
59
if not vfs_enabled():
60
raise request.DisabledMethod(self.__class__.__name__)
62
def translate_client_path(self, relpath):
63
# VFS requests are made with escaped paths so the escaping done in
64
# SmartServerRequest.translate_client_path leads to double escaping.
65
# Remove it here -- the fact that the result is still escaped means
66
# that the str() will not fail on valid input.
67
x = request.SmartServerRequest.translate_client_path(self, relpath)
68
return str(urlutils.unescape(x))
60
raise errors.DisabledMethod(self.__class__.__name__)
71
63
class HasRequest(VfsRequest):
73
65
def do(self, relpath):
74
relpath = self.translate_client_path(relpath)
75
r = self._backing_transport.has(relpath) and b'yes' or b'no'
76
return request.SuccessfulSmartServerResponse((r,))
66
r = self._backing_transport.has(relpath) and 'yes' or 'no'
67
return request.SmartServerResponse((r,))
79
70
class GetRequest(VfsRequest):
81
72
def do(self, relpath):
82
relpath = self.translate_client_path(relpath)
83
73
backing_bytes = self._backing_transport.get_bytes(relpath)
84
return request.SuccessfulSmartServerResponse((b'ok',), backing_bytes)
74
return request.SmartServerResponse(('ok',), backing_bytes)
87
77
class AppendRequest(VfsRequest):
89
79
def do(self, relpath, mode):
90
relpath = self.translate_client_path(relpath)
91
80
self._relpath = relpath
92
81
self._mode = _deserialise_optional_mode(mode)
94
83
def do_body(self, body_bytes):
95
84
old_length = self._backing_transport.append_bytes(
96
85
self._relpath, body_bytes, self._mode)
97
return request.SuccessfulSmartServerResponse((b'appended', str(old_length).encode('ascii')))
86
return request.SmartServerResponse(('appended', '%d' % old_length))
100
89
class DeleteRequest(VfsRequest):
102
91
def do(self, relpath):
103
relpath = self.translate_client_path(relpath)
104
92
self._backing_transport.delete(relpath)
105
return request.SuccessfulSmartServerResponse((b'ok', ))
93
return request.SmartServerResponse(('ok', ))
108
96
class IterFilesRecursiveRequest(VfsRequest):
110
98
def do(self, relpath):
111
if not relpath.endswith(b'/'):
113
relpath = self.translate_client_path(relpath)
114
99
transport = self._backing_transport.clone(relpath)
115
100
filenames = transport.iter_files_recursive()
116
return request.SuccessfulSmartServerResponse((b'names',) + tuple(filenames))
101
return request.SmartServerResponse(('names',) + tuple(filenames))
119
104
class ListDirRequest(VfsRequest):
121
106
def do(self, relpath):
122
if not relpath.endswith(b'/'):
124
relpath = self.translate_client_path(relpath)
125
107
filenames = self._backing_transport.list_dir(relpath)
126
return request.SuccessfulSmartServerResponse((b'names',) + tuple([filename.encode('utf-8') for filename in filenames]))
108
return request.SmartServerResponse(('names',) + tuple(filenames))
129
111
class MkdirRequest(VfsRequest):
131
113
def do(self, relpath, mode):
132
relpath = self.translate_client_path(relpath)
133
114
self._backing_transport.mkdir(relpath,
134
115
_deserialise_optional_mode(mode))
135
return request.SuccessfulSmartServerResponse((b'ok',))
116
return request.SmartServerResponse(('ok',))
138
119
class MoveRequest(VfsRequest):
140
121
def do(self, rel_from, rel_to):
141
rel_from = self.translate_client_path(rel_from)
142
rel_to = self.translate_client_path(rel_to)
143
122
self._backing_transport.move(rel_from, rel_to)
144
return request.SuccessfulSmartServerResponse((b'ok',))
123
return request.SmartServerResponse(('ok',))
147
126
class PutRequest(VfsRequest):
149
128
def do(self, relpath, mode):
150
relpath = self.translate_client_path(relpath)
151
129
self._relpath = relpath
152
130
self._mode = _deserialise_optional_mode(mode)
154
132
def do_body(self, body_bytes):
155
self._backing_transport.put_bytes(
156
self._relpath, body_bytes, self._mode)
157
return request.SuccessfulSmartServerResponse((b'ok',))
133
self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
134
return request.SmartServerResponse(('ok',))
160
137
class PutNonAtomicRequest(VfsRequest):
162
139
def do(self, relpath, mode, create_parent, dir_mode):
163
relpath = self.translate_client_path(relpath)
164
140
self._relpath = relpath
165
141
self._dir_mode = _deserialise_optional_mode(dir_mode)
166
142
self._mode = _deserialise_optional_mode(mode)
167
143
# a boolean would be nicer XXX
168
self._create_parent = (create_parent == b'T')
144
self._create_parent = (create_parent == 'T')
170
146
def do_body(self, body_bytes):
171
147
self._backing_transport.put_bytes_non_atomic(self._relpath,
174
create_parent_dir=self._create_parent,
175
dir_mode=self._dir_mode)
176
return request.SuccessfulSmartServerResponse((b'ok',))
150
create_parent_dir=self._create_parent,
151
dir_mode=self._dir_mode)
152
return request.SmartServerResponse(('ok',))
179
155
class ReadvRequest(VfsRequest):
181
157
def do(self, relpath):
182
relpath = self.translate_client_path(relpath)
183
158
self._relpath = relpath
185
160
def do_body(self, body_bytes):
186
161
"""accept offsets for a readv request."""
187
162
offsets = self._deserialise_offsets(body_bytes)
188
backing_bytes = b''.join(bytes for offset, bytes in
189
self._backing_transport.readv(self._relpath, offsets))
190
return request.SuccessfulSmartServerResponse((b'readv',), backing_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)
192
167
def _deserialise_offsets(self, text):
193
168
# XXX: FIXME this should be on the protocol object.
195
for line in text.split(b'\n'):
170
for line in text.split('\n'):
198
start, length = line.split(b',')
173
start, length = line.split(',')
199
174
offsets.append((int(start), int(length)))