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
17
17
"""Implementation of Transport that uses memory for its storage.
27
27
from cStringIO import StringIO
30
from bzrlib.errors import TransportError, NoSuchFile, FileExists, LockError
34
from bzrlib.errors import (
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,
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] != '/':
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]
133
def external_url(self):
134
"""See bzrlib.transport.Transport.external_url."""
135
# MemoryTransport's are only accessible in-process
137
raise InProcessTransport(self)
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)
146
raise NoSuchFile(relpath)
125
147
return StringIO(self._files[_abspath][0])
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)
140
163
def mkdir(self, relpath, mode=None):
141
164
"""See Transport.mkdir()."""
145
168
raise FileExists(relpath)
146
169
self._dirs[_abspath]=mode
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
148
178
def listable(self):
149
179
"""See Transport.listable."""
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 ..')
238
if relpath[0] == '/':
264
if relpath[:1] == '/':
241
if (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('/')
269
for i in cwd_parts + rel_parts:
272
raise ValueError("illegal relpath %r under %r"
273
% (relpath, self._cwd))
275
elif i == '.' or i == '':
279
return '/' + '/'.join(r)
251
282
class _MemoryLock(object):
252
283
"""This makes a lock."""
254
285
def __init__(self, path, transport):
255
assert isinstance(transport, MemoryTransport)
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
263
# Should this warn, or actually try to cleanup?
265
warnings.warn("MemoryLock %r not explicitly unlocked" % (self.path,))
268
292
def unlock(self):
269
293
del self.transport._locks[self.path]
270
294
self.transport = None
273
class MemoryServer(Server):
297
class MemoryServer(transport.Server):
274
298
"""Server for the MemoryTransport for testing with."""
277
"""See bzrlib.transport.Server.setUp."""
300
def start_server(self):
278
301
self._dirs = {'/':None}
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
288
register_transport(self._scheme, memory_factory)
312
self._memory_factory = memory_factory
313
transport.register_transport(self._scheme, self._memory_factory)
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)
294
319
def get_url(self):
295
320
"""See bzrlib.transport.Server.get_url."""
296
321
return self._scheme
323
def get_bogus_url(self):
324
raise NotImplementedError
299
327
def get_test_permutations():
300
328
"""Return the permutations to be used in testing."""