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.
29
from bzrlib import errors
30
from bzrlib.smart import request
33
def _deserialise_optional_mode(mode):
34
# XXX: FIXME this should be on the protocol object. Later protocol versions
35
# might serialise modes differently.
42
class VfsRequest(request.SmartServerRequest):
43
"""Base class for VFS requests.
45
VFS requests are disabled if the NO_SMART_VFS environment variable is set.
48
def _check_enabled(self):
49
if 'NO_SMART_VFS' in os.environ:
50
raise errors.DisabledMethod(self.__class__.__name__)
53
class HasRequest(VfsRequest):
55
def do(self, relpath):
56
r = self._backing_transport.has(relpath) and 'yes' or 'no'
57
return request.SmartServerResponse((r,))
60
class GetRequest(VfsRequest):
62
def do(self, relpath):
63
backing_bytes = self._backing_transport.get_bytes(relpath)
64
return request.SmartServerResponse(('ok',), backing_bytes)
67
class AppendRequest(VfsRequest):
69
def do(self, relpath, mode):
70
self._relpath = relpath
71
self._mode = _deserialise_optional_mode(mode)
73
def do_body(self, body_bytes):
74
old_length = self._backing_transport.append_bytes(
75
self._relpath, body_bytes, self._mode)
76
return request.SmartServerResponse(('appended', '%d' % old_length))
79
class DeleteRequest(VfsRequest):
81
def do(self, relpath):
82
self._backing_transport.delete(relpath)
83
return request.SmartServerResponse(('ok', ))
86
class IterFilesRecursive(VfsRequest):
88
def do(self, relpath):
89
transport = self._backing_transport.clone(relpath)
90
filenames = transport.iter_files_recursive()
91
return request.SmartServerResponse(('names',) + tuple(filenames))
94
class ListDirRequest(VfsRequest):
96
def do(self, relpath):
97
filenames = self._backing_transport.list_dir(relpath)
98
return request.SmartServerResponse(('names',) + tuple(filenames))
101
class MkdirCommand(VfsRequest):
103
def do(self, relpath, mode):
104
self._backing_transport.mkdir(relpath,
105
_deserialise_optional_mode(mode))
106
return request.SmartServerResponse(('ok',))
109
class MoveCommand(VfsRequest):
111
def do(self, rel_from, rel_to):
112
self._backing_transport.move(rel_from, rel_to)
113
return request.SmartServerResponse(('ok',))
116
class PutCommand(VfsRequest):
118
def do(self, relpath, mode):
119
self._relpath = relpath
120
self._mode = _deserialise_optional_mode(mode)
122
def do_body(self, body_bytes):
123
self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
124
return request.SmartServerResponse(('ok',))
127
class PutNonAtomicCommand(VfsRequest):
129
def do(self, relpath, mode, create_parent, dir_mode):
130
self._relpath = relpath
131
self._dir_mode = _deserialise_optional_mode(dir_mode)
132
self._mode = _deserialise_optional_mode(mode)
133
# a boolean would be nicer XXX
134
self._create_parent = (create_parent == 'T')
136
def do_body(self, body_bytes):
137
self._backing_transport.put_bytes_non_atomic(self._relpath,
140
create_parent_dir=self._create_parent,
141
dir_mode=self._dir_mode)
142
return request.SmartServerResponse(('ok',))
145
class ReadvCommand(VfsRequest):
147
def do(self, relpath):
148
self._relpath = relpath
150
def do_body(self, body_bytes):
151
"""accept offsets for a readv request."""
152
offsets = self._deserialise_offsets(body_bytes)
153
backing_bytes = ''.join(bytes for offset, bytes in
154
self._backing_transport.readv(self._relpath, offsets))
155
return request.SmartServerResponse(('readv',), backing_bytes)
157
def _deserialise_offsets(self, text):
158
# XXX: FIXME this should be on the protocol object.
160
for line in text.split('\n'):
163
start, length = line.split(',')
164
offsets.append((int(start), int(length)))
168
class RenameCommand(VfsRequest):
170
def do(self, rel_from, rel_to):
171
self._backing_transport.rename(rel_from, rel_to)
172
return request.SmartServerResponse(('ok', ))
175
class RmdirCommand(VfsRequest):
177
def do(self, relpath):
178
self._backing_transport.rmdir(relpath)
179
return request.SmartServerResponse(('ok', ))
182
class StatCommand(VfsRequest):
184
def do(self, relpath):
185
stat = self._backing_transport.stat(relpath)
186
return request.SmartServerResponse(
187
('stat', str(stat.st_size), oct(stat.st_mode)))