/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/memory.py

  • Committer: Robert Collins
  • Date: 2010-05-11 08:44:59 UTC
  • mfrom: (5221 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100511084459-pb0uinna9zs3wu59
Merge trunk - resolve conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-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
    transport,
 
32
    urlutils,
 
33
    )
 
34
from bzrlib.errors import (
 
35
    FileExists,
 
36
    LockError,
 
37
    InProcessTransport,
 
38
    NoSuchFile,
 
39
    TransportError,
 
40
    )
32
41
from bzrlib.trace import mutter
33
 
from bzrlib.transport import (Transport, register_transport, Server)
34
 
import bzrlib.urlutils as urlutils
 
42
from bzrlib.transport import (
 
43
    AppendBasedFileStream,
 
44
    _file_streams,
 
45
    LateReadError,
 
46
    )
35
47
 
36
48
 
37
49
 
49
61
            self.st_mode = S_IFDIR | perms
50
62
 
51
63
 
52
 
class MemoryTransport(Transport):
 
64
class MemoryTransport(transport.Transport):
53
65
    """This is an in memory file system for transient data storage."""
54
66
 
55
67
    def __init__(self, url=""):
59
71
        if url[-1] != '/':
60
72
            url = url + '/'
61
73
        super(MemoryTransport, self).__init__(url)
62
 
        self._cwd = url[url.find(':') + 3:]
 
74
        split = url.find(':') + 3
 
75
        self._scheme = url[:split]
 
76
        self._cwd = url[split:]
63
77
        # dictionaries from absolute path to file mode
64
78
        self._dirs = {'/':None}
65
79
        self._files = {}
67
81
 
68
82
    def clone(self, offset=None):
69
83
        """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)
 
84
        path = self._combine_paths(self._cwd, offset)
 
85
        if len(path) == 0 or path[-1] != '/':
 
86
            path += '/'
 
87
        url = self._scheme + path
 
88
        result = self.__class__(url)
85
89
        result._dirs = self._dirs
86
90
        result._files = self._files
87
91
        result._locks = self._locks
126
130
            raise NoSuchFile(relpath)
127
131
        del self._files[_abspath]
128
132
 
 
133
    def external_url(self):
 
134
        """See bzrlib.transport.Transport.external_url."""
 
135
        # MemoryTransport's are only accessible in-process
 
136
        # so we raise here
 
137
        raise InProcessTransport(self)
 
138
 
129
139
    def get(self, relpath):
130
140
        """See Transport.get()."""
131
141
        _abspath = self._abspath(relpath)
132
142
        if not _abspath in self._files:
133
 
            raise NoSuchFile(relpath)
 
143
            if _abspath in self._dirs:
 
144
                return LateReadError(relpath)
 
145
            else:
 
146
                raise NoSuchFile(relpath)
134
147
        return StringIO(self._files[_abspath][0])
135
148
 
136
149
    def put_file(self, relpath, f, mode=None):
137
150
        """See Transport.put_file()."""
138
151
        _abspath = self._abspath(relpath)
139
152
        self._check_parent(_abspath)
140
 
        self._files[_abspath] = (f.read(), mode)
 
153
        bytes = f.read()
 
154
        if type(bytes) is not str:
 
155
            # Although not strictly correct, we raise UnicodeEncodeError to be
 
156
            # compatible with other transports.
 
157
            raise UnicodeEncodeError(
 
158
                'undefined', bytes, 0, 1,
 
159
                'put_file must be given a file of bytes, not unicode.')
 
160
        self._files[_abspath] = (bytes, mode)
 
161
        return len(bytes)
141
162
 
142
163
    def mkdir(self, relpath, mode=None):
143
164
        """See Transport.mkdir()."""
147
168
            raise FileExists(relpath)
148
169
        self._dirs[_abspath]=mode
149
170
 
 
171
    def open_write_stream(self, relpath, mode=None):
 
172
        """See Transport.open_write_stream."""
 
173
        self.put_bytes(relpath, "", mode)
 
174
        result = AppendBasedFileStream(self, relpath)
 
175
        _file_streams[self.abspath(relpath)] = result
 
176
        return result
 
177
 
150
178
    def listable(self):
151
179
        """See Transport.listable."""
152
180
        return True
155
183
        for file in self._files:
156
184
            if file.startswith(self._cwd):
157
185
                yield urlutils.escape(file[len(self._cwd):])
158
 
    
 
186
 
159
187
    def list_dir(self, relpath):
160
188
        """See Transport.list_dir()."""
161
189
        _abspath = self._abspath(relpath)
162
190
        if _abspath != '/' and _abspath not in self._dirs:
163
191
            raise NoSuchFile(relpath)
164
192
        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:])
 
193
 
 
194
        if not _abspath.endswith('/'):
 
195
            _abspath += '/'
 
196
 
 
197
        for path_group in self._files, self._dirs:
 
198
            for path in path_group:
 
199
                if path.startswith(_abspath):
 
200
                    trailing = path[len(_abspath):]
 
201
                    if trailing and '/' not in trailing:
 
202
                        result.append(trailing)
176
203
        return map(urlutils.escape, result)
177
204
 
178
205
    def rename(self, rel_from, rel_to):
195
222
                    del container[path]
196
223
        do_renames(self._files)
197
224
        do_renames(self._dirs)
198
 
    
 
225
 
199
226
    def rmdir(self, relpath):
200
227
        """See Transport.rmdir."""
201
228
        _abspath = self._abspath(relpath)
202
229
        if _abspath in self._files:
203
230
            self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
204
231
        for path in self._files:
205
 
            if path.startswith(_abspath):
 
232
            if path.startswith(_abspath + '/'):
206
233
                self._translate_error(IOError(errno.ENOTEMPTY, relpath),
207
234
                                      relpath)
208
235
        for path in self._dirs:
209
 
            if path.startswith(_abspath) and path != _abspath:
 
236
            if path.startswith(_abspath + '/') and path != _abspath:
210
237
                self._translate_error(IOError(errno.ENOTEMPTY, relpath), relpath)
211
238
        if not _abspath in self._dirs:
212
239
            raise NoSuchFile(relpath)
216
243
        """See Transport.stat()."""
217
244
        _abspath = self._abspath(relpath)
218
245
        if _abspath in self._files:
219
 
            return MemoryStat(len(self._files[_abspath][0]), False, 
 
246
            return MemoryStat(len(self._files[_abspath][0]), False,
220
247
                              self._files[_abspath][1])
221
248
        elif _abspath in self._dirs:
222
249
            return MemoryStat(0, True, self._dirs[_abspath])
234
261
    def _abspath(self, relpath):
235
262
        """Generate an internal absolute path."""
236
263
        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
 
264
        if relpath[:1] == '/':
 
265
            return relpath
 
266
        cwd_parts = self._cwd.split('/')
 
267
        rel_parts = relpath.split('/')
 
268
        r = []
 
269
        for i in cwd_parts + rel_parts:
 
270
            if i == '..':
 
271
                if not r:
 
272
                    raise ValueError("illegal relpath %r under %r"
 
273
                        % (relpath, self._cwd))
 
274
                r = r[:-1]
 
275
            elif i == '.' or i == '':
 
276
                pass
 
277
            else:
 
278
                r.append(i)
 
279
        return '/' + '/'.join(r)
248
280
 
249
281
 
250
282
class _MemoryLock(object):
251
283
    """This makes a lock."""
252
284
 
253
285
    def __init__(self, path, transport):
254
 
        assert isinstance(transport, MemoryTransport)
255
286
        self.path = path
256
287
        self.transport = transport
257
288
        if self.path in self.transport._locks:
269
300
        self.transport = None
270
301
 
271
302
 
272
 
class MemoryServer(Server):
 
303
class MemoryServer(transport.Server):
273
304
    """Server for the MemoryTransport for testing with."""
274
305
 
275
 
    def setUp(self):
276
 
        """See bzrlib.transport.Server.setUp."""
 
306
    def start_server(self):
277
307
        self._dirs = {'/':None}
278
308
        self._files = {}
279
309
        self._locks = {}
280
310
        self._scheme = "memory+%s:///" % id(self)
281
311
        def memory_factory(url):
282
 
            result = MemoryTransport(url)
 
312
            from bzrlib.transport import memory
 
313
            result = memory.MemoryTransport(url)
283
314
            result._dirs = self._dirs
284
315
            result._files = self._files
285
316
            result._locks = self._locks
286
317
            return result
287
 
        register_transport(self._scheme, memory_factory)
 
318
        self._memory_factory = memory_factory
 
319
        transport.register_transport(self._scheme, self._memory_factory)
288
320
 
289
 
    def tearDown(self):
290
 
        """See bzrlib.transport.Server.tearDown."""
 
321
    def stop_server(self):
291
322
        # unregister this server
 
323
        transport.unregister_transport(self._scheme, self._memory_factory)
292
324
 
293
325
    def get_url(self):
294
326
        """See bzrlib.transport.Server.get_url."""
295
327
        return self._scheme
296
328
 
 
329
    def get_bogus_url(self):
 
330
        raise NotImplementedError
 
331
 
297
332
 
298
333
def get_test_permutations():
299
334
    """Return the permutations to be used in testing."""