~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/memory.py

  • Committer: John Arbash Meinel
  • Date: 2013-05-19 14:29:37 UTC
  • mfrom: (6437.63.9 2.5)
  • mto: (6437.63.10 2.5)
  • mto: This revision was merged to the branch mainline in revision 6575.
  • Revision ID: john@arbash-meinel.com-20130519142937-21ykz2n2y2f22za9
Merge in the actual 2.5 branch. It seems I failed before

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 __future__ import absolute_import
 
24
 
23
25
import os
24
26
import errno
25
 
import re
26
27
from stat import S_IFREG, S_IFDIR
27
28
from cStringIO import StringIO
28
 
import warnings
29
29
 
30
 
from bzrlib.errors import TransportError, NoSuchFile, FileExists, LockError
31
 
from bzrlib.trace import mutter
32
 
from bzrlib.transport import (Transport, register_transport, Server)
33
 
import bzrlib.urlutils as urlutils
 
30
from bzrlib import (
 
31
    transport,
 
32
    urlutils,
 
33
    )
 
34
from bzrlib.errors import (
 
35
    FileExists,
 
36
    LockError,
 
37
    InProcessTransport,
 
38
    NoSuchFile,
 
39
    )
 
40
from bzrlib.transport import (
 
41
    AppendBasedFileStream,
 
42
    _file_streams,
 
43
    LateReadError,
 
44
    )
34
45
 
35
46
 
36
47
 
48
59
            self.st_mode = S_IFDIR | perms
49
60
 
50
61
 
51
 
class MemoryTransport(Transport):
 
62
class MemoryTransport(transport.Transport):
52
63
    """This is an in memory file system for transient data storage."""
53
64
 
54
65
    def __init__(self, url=""):
68
79
 
69
80
    def clone(self, offset=None):
70
81
        """See Transport.clone()."""
71
 
        path = self._combine_paths(self._cwd, offset)
 
82
        path = urlutils.URL._combine_paths(self._cwd, offset)
72
83
        if len(path) == 0 or path[-1] != '/':
73
84
            path += '/'
74
85
        url = self._scheme + path
75
 
        result = MemoryTransport(url)
 
86
        result = self.__class__(url)
76
87
        result._dirs = self._dirs
77
88
        result._files = self._files
78
89
        result._locks = self._locks
117
128
            raise NoSuchFile(relpath)
118
129
        del self._files[_abspath]
119
130
 
 
131
    def external_url(self):
 
132
        """See bzrlib.transport.Transport.external_url."""
 
133
        # MemoryTransport's are only accessible in-process
 
134
        # so we raise here
 
135
        raise InProcessTransport(self)
 
136
 
120
137
    def get(self, relpath):
121
138
        """See Transport.get()."""
122
139
        _abspath = self._abspath(relpath)
123
140
        if not _abspath in self._files:
124
 
            raise NoSuchFile(relpath)
 
141
            if _abspath in self._dirs:
 
142
                return LateReadError(relpath)
 
143
            else:
 
144
                raise NoSuchFile(relpath)
125
145
        return StringIO(self._files[_abspath][0])
126
146
 
127
147
    def put_file(self, relpath, f, mode=None):
136
156
                'undefined', bytes, 0, 1,
137
157
                'put_file must be given a file of bytes, not unicode.')
138
158
        self._files[_abspath] = (bytes, mode)
 
159
        return len(bytes)
139
160
 
140
161
    def mkdir(self, relpath, mode=None):
141
162
        """See Transport.mkdir()."""
145
166
            raise FileExists(relpath)
146
167
        self._dirs[_abspath]=mode
147
168
 
 
169
    def open_write_stream(self, relpath, mode=None):
 
170
        """See Transport.open_write_stream."""
 
171
        self.put_bytes(relpath, "", mode)
 
172
        result = AppendBasedFileStream(self, relpath)
 
173
        _file_streams[self.abspath(relpath)] = result
 
174
        return result
 
175
 
148
176
    def listable(self):
149
177
        """See Transport.listable."""
150
178
        return True
153
181
        for file in self._files:
154
182
            if file.startswith(self._cwd):
155
183
                yield urlutils.escape(file[len(self._cwd):])
156
 
    
 
184
 
157
185
    def list_dir(self, relpath):
158
186
        """See Transport.list_dir()."""
159
187
        _abspath = self._abspath(relpath)
192
220
                    del container[path]
193
221
        do_renames(self._files)
194
222
        do_renames(self._dirs)
195
 
    
 
223
 
196
224
    def rmdir(self, relpath):
197
225
        """See Transport.rmdir."""
198
226
        _abspath = self._abspath(relpath)
213
241
        """See Transport.stat()."""
214
242
        _abspath = self._abspath(relpath)
215
243
        if _abspath in self._files:
216
 
            return MemoryStat(len(self._files[_abspath][0]), False, 
 
244
            return MemoryStat(len(self._files[_abspath][0]), False,
217
245
                              self._files[_abspath][1])
218
246
        elif _abspath in self._dirs:
219
247
            return MemoryStat(0, True, self._dirs[_abspath])
231
259
    def _abspath(self, relpath):
232
260
        """Generate an internal absolute path."""
233
261
        relpath = urlutils.unescape(relpath)
234
 
        if relpath.find('..') != -1:
235
 
            raise AssertionError('relpath contains ..')
236
 
        if relpath == '':
237
 
            return '/'
238
 
        if relpath[0] == '/':
 
262
        if relpath[:1] == '/':
239
263
            return relpath
240
 
        if relpath == '.':
241
 
            if (self._cwd == '/'):
242
 
                return self._cwd
243
 
            return self._cwd[:-1]
244
 
        if relpath.endswith('/'):
245
 
            relpath = relpath[:-1]
246
 
        if relpath.startswith('./'):
247
 
            relpath = relpath[2:]
248
 
        return self._cwd + relpath
 
264
        cwd_parts = self._cwd.split('/')
 
265
        rel_parts = relpath.split('/')
 
266
        r = []
 
267
        for i in cwd_parts + rel_parts:
 
268
            if i == '..':
 
269
                if not r:
 
270
                    raise ValueError("illegal relpath %r under %r"
 
271
                        % (relpath, self._cwd))
 
272
                r = r[:-1]
 
273
            elif i == '.' or i == '':
 
274
                pass
 
275
            else:
 
276
                r.append(i)
 
277
        return '/' + '/'.join(r)
249
278
 
250
279
 
251
280
class _MemoryLock(object):
252
281
    """This makes a lock."""
253
282
 
254
283
    def __init__(self, path, transport):
255
 
        assert isinstance(transport, MemoryTransport)
256
284
        self.path = path
257
285
        self.transport = transport
258
286
        if self.path in self.transport._locks:
259
287
            raise LockError('File %r already locked' % (self.path,))
260
288
        self.transport._locks[self.path] = self
261
289
 
262
 
    def __del__(self):
263
 
        # Should this warn, or actually try to cleanup?
264
 
        if self.transport:
265
 
            warnings.warn("MemoryLock %r not explicitly unlocked" % (self.path,))
266
 
            self.unlock()
267
 
 
268
290
    def unlock(self):
269
291
        del self.transport._locks[self.path]
270
292
        self.transport = None
271
293
 
272
294
 
273
 
class MemoryServer(Server):
 
295
class MemoryServer(transport.Server):
274
296
    """Server for the MemoryTransport for testing with."""
275
297
 
276
 
    def setUp(self):
277
 
        """See bzrlib.transport.Server.setUp."""
 
298
    def start_server(self):
278
299
        self._dirs = {'/':None}
279
300
        self._files = {}
280
301
        self._locks = {}
281
302
        self._scheme = "memory+%s:///" % id(self)
282
303
        def memory_factory(url):
283
 
            result = MemoryTransport(url)
 
304
            from bzrlib.transport import memory
 
305
            result = memory.MemoryTransport(url)
284
306
            result._dirs = self._dirs
285
307
            result._files = self._files
286
308
            result._locks = self._locks
287
309
            return result
288
 
        register_transport(self._scheme, memory_factory)
 
310
        self._memory_factory = memory_factory
 
311
        transport.register_transport(self._scheme, self._memory_factory)
289
312
 
290
 
    def tearDown(self):
291
 
        """See bzrlib.transport.Server.tearDown."""
 
313
    def stop_server(self):
292
314
        # unregister this server
 
315
        transport.unregister_transport(self._scheme, self._memory_factory)
293
316
 
294
317
    def get_url(self):
295
318
        """See bzrlib.transport.Server.get_url."""
296
319
        return self._scheme
297
320
 
 
321
    def get_bogus_url(self):
 
322
        raise NotImplementedError
 
323
 
298
324
 
299
325
def get_test_permutations():
300
326
    """Return the permutations to be used in testing."""