22
22
from cStringIO import StringIO
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
28
28
class MemoryStat(object):
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."""
43
43
def __init__(self, url=""):
44
44
"""Set the 'base' path where files will be stored."""
70
71
result = MemoryTransport(url)
71
72
result._dirs = self._dirs
72
73
result._files = self._files
74
result._locks = self._locks
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:]
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:])
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]
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])
163
raise NoSuchFile(relpath)
165
# def lock_read(self, relpath):
168
# def lock_write(self, relpath):
181
raise NoSuchFile(_abspath)
183
def lock_read(self, relpath):
184
"""See Transport.lock_read()."""
185
return _MemoryLock(self._abspath(relpath), self)
187
def lock_write(self, relpath):
188
"""See Transport.lock_write()."""
189
return _MemoryLock(self._abspath(relpath), self)
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
204
class _MemoryLock(object):
205
"""This makes a lock."""
207
def __init__(self, path, transport):
208
assert isinstance(transport, MemoryTransport)
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
216
# Should this warn, or actually try to cleanup?
218
warn("MemoryLock %r not explicitly unlocked" % (self.path,))
222
del self.transport._locks[self.path]
223
self.transport = None
182
226
class MemoryServer(Server):
183
227
"""Server for the MemoryTransport for testing with."""
186
230
"""See bzrlib.transport.Server.setUp."""
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
241
register_transport(self._scheme, memory_factory)
190
243
def tearDown(self):
191
244
"""See bzrlib.transport.Server.tearDown."""