~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/memory.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
from cStringIO import StringIO
23
23
 
24
24
from bzrlib.trace import mutter
25
 
from bzrlib.errors import TransportError, NoSuchFile, FileExists
 
25
from bzrlib.errors import TransportError, NoSuchFile, FileExists, LockError
26
26
from bzrlib.transport import Transport, register_transport, Server
27
27
 
28
28
class MemoryStat(object):
38
38
 
39
39
 
40
40
class MemoryTransport(Transport):
41
 
    """This is the transport agent for local filesystem access."""
 
41
    """This is an in memory file system for transient data storage."""
42
42
 
43
43
    def __init__(self, url=""):
44
44
        """Set the 'base' path where files will be stored."""
50
50
        self._cwd = url[url.find(':') + 1:]
51
51
        self._dirs = {}
52
52
        self._files = {}
 
53
        self._locks = {}
53
54
 
54
55
    def clone(self, offset=None):
55
56
        """See Transport.clone()."""
70
71
        result = MemoryTransport(url)
71
72
        result._dirs = self._dirs
72
73
        result._files = self._files
 
74
        result._locks = self._locks
73
75
        return result
74
76
 
75
77
    def abspath(self, relpath):
76
78
        """See Transport.abspath()."""
77
 
        return self.base[:-1] + self._abspath(relpath)
 
79
        return self.base[:-1] + self._abspath(relpath)[len(self._cwd) - 1:]
78
80
 
79
81
    def append(self, relpath, f):
80
82
        """See Transport.append()."""
145
147
        for path in self._dirs:
146
148
            if (path.startswith(_abspath) and 
147
149
                path[len(_abspath) + 1:].find('/') == -1 and
148
 
                len(path) > len(_abspath)):
 
150
                len(path) > len(_abspath) and
 
151
                path[len(_abspath)] == '/'):
149
152
                result.append(path[len(_abspath) + 1:])
150
153
        return result
151
154
    
 
155
    def rmdir(self, relpath):
 
156
        """See Transport.rmdir."""
 
157
        _abspath = self._abspath(relpath)
 
158
        if _abspath in self._files:
 
159
            self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
 
160
        for path in self._files:
 
161
            if path.startswith(_abspath):
 
162
                self._translate_error(IOError(errno.EBUSY, relpath), relpath)
 
163
        for path in self._dirs:
 
164
            if path.startswith(_abspath) and path != _abspath:
 
165
                self._translate_error(IOError(errno.EBUSY, relpath), relpath)
 
166
        if not _abspath in self._dirs:
 
167
            raise NoSuchFile(relpath)
 
168
        del self._dirs[_abspath]
 
169
 
152
170
    def stat(self, relpath):
153
171
        """See Transport.stat()."""
154
172
        _abspath = self._abspath(relpath)
160
178
        elif _abspath in self._dirs:
161
179
            return MemoryStat(0, True, self._dirs[_abspath])
162
180
        else:
163
 
            raise NoSuchFile(relpath)
164
 
 
165
 
#    def lock_read(self, relpath):
166
 
#   TODO if needed
167
 
#
168
 
#    def lock_write(self, relpath):
169
 
#   TODO if needed
 
181
            raise NoSuchFile(_abspath)
 
182
 
 
183
    def lock_read(self, relpath):
 
184
        """See Transport.lock_read()."""
 
185
        return _MemoryLock(self._abspath(relpath), self)
 
186
 
 
187
    def lock_write(self, relpath):
 
188
        """See Transport.lock_write()."""
 
189
        return _MemoryLock(self._abspath(relpath), self)
170
190
 
171
191
    def _abspath(self, relpath):
172
192
        """Generate an internal absolute path."""
176
196
            return self._cwd[:-1]
177
197
        if relpath.endswith('/'):
178
198
            relpath = relpath[:-1]
 
199
        if relpath.startswith('./'):
 
200
            relpath = relpath[2:]
179
201
        return self._cwd + relpath
180
202
 
181
203
 
 
204
class _MemoryLock(object):
 
205
    """This makes a lock."""
 
206
 
 
207
    def __init__(self, path, transport):
 
208
        assert isinstance(transport, MemoryTransport)
 
209
        self.path = path
 
210
        self.transport = transport
 
211
        if self.path in self.transport._locks:
 
212
            raise LockError('File %r already locked' % (self.path,))
 
213
        self.transport._locks[self.path] = self
 
214
 
 
215
    def __del__(self):
 
216
        # Should this warn, or actually try to cleanup?
 
217
        if self.transport:
 
218
            warn("MemoryLock %r not explicitly unlocked" % (self.path,))
 
219
            self.unlock()
 
220
 
 
221
    def unlock(self):
 
222
        del self.transport._locks[self.path]
 
223
        self.transport = None
 
224
 
 
225
 
182
226
class MemoryServer(Server):
183
227
    """Server for the MemoryTransport for testing with."""
184
228
 
185
229
    def setUp(self):
186
230
        """See bzrlib.transport.Server.setUp."""
 
231
        self._dirs = {}
 
232
        self._files = {}
 
233
        self._locks = {}
187
234
        self._scheme = "memory+%s:" % id(self)
188
 
        register_transport(self._scheme, MemoryTransport)
 
235
        def memory_factory(url):
 
236
            result = MemoryTransport(url)
 
237
            result._dirs = self._dirs
 
238
            result._files = self._files
 
239
            result._locks = self._locks
 
240
            return result
 
241
        register_transport(self._scheme, memory_factory)
189
242
 
190
243
    def tearDown(self):
191
244
        """See bzrlib.transport.Server.tearDown."""