~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/vfs.py

  • Committer: Vincent Ladeuil
  • Date: 2010-02-03 07:18:36 UTC
  • mto: (5008.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5009.
  • Revision ID: v.ladeuil+lp@free.fr-20100203071836-u9b86q68fr9ri5s6
Fix NEWS.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
 
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 import urlutils
 
31
from bzrlib.smart import request
 
32
 
 
33
 
 
34
def _deserialise_optional_mode(mode):
 
35
    # XXX: FIXME this should be on the protocol object.  Later protocol versions
 
36
    # might serialise modes differently.
 
37
    if mode == '':
 
38
        return None
 
39
    else:
 
40
        return int(mode)
 
41
 
 
42
 
 
43
def vfs_enabled():
 
44
    """Is the VFS enabled ?
 
45
 
 
46
    the VFS is disabled when the BZR_NO_SMART_VFS environment variable is set.
 
47
 
 
48
    :return: True if it is enabled.
 
49
    """
 
50
    return not 'BZR_NO_SMART_VFS' in os.environ
 
51
 
 
52
 
 
53
class VfsRequest(request.SmartServerRequest):
 
54
    """Base class for VFS requests.
 
55
 
 
56
    VFS requests are disabled if vfs_enabled() returns False.
 
57
    """
 
58
 
 
59
    def _check_enabled(self):
 
60
        if not vfs_enabled():
 
61
            raise errors.DisabledMethod(self.__class__.__name__)
 
62
 
 
63
    def translate_client_path(self, relpath):
 
64
        # VFS requests are made with escaped paths so the escaping done in
 
65
        # SmartServerRequest.translate_client_path leads to double escaping.
 
66
        # Remove it here -- the fact that the result is still escaped means
 
67
        # that the str() will not fail on valid input.
 
68
        x = request.SmartServerRequest.translate_client_path(self, relpath)
 
69
        return str(urlutils.unescape(x))
 
70
 
 
71
 
 
72
class HasRequest(VfsRequest):
 
73
 
 
74
    def do(self, relpath):
 
75
        relpath = self.translate_client_path(relpath)
 
76
        r = self._backing_transport.has(relpath) and 'yes' or 'no'
 
77
        return request.SuccessfulSmartServerResponse((r,))
 
78
 
 
79
 
 
80
class GetRequest(VfsRequest):
 
81
 
 
82
    def do(self, relpath):
 
83
        relpath = self.translate_client_path(relpath)
 
84
        backing_bytes = self._backing_transport.get_bytes(relpath)
 
85
        return request.SuccessfulSmartServerResponse(('ok',), backing_bytes)
 
86
 
 
87
 
 
88
class AppendRequest(VfsRequest):
 
89
 
 
90
    def do(self, relpath, mode):
 
91
        relpath = self.translate_client_path(relpath)
 
92
        self._relpath = relpath
 
93
        self._mode = _deserialise_optional_mode(mode)
 
94
 
 
95
    def do_body(self, body_bytes):
 
96
        old_length = self._backing_transport.append_bytes(
 
97
            self._relpath, body_bytes, self._mode)
 
98
        return request.SuccessfulSmartServerResponse(('appended', '%d' % old_length))
 
99
 
 
100
 
 
101
class DeleteRequest(VfsRequest):
 
102
 
 
103
    def do(self, relpath):
 
104
        relpath = self.translate_client_path(relpath)
 
105
        self._backing_transport.delete(relpath)
 
106
        return request.SuccessfulSmartServerResponse(('ok', ))
 
107
 
 
108
 
 
109
class IterFilesRecursiveRequest(VfsRequest):
 
110
 
 
111
    def do(self, relpath):
 
112
        if not relpath.endswith('/'):
 
113
            relpath += '/'
 
114
        relpath = self.translate_client_path(relpath)
 
115
        transport = self._backing_transport.clone(relpath)
 
116
        filenames = transport.iter_files_recursive()
 
117
        return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
 
118
 
 
119
 
 
120
class ListDirRequest(VfsRequest):
 
121
 
 
122
    def do(self, relpath):
 
123
        if not relpath.endswith('/'):
 
124
            relpath += '/'
 
125
        relpath = self.translate_client_path(relpath)
 
126
        filenames = self._backing_transport.list_dir(relpath)
 
127
        return request.SuccessfulSmartServerResponse(('names',) + tuple(filenames))
 
128
 
 
129
 
 
130
class MkdirRequest(VfsRequest):
 
131
 
 
132
    def do(self, relpath, mode):
 
133
        relpath = self.translate_client_path(relpath)
 
134
        self._backing_transport.mkdir(relpath,
 
135
                                      _deserialise_optional_mode(mode))
 
136
        return request.SuccessfulSmartServerResponse(('ok',))
 
137
 
 
138
 
 
139
class MoveRequest(VfsRequest):
 
140
 
 
141
    def do(self, rel_from, rel_to):
 
142
        rel_from = self.translate_client_path(rel_from)
 
143
        rel_to = self.translate_client_path(rel_to)
 
144
        self._backing_transport.move(rel_from, rel_to)
 
145
        return request.SuccessfulSmartServerResponse(('ok',))
 
146
 
 
147
 
 
148
class PutRequest(VfsRequest):
 
149
 
 
150
    def do(self, relpath, mode):
 
151
        relpath = self.translate_client_path(relpath)
 
152
        self._relpath = relpath
 
153
        self._mode = _deserialise_optional_mode(mode)
 
154
 
 
155
    def do_body(self, body_bytes):
 
156
        self._backing_transport.put_bytes(self._relpath, body_bytes, self._mode)
 
157
        return request.SuccessfulSmartServerResponse(('ok',))
 
158
 
 
159
 
 
160
class PutNonAtomicRequest(VfsRequest):
 
161
 
 
162
    def do(self, relpath, mode, create_parent, dir_mode):
 
163
        relpath = self.translate_client_path(relpath)
 
164
        self._relpath = relpath
 
165
        self._dir_mode = _deserialise_optional_mode(dir_mode)
 
166
        self._mode = _deserialise_optional_mode(mode)
 
167
        # a boolean would be nicer XXX
 
168
        self._create_parent = (create_parent == 'T')
 
169
 
 
170
    def do_body(self, body_bytes):
 
171
        self._backing_transport.put_bytes_non_atomic(self._relpath,
 
172
                body_bytes,
 
173
                mode=self._mode,
 
174
                create_parent_dir=self._create_parent,
 
175
                dir_mode=self._dir_mode)
 
176
        return request.SuccessfulSmartServerResponse(('ok',))
 
177
 
 
178
 
 
179
class ReadvRequest(VfsRequest):
 
180
 
 
181
    def do(self, relpath):
 
182
        relpath = self.translate_client_path(relpath)
 
183
        self._relpath = relpath
 
184
 
 
185
    def do_body(self, body_bytes):
 
186
        """accept offsets for a readv request."""
 
187
        offsets = self._deserialise_offsets(body_bytes)
 
188
        backing_bytes = ''.join(bytes for offset, bytes in
 
189
            self._backing_transport.readv(self._relpath, offsets))
 
190
        return request.SuccessfulSmartServerResponse(('readv',), backing_bytes)
 
191
 
 
192
    def _deserialise_offsets(self, text):
 
193
        # XXX: FIXME this should be on the protocol object.
 
194
        offsets = []
 
195
        for line in text.split('\n'):
 
196
            if not line:
 
197
                continue
 
198
            start, length = line.split(',')
 
199
            offsets.append((int(start), int(length)))
 
200
        return offsets
 
201
 
 
202
 
 
203
class RenameRequest(VfsRequest):
 
204
 
 
205
    def do(self, rel_from, rel_to):
 
206
        rel_from = self.translate_client_path(rel_from)
 
207
        rel_to = self.translate_client_path(rel_to)
 
208
        self._backing_transport.rename(rel_from, rel_to)
 
209
        return request.SuccessfulSmartServerResponse(('ok', ))
 
210
 
 
211
 
 
212
class RmdirRequest(VfsRequest):
 
213
 
 
214
    def do(self, relpath):
 
215
        relpath = self.translate_client_path(relpath)
 
216
        self._backing_transport.rmdir(relpath)
 
217
        return request.SuccessfulSmartServerResponse(('ok', ))
 
218
 
 
219
 
 
220
class StatRequest(VfsRequest):
 
221
 
 
222
    def do(self, relpath):
 
223
        if not relpath.endswith('/'):
 
224
            relpath += '/'
 
225
        relpath = self.translate_client_path(relpath)
 
226
        stat = self._backing_transport.stat(relpath)
 
227
        return request.SuccessfulSmartServerResponse(
 
228
            ('stat', str(stat.st_size), oct(stat.st_mode)))
 
229