~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/memory.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) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Implementation of Transport that uses memory for its storage.
18
18
 
20
20
so this is primarily useful for testing.
21
21
"""
22
22
 
23
 
from copy import copy
24
23
import os
25
24
import errno
26
25
import re
28
27
from cStringIO import StringIO
29
28
import warnings
30
29
 
31
 
from bzrlib.errors import TransportError, NoSuchFile, FileExists, LockError
 
30
from bzrlib import (
 
31
    urlutils,
 
32
    )
 
33
from bzrlib.errors import (
 
34
    FileExists,
 
35
    LockError,
 
36
    InProcessTransport,
 
37
    NoSuchFile,
 
38
    TransportError,
 
39
    )
32
40
from bzrlib.trace import mutter
33
 
from bzrlib.transport import (Transport, register_transport, Server)
34
 
import bzrlib.urlutils as urlutils
 
41
from bzrlib.transport import (
 
42
    AppendBasedFileStream,
 
43
    _file_streams,
 
44
    LateReadError,
 
45
    register_transport,
 
46
    Server,
 
47
    Transport,
 
48
    unregister_transport,
 
49
    )
35
50
 
36
51
 
37
52
 
59
74
        if url[-1] != '/':
60
75
            url = url + '/'
61
76
        super(MemoryTransport, self).__init__(url)
62
 
        self._cwd = url[url.find(':') + 3:]
 
77
        split = url.find(':') + 3
 
78
        self._scheme = url[:split]
 
79
        self._cwd = url[split:]
63
80
        # dictionaries from absolute path to file mode
64
81
        self._dirs = {'/':None}
65
82
        self._files = {}
67
84
 
68
85
    def clone(self, offset=None):
69
86
        """See Transport.clone()."""
70
 
        if offset is None or offset == '':
71
 
            return copy(self)
72
 
        segments = offset.split('/')
73
 
        cwdsegments = self._cwd.split('/')[:-1]
74
 
        while len(segments):
75
 
            segment = segments.pop(0)
76
 
            if segment == '.':
77
 
                continue
78
 
            if segment == '..':
79
 
                if len(cwdsegments) > 1:
80
 
                    cwdsegments.pop()
81
 
                continue
82
 
            cwdsegments.append(segment)
83
 
        url = self.base[:self.base.find(':') + 3] + '/'.join(cwdsegments) + '/'
84
 
        result = MemoryTransport(url)
 
87
        path = self._combine_paths(self._cwd, offset)
 
88
        if len(path) == 0 or path[-1] != '/':
 
89
            path += '/'
 
90
        url = self._scheme + path
 
91
        result = self.__class__(url)
85
92
        result._dirs = self._dirs
86
93
        result._files = self._files
87
94
        result._locks = self._locks
98
105
        else:
99
106
            return temp_t.base[:-1]
100
107
 
101
 
    def append(self, relpath, f, mode=None):
102
 
        """See Transport.append()."""
 
108
    def append_file(self, relpath, f, mode=None):
 
109
        """See Transport.append_file()."""
103
110
        _abspath = self._abspath(relpath)
104
111
        self._check_parent(_abspath)
105
112
        orig_content, orig_mode = self._files.get(_abspath, ("", None))
117
124
    def has(self, relpath):
118
125
        """See Transport.has()."""
119
126
        _abspath = self._abspath(relpath)
120
 
        return _abspath in self._files or _abspath in self._dirs
 
127
        return (_abspath in self._files) or (_abspath in self._dirs)
121
128
 
122
129
    def delete(self, relpath):
123
130
        """See Transport.delete()."""
126
133
            raise NoSuchFile(relpath)
127
134
        del self._files[_abspath]
128
135
 
 
136
    def external_url(self):
 
137
        """See bzrlib.transport.Transport.external_url."""
 
138
        # MemoryTransport's are only accessible in-process
 
139
        # so we raise here
 
140
        raise InProcessTransport(self)
 
141
 
129
142
    def get(self, relpath):
130
143
        """See Transport.get()."""
131
144
        _abspath = self._abspath(relpath)
132
145
        if not _abspath in self._files:
133
 
            raise NoSuchFile(relpath)
 
146
            if _abspath in self._dirs:
 
147
                return LateReadError(relpath)
 
148
            else:
 
149
                raise NoSuchFile(relpath)
134
150
        return StringIO(self._files[_abspath][0])
135
151
 
136
 
    def put(self, relpath, f, mode=None):
137
 
        """See Transport.put()."""
 
152
    def put_file(self, relpath, f, mode=None):
 
153
        """See Transport.put_file()."""
138
154
        _abspath = self._abspath(relpath)
139
155
        self._check_parent(_abspath)
140
 
        self._files[_abspath] = (f.read(), mode)
 
156
        bytes = f.read()
 
157
        if type(bytes) is not str:
 
158
            # Although not strictly correct, we raise UnicodeEncodeError to be
 
159
            # compatible with other transports.
 
160
            raise UnicodeEncodeError(
 
161
                'undefined', bytes, 0, 1,
 
162
                'put_file must be given a file of bytes, not unicode.')
 
163
        self._files[_abspath] = (bytes, mode)
 
164
        return len(bytes)
141
165
 
142
166
    def mkdir(self, relpath, mode=None):
143
167
        """See Transport.mkdir()."""
147
171
            raise FileExists(relpath)
148
172
        self._dirs[_abspath]=mode
149
173
 
 
174
    def open_write_stream(self, relpath, mode=None):
 
175
        """See Transport.open_write_stream."""
 
176
        self.put_bytes(relpath, "", mode)
 
177
        result = AppendBasedFileStream(self, relpath)
 
178
        _file_streams[self.abspath(relpath)] = result
 
179
        return result
 
180
 
150
181
    def listable(self):
151
182
        """See Transport.listable."""
152
183
        return True
154
185
    def iter_files_recursive(self):
155
186
        for file in self._files:
156
187
            if file.startswith(self._cwd):
157
 
                yield file[len(self._cwd):]
158
 
    
 
188
                yield urlutils.escape(file[len(self._cwd):])
 
189
 
159
190
    def list_dir(self, relpath):
160
191
        """See Transport.list_dir()."""
161
192
        _abspath = self._abspath(relpath)
162
193
        if _abspath != '/' and _abspath not in self._dirs:
163
194
            raise NoSuchFile(relpath)
164
195
        result = []
165
 
        for path in self._files:
166
 
            if (path.startswith(_abspath) and 
167
 
                path[len(_abspath) + 1:].find('/') == -1 and
168
 
                len(path) > len(_abspath)):
169
 
                result.append(path[len(_abspath) + 1:])
170
 
        for path in self._dirs:
171
 
            if (path.startswith(_abspath) and 
172
 
                path[len(_abspath) + 1:].find('/') == -1 and
173
 
                len(path) > len(_abspath) and
174
 
                path[len(_abspath)] == '/'):
175
 
                result.append(path[len(_abspath) + 1:])
176
 
        return result
 
196
 
 
197
        if not _abspath.endswith('/'):
 
198
            _abspath += '/'
 
199
 
 
200
        for path_group in self._files, self._dirs:
 
201
            for path in path_group:
 
202
                if path.startswith(_abspath):
 
203
                    trailing = path[len(_abspath):]
 
204
                    if trailing and '/' not in trailing:
 
205
                        result.append(trailing)
 
206
        return map(urlutils.escape, result)
177
207
 
178
208
    def rename(self, rel_from, rel_to):
179
209
        """Rename a file or directory; fail if the destination exists"""
195
225
                    del container[path]
196
226
        do_renames(self._files)
197
227
        do_renames(self._dirs)
198
 
    
 
228
 
199
229
    def rmdir(self, relpath):
200
230
        """See Transport.rmdir."""
201
231
        _abspath = self._abspath(relpath)
202
232
        if _abspath in self._files:
203
233
            self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
204
234
        for path in self._files:
205
 
            if path.startswith(_abspath):
 
235
            if path.startswith(_abspath + '/'):
206
236
                self._translate_error(IOError(errno.ENOTEMPTY, relpath),
207
237
                                      relpath)
208
238
        for path in self._dirs:
209
 
            if path.startswith(_abspath) and path != _abspath:
 
239
            if path.startswith(_abspath + '/') and path != _abspath:
210
240
                self._translate_error(IOError(errno.ENOTEMPTY, relpath), relpath)
211
241
        if not _abspath in self._dirs:
212
242
            raise NoSuchFile(relpath)
216
246
        """See Transport.stat()."""
217
247
        _abspath = self._abspath(relpath)
218
248
        if _abspath in self._files:
219
 
            return MemoryStat(len(self._files[_abspath][0]), False, 
 
249
            return MemoryStat(len(self._files[_abspath][0]), False,
220
250
                              self._files[_abspath][1])
221
251
        elif _abspath in self._dirs:
222
252
            return MemoryStat(0, True, self._dirs[_abspath])
234
264
    def _abspath(self, relpath):
235
265
        """Generate an internal absolute path."""
236
266
        relpath = urlutils.unescape(relpath)
237
 
        if relpath.find('..') != -1:
238
 
            raise AssertionError('relpath contains ..')
239
 
        if relpath == '.':
240
 
            if (self._cwd == '/'):
241
 
                return self._cwd
242
 
            return self._cwd[:-1]
243
 
        if relpath.endswith('/'):
244
 
            relpath = relpath[:-1]
245
 
        if relpath.startswith('./'):
246
 
            relpath = relpath[2:]
247
 
        return self._cwd + relpath
 
267
        if relpath[:1] == '/':
 
268
            return relpath
 
269
        cwd_parts = self._cwd.split('/')
 
270
        rel_parts = relpath.split('/')
 
271
        r = []
 
272
        for i in cwd_parts + rel_parts:
 
273
            if i == '..':
 
274
                if not r:
 
275
                    raise ValueError("illegal relpath %r under %r"
 
276
                        % (relpath, self._cwd))
 
277
                r = r[:-1]
 
278
            elif i == '.' or i == '':
 
279
                pass
 
280
            else:
 
281
                r.append(i)
 
282
        return '/' + '/'.join(r)
248
283
 
249
284
 
250
285
class _MemoryLock(object):
251
286
    """This makes a lock."""
252
287
 
253
288
    def __init__(self, path, transport):
254
 
        assert isinstance(transport, MemoryTransport)
255
289
        self.path = path
256
290
        self.transport = transport
257
291
        if self.path in self.transport._locks:
272
306
class MemoryServer(Server):
273
307
    """Server for the MemoryTransport for testing with."""
274
308
 
275
 
    def setUp(self):
276
 
        """See bzrlib.transport.Server.setUp."""
 
309
    def start_server(self):
277
310
        self._dirs = {'/':None}
278
311
        self._files = {}
279
312
        self._locks = {}
284
317
            result._files = self._files
285
318
            result._locks = self._locks
286
319
            return result
287
 
        register_transport(self._scheme, memory_factory)
 
320
        self._memory_factory = memory_factory
 
321
        register_transport(self._scheme, self._memory_factory)
288
322
 
289
 
    def tearDown(self):
290
 
        """See bzrlib.transport.Server.tearDown."""
 
323
    def stop_server(self):
291
324
        # unregister this server
 
325
        unregister_transport(self._scheme, self._memory_factory)
292
326
 
293
327
    def get_url(self):
294
328
        """See bzrlib.transport.Server.get_url."""