1
# Copyright (C) 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""VFS operations for the smart server.
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.
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.
27
from bzrlib.smart import request
30
# vfs_commands is the set of commands handlers for the version 1 protocol.
31
vfs_commands = request.version_one_commands.copy()
33
def register_command(command):
34
vfs_commands[command.method] = command
37
def _deserialise_optional_mode(mode):
38
# XXX: FIXME this should be on the protocol object. Later protocol versions
39
# might serialise modes differently.
46
class HasRequest(request.SmartServerRequest):
50
def do(self, relpath):
51
r = self._backing_transport.has(relpath) and 'yes' or 'no'
52
return request.SmartServerResponse((r,))
53
register_command(HasRequest)
56
class GetRequest(request.SmartServerRequest):
60
def do(self, relpath):
61
backing_bytes = self._backing_transport.get_bytes(relpath)
62
return request.SmartServerResponse(('ok',), backing_bytes)
63
register_command(GetRequest)
66
class AppendRequest(request.SmartServerRequest):
70
def do(self, relpath, mode):
71
self._relpath = relpath
72
self._mode = _deserialise_optional_mode(mode)
74
def do_body(self, body_bytes):
75
old_length = self._backing_transport.append_bytes(
76
self._relpath, body_bytes, self._mode)
77
return request.SmartServerResponse(('appended', '%d' % old_length))
79
register_command(AppendRequest)
82
class DeleteRequest(request.SmartServerRequest):
86
def do(self, relpath):
87
self._backing_transport.delete(relpath)
88
return request.SmartServerResponse(('ok', ))
89
register_command(DeleteRequest)
92
class IterFilesRecursive(request.SmartServerRequest):
94
method = 'iter_files_recursive'
96
def do(self, relpath):
97
transport = self._backing_transport.clone(relpath)
98
filenames = transport.iter_files_recursive()
99
return request.SmartServerResponse(('names',) + tuple(filenames))
100
register_command(IterFilesRecursive)
103
class ListDirRequest(request.SmartServerRequest):
107
def do(self, relpath):
108
filenames = self._backing_transport.list_dir(relpath)
109
return request.SmartServerResponse(('names',) + tuple(filenames))
110
register_command(ListDirRequest)
113
class MkdirCommand(request.SmartServerRequest):
117
def do(self, relpath, mode):
118
self._backing_transport.mkdir(relpath,
119
_deserialise_optional_mode(mode))
120
return request.SmartServerResponse(('ok',))
121
register_command(MkdirCommand)
124
class MoveCommand(request.SmartServerRequest):
128
def do(self, rel_from, rel_to):
129
self._backing_transport.move(rel_from, rel_to)
130
return request.SmartServerResponse(('ok',))
131
register_command(MoveCommand)
134
class PutCommand(request.SmartServerRequest):
138
def do(self, relpath, mode):
139
self._relpath = relpath
140
self._mode = _deserialise_optional_mode(mode)
142
def do_body(self, body_bytes):
143
self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
144
return request.SmartServerResponse(('ok',))
145
register_command(PutCommand)
148
class PutNonAtomicCommand(request.SmartServerRequest):
150
method = 'put_non_atomic'
152
def do(self, relpath, mode, create_parent, dir_mode):
153
self._relpath = relpath
154
self._dir_mode = _deserialise_optional_mode(dir_mode)
155
self._mode = _deserialise_optional_mode(mode)
156
# a boolean would be nicer XXX
157
self._create_parent = (create_parent == 'T')
159
def do_body(self, body_bytes):
160
self._backing_transport.put_bytes_non_atomic(self._relpath,
163
create_parent_dir=self._create_parent,
164
dir_mode=self._dir_mode)
165
return request.SmartServerResponse(('ok',))
166
register_command(PutNonAtomicCommand)
169
class ReadvCommand(request.SmartServerRequest):
173
def do(self, relpath):
174
self._relpath = relpath
176
def do_body(self, body_bytes):
177
"""accept offsets for a readv request."""
178
offsets = self._deserialise_offsets(body_bytes)
179
backing_bytes = ''.join(bytes for offset, bytes in
180
self._backing_transport.readv(self._relpath, offsets))
181
return request.SmartServerResponse(('readv',), backing_bytes)
183
def _deserialise_offsets(self, text):
184
# XXX: FIXME this should be on the protocol object.
186
for line in text.split('\n'):
189
start, length = line.split(',')
190
offsets.append((int(start), int(length)))
192
register_command(ReadvCommand)
195
class RenameCommand(request.SmartServerRequest):
199
def do(self, rel_from, rel_to):
200
self._backing_transport.rename(rel_from, rel_to)
201
return request.SmartServerResponse(('ok', ))
202
register_command(RenameCommand)
205
class RmdirCommand(request.SmartServerRequest):
209
def do(self, relpath):
210
self._backing_transport.rmdir(relpath)
211
return request.SmartServerResponse(('ok', ))
212
register_command(RmdirCommand)
215
class StatCommand(request.SmartServerRequest):
219
def do(self, relpath):
220
stat = self._backing_transport.stat(relpath)
221
return request.SmartServerResponse(
222
('stat', str(stat.st_size), oct(stat.st_mode)))
223
register_command(StatCommand)