~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/memory.py

  • Committer: Martin Packman
  • Date: 2011-12-23 19:38:22 UTC
  • mto: This revision was merged to the branch mainline in revision 6405.
  • Revision ID: martin.packman@canonical.com-20111223193822-hesheea4o8aqwexv
Accept and document passing the medium rather than transport for smart connections

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
 
27
27
from cStringIO import StringIO
28
28
import warnings
29
29
 
30
 
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
    )
31
41
from bzrlib.trace import mutter
32
 
from bzrlib.transport import (Transport, register_transport, Server)
33
 
import bzrlib.urlutils as urlutils
 
42
from bzrlib.transport import (
 
43
    AppendBasedFileStream,
 
44
    _file_streams,
 
45
    LateReadError,
 
46
    )
34
47
 
35
48
 
36
49
 
48
61
            self.st_mode = S_IFDIR | perms
49
62
 
50
63
 
51
 
class MemoryTransport(Transport):
 
64
class MemoryTransport(transport.Transport):
52
65
    """This is an in memory file system for transient data storage."""
53
66
 
54
67
    def __init__(self, url=""):
68
81
 
69
82
    def clone(self, offset=None):
70
83
        """See Transport.clone()."""
71
 
        path = self._combine_paths(self._cwd, offset)
 
84
        path = urlutils.URL._combine_paths(self._cwd, offset)
72
85
        if len(path) == 0 or path[-1] != '/':
73
86
            path += '/'
74
87
        url = self._scheme + path
75
 
        result = MemoryTransport(url)
 
88
        result = self.__class__(url)
76
89
        result._dirs = self._dirs
77
90
        result._files = self._files
78
91
        result._locks = self._locks
117
130
            raise NoSuchFile(relpath)
118
131
        del self._files[_abspath]
119
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
 
120
139
    def get(self, relpath):
121
140
        """See Transport.get()."""
122
141
        _abspath = self._abspath(relpath)
123
142
        if not _abspath in self._files:
124
 
            raise NoSuchFile(relpath)
 
143
            if _abspath in self._dirs:
 
144
                return LateReadError(relpath)
 
145
            else:
 
146
                raise NoSuchFile(relpath)
125
147
        return StringIO(self._files[_abspath][0])
126
148
 
127
149
    def put_file(self, relpath, f, mode=None):
136
158
                'undefined', bytes, 0, 1,
137
159
                'put_file must be given a file of bytes, not unicode.')
138
160
        self._files[_abspath] = (bytes, mode)
 
161
        return len(bytes)
139
162
 
140
163
    def mkdir(self, relpath, mode=None):
141
164
        """See Transport.mkdir()."""
145
168
            raise FileExists(relpath)
146
169
        self._dirs[_abspath]=mode
147
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
 
148
178
    def listable(self):
149
179
        """See Transport.listable."""
150
180
        return True
153
183
        for file in self._files:
154
184
            if file.startswith(self._cwd):
155
185
                yield urlutils.escape(file[len(self._cwd):])
156
 
    
 
186
 
157
187
    def list_dir(self, relpath):
158
188
        """See Transport.list_dir()."""
159
189
        _abspath = self._abspath(relpath)
192
222
                    del container[path]
193
223
        do_renames(self._files)
194
224
        do_renames(self._dirs)
195
 
    
 
225
 
196
226
    def rmdir(self, relpath):
197
227
        """See Transport.rmdir."""
198
228
        _abspath = self._abspath(relpath)
213
243
        """See Transport.stat()."""
214
244
        _abspath = self._abspath(relpath)
215
245
        if _abspath in self._files:
216
 
            return MemoryStat(len(self._files[_abspath][0]), False, 
 
246
            return MemoryStat(len(self._files[_abspath][0]), False,
217
247
                              self._files[_abspath][1])
218
248
        elif _abspath in self._dirs:
219
249
            return MemoryStat(0, True, self._dirs[_abspath])
231
261
    def _abspath(self, relpath):
232
262
        """Generate an internal absolute path."""
233
263
        relpath = urlutils.unescape(relpath)
234
 
        if relpath.find('..') != -1:
235
 
            raise AssertionError('relpath contains ..')
236
 
        if relpath == '':
237
 
            return '/'
238
 
        if relpath[0] == '/':
 
264
        if relpath[:1] == '/':
239
265
            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
 
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)
249
280
 
250
281
 
251
282
class _MemoryLock(object):
252
283
    """This makes a lock."""
253
284
 
254
285
    def __init__(self, path, transport):
255
 
        assert isinstance(transport, MemoryTransport)
256
286
        self.path = path
257
287
        self.transport = transport
258
288
        if self.path in self.transport._locks:
259
289
            raise LockError('File %r already locked' % (self.path,))
260
290
        self.transport._locks[self.path] = self
261
291
 
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
292
    def unlock(self):
269
293
        del self.transport._locks[self.path]
270
294
        self.transport = None
271
295
 
272
296
 
273
 
class MemoryServer(Server):
 
297
class MemoryServer(transport.Server):
274
298
    """Server for the MemoryTransport for testing with."""
275
299
 
276
 
    def setUp(self):
277
 
        """See bzrlib.transport.Server.setUp."""
 
300
    def start_server(self):
278
301
        self._dirs = {'/':None}
279
302
        self._files = {}
280
303
        self._locks = {}
281
304
        self._scheme = "memory+%s:///" % id(self)
282
305
        def memory_factory(url):
283
 
            result = MemoryTransport(url)
 
306
            from bzrlib.transport import memory
 
307
            result = memory.MemoryTransport(url)
284
308
            result._dirs = self._dirs
285
309
            result._files = self._files
286
310
            result._locks = self._locks
287
311
            return result
288
 
        register_transport(self._scheme, memory_factory)
 
312
        self._memory_factory = memory_factory
 
313
        transport.register_transport(self._scheme, self._memory_factory)
289
314
 
290
 
    def tearDown(self):
291
 
        """See bzrlib.transport.Server.tearDown."""
 
315
    def stop_server(self):
292
316
        # unregister this server
 
317
        transport.unregister_transport(self._scheme, self._memory_factory)
293
318
 
294
319
    def get_url(self):
295
320
        """See bzrlib.transport.Server.get_url."""
296
321
        return self._scheme
297
322
 
 
323
    def get_bogus_url(self):
 
324
        raise NotImplementedError
 
325
 
298
326
 
299
327
def get_test_permutations():
300
328
    """Return the permutations to be used in testing."""