1
# Copyright (C) 2006, 2007 Canonical Ltd
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""VFS operations for the smart server.
19
This module defines the smart server methods that are low-level file operations
20
higher-level concepts like branches and revisions.
22
These methods, plus 'hello' and 'get_bundle', are version 1 of the smart server
23
protocol, as implemented in bzr 0.11 and later.
28
from bzrlib import errors
29
from bzrlib.smart import request
32
def _deserialise_optional_mode(mode):
33
# XXX: FIXME this should be on the protocol object. Later protocol versions
34
# might serialise modes differently.
42
"""Is the VFS enabled ?
44
the VFS is disabled when the BZR_NO_SMART_VFS environment variable is set.
46
:return: True if it is enabled.
48
return not 'BZR_NO_SMART_VFS' in os.environ
51
class VfsRequest(request.SmartServerRequest):
52
"""Base class for VFS requests.
54
VFS requests are disabled if vfs_enabled() returns False.
57
def _check_enabled(self):
59
raise errors.DisabledMethod(self.__class__.__name__)
62
class HasRequest(VfsRequest):
64
def do(self, relpath):
65
relpath = self.translate_client_path(relpath)
66
r = self._backing_transport.has(relpath) and 'yes' or 'no'
67
return request.SuccessfulSmartServerResponse((r,))
70
class GetRequest(VfsRequest):
72
def do(self, relpath):
73
relpath = self.translate_client_path(relpath)
74
backing_bytes = self._backing_transport.get_bytes(relpath)
75
return request.SuccessfulSmartServerResponse(('ok',), backing_bytes)
78
class AppendRequest(VfsRequest):
80
def do(self, relpath, mode):
81
relpath = self.translate_client_path(relpath)
82
self._relpath = relpath
83
self._mode = _deserialise_optional_mode(mode)
85
def do_body(self, body_bytes):
86
old_length = self._backing_transport.append_bytes(
87
self._relpath, body_bytes, self._mode)
88
return request.SuccessfulSmartServerResponse(('appended', '%d' % old_length))
91
class DeleteRequest(VfsRequest):
93
def do(self, relpath):
94
relpath = self.translate_client_path(relpath)
95
self._backing_transport.delete(relpath)
96
return request.SuccessfulSmartServerResponse(('ok', ))
99
class IterFilesRecursiveRequest(VfsRequest):
101
def do(self, relpath):
102
if not relpath.endswith('/'):
104
relpath = self.translate_client_path(relpath)
105
transport = self._backing_transport.clone(relpath)
106
filenames = transport.iter_files_recursive()
107
return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
110
class ListDirRequest(VfsRequest):
112
def do(self, relpath):
113
if not relpath.endswith('/'):
115
relpath = self.translate_client_path(relpath)
116
filenames = self._backing_transport.list_dir(relpath)
117
return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
120
class MkdirRequest(VfsRequest):
122
def do(self, relpath, mode):
123
relpath = self.translate_client_path(relpath)
124
self._backing_transport.mkdir(relpath,
125
_deserialise_optional_mode(mode))
126
return request.SuccessfulSmartServerResponse(('ok',))
129
class MoveRequest(VfsRequest):
131
def do(self, rel_from, rel_to):
132
rel_from = self.translate_client_path(rel_from)
133
rel_to = self.translate_client_path(rel_to)
134
self._backing_transport.move(rel_from, rel_to)
135
return request.SuccessfulSmartServerResponse(('ok',))
138
class PutRequest(VfsRequest):
140
def do(self, relpath, mode):
141
relpath = self.translate_client_path(relpath)
142
self._relpath = relpath
143
self._mode = _deserialise_optional_mode(mode)
145
def do_body(self, body_bytes):
146
self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
147
return request.SuccessfulSmartServerResponse(('ok',))
150
class PutNonAtomicRequest(VfsRequest):
152
def do(self, relpath, mode, create_parent, dir_mode):
153
relpath = self.translate_client_path(relpath)
154
self._relpath = relpath
155
self._dir_mode = _deserialise_optional_mode(dir_mode)
156
self._mode = _deserialise_optional_mode(mode)
157
# a boolean would be nicer XXX
158
self._create_parent = (create_parent == 'T')
160
def do_body(self, body_bytes):
161
self._backing_transport.put_bytes_non_atomic(self._relpath,
164
create_parent_dir=self._create_parent,
165
dir_mode=self._dir_mode)
166
return request.SuccessfulSmartServerResponse(('ok',))
169
class ReadvRequest(VfsRequest):
171
def do(self, relpath):
172
relpath = self.translate_client_path(relpath)
173
self._relpath = relpath
175
def do_body(self, body_bytes):
176
"""accept offsets for a readv request."""
177
offsets = self._deserialise_offsets(body_bytes)
178
backing_bytes = ''.join(bytes for offset, bytes in
179
self._backing_transport.readv(self._relpath, offsets))
180
return request.SuccessfulSmartServerResponse(('readv',), backing_bytes)
182
def _deserialise_offsets(self, text):
183
# XXX: FIXME this should be on the protocol object.
185
for line in text.split('\n'):
188
start, length = line.split(',')
189
offsets.append((int(start), int(length)))
193
class RenameRequest(VfsRequest):
195
def do(self, rel_from, rel_to):
196
rel_from = self.translate_client_path(rel_from)
197
rel_to = self.translate_client_path(rel_to)
198
self._backing_transport.rename(rel_from, rel_to)
199
return request.SuccessfulSmartServerResponse(('ok', ))
202
class RmdirRequest(VfsRequest):
204
def do(self, relpath):
205
relpath = self.translate_client_path(relpath)
206
self._backing_transport.rmdir(relpath)
207
return request.SuccessfulSmartServerResponse(('ok', ))
210
class StatRequest(VfsRequest):
212
def do(self, relpath):
213
if not relpath.endswith('/'):
215
relpath = self.translate_client_path(relpath)
216
stat = self._backing_transport.stat(relpath)
217
return request.SuccessfulSmartServerResponse(
218
('stat', str(stat.st_size), oct(stat.st_mode)))