15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
16
"""Implementation of Transport that uses memory for its storage."""
20
22
from cStringIO import StringIO
22
24
from bzrlib.trace import mutter
23
from bzrlib.transport import Transport, \
24
TransportError, NoSuchFile, FileExists
25
from bzrlib.errors import TransportError, NoSuchFile, FileExists, LockError
26
from bzrlib.transport import Transport, register_transport, Server
27
28
class MemoryStat(object):
29
def __init__(self, size):
30
def __init__(self, size, is_dir, perms):
30
31
self.st_size = size
35
self.st_mode = S_IFREG | perms
37
self.st_mode = S_IFDIR | perms
33
40
class MemoryTransport(Transport):
34
"""This is the transport agent for local filesystem access."""
41
"""This is an in memory file system for transient data storage."""
43
def __init__(self, url=""):
37
44
"""Set the 'base' path where files will be stored."""
38
super(MemoryTransport, self).__init__('in-memory:')
49
super(MemoryTransport, self).__init__(url)
50
self._cwd = url[url.find(':') + 1:]
42
55
def clone(self, offset=None):
43
56
"""See Transport.clone()."""
59
segments = offset.split('/')
60
cwdsegments = self._cwd.split('/')[:-1]
62
segment = segments.pop(0)
66
if len(cwdsegments) > 1:
69
cwdsegments.append(segment)
70
url = self.base[:self.base.find(':') + 1] + '/'.join(cwdsegments) + '/'
71
result = MemoryTransport(url)
72
result._dirs = self._dirs
73
result._files = self._files
74
result._locks = self._locks
46
77
def abspath(self, relpath):
47
78
"""See Transport.abspath()."""
48
return self.base + relpath
79
return self.base[:-1] + self._abspath(relpath)[len(self._cwd) - 1:]
50
81
def append(self, relpath, f):
51
82
"""See Transport.append()."""
52
self._check_parent(relpath)
53
self._files[relpath] = self._files.get(relpath, "") + f.read()
83
_abspath = self._abspath(relpath)
84
self._check_parent(_abspath)
85
orig_content, orig_mode = self._files.get(_abspath, ("", None))
86
self._files[_abspath] = (orig_content + f.read(), orig_mode)
55
def _check_parent(self, relpath):
56
dir = os.path.dirname(relpath)
88
def _check_parent(self, _abspath):
89
dir = os.path.dirname(_abspath)
58
91
if not dir in self._dirs:
59
raise NoSuchFile(relpath)
92
raise NoSuchFile(_abspath)
61
94
def has(self, relpath):
62
95
"""See Transport.has()."""
63
return relpath in self._files
96
_abspath = self._abspath(relpath)
97
return _abspath in self._files or _abspath in self._dirs
99
def delete(self, relpath):
100
"""See Transport.delete()."""
101
_abspath = self._abspath(relpath)
102
if not _abspath in self._files:
103
raise NoSuchFile(relpath)
104
del self._files[_abspath]
65
106
def get(self, relpath):
66
107
"""See Transport.get()."""
67
if not relpath in self._files:
108
_abspath = self._abspath(relpath)
109
if not _abspath in self._files:
68
110
raise NoSuchFile(relpath)
69
return StringIO(self._files[relpath])
111
return StringIO(self._files[_abspath][0])
71
def put(self, relpath, f):
113
def put(self, relpath, f, mode=None):
72
114
"""See Transport.put()."""
73
self._check_parent(relpath)
74
self._files[relpath] = f.read()
115
_abspath = self._abspath(relpath)
116
self._check_parent(_abspath)
117
self._files[_abspath] = (f.read(), mode)
76
def mkdir(self, relpath):
119
def mkdir(self, relpath, mode=None):
77
120
"""See Transport.mkdir()."""
78
self._check_parent(relpath)
79
if relpath in self._dirs:
121
_abspath = self._abspath(relpath)
122
self._check_parent(_abspath)
123
if _abspath in self._dirs:
80
124
raise FileExists(relpath)
81
self._dirs.add(relpath)
125
self._dirs[_abspath]=mode
83
127
def listable(self):
84
128
"""See Transport.listable."""
87
131
def iter_files_recursive(self):
88
return iter(self._files)
90
# def list_dir(self, relpath):
132
for file in self._files:
133
if file.startswith(self._cwd):
134
yield file[len(self._cwd):]
136
def list_dir(self, relpath):
137
"""See Transport.list_dir()."""
138
_abspath = self._abspath(relpath)
139
if _abspath != '/' and _abspath not in self._dirs:
140
raise NoSuchFile(relpath)
142
for path in self._files:
143
if (path.startswith(_abspath) and
144
path[len(_abspath) + 1:].find('/') == -1 and
145
len(path) > len(_abspath)):
146
result.append(path[len(_abspath) + 1:])
147
for path in self._dirs:
148
if (path.startswith(_abspath) and
149
path[len(_abspath) + 1:].find('/') == -1 and
150
len(path) > len(_abspath) and
151
path[len(_abspath)] == '/'):
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]
93
170
def stat(self, relpath):
94
171
"""See Transport.stat()."""
95
return MemoryStat(len(self._files[relpath]))
97
# def lock_read(self, relpath):
100
# def lock_write(self, relpath):
172
_abspath = self._abspath(relpath)
173
if _abspath in self._files:
174
return MemoryStat(len(self._files[_abspath][0]), False,
175
self._files[_abspath][1])
177
return MemoryStat(0, True, None)
178
elif _abspath in self._dirs:
179
return MemoryStat(0, True, self._dirs[_abspath])
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)
191
def _abspath(self, relpath):
192
"""Generate an internal absolute path."""
193
if relpath.find('..') != -1:
194
raise AssertionError('relpath contains ..')
196
return self._cwd[:-1]
197
if relpath.endswith('/'):
198
relpath = relpath[:-1]
199
if relpath.startswith('./'):
200
relpath = relpath[2:]
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
226
class MemoryServer(Server):
227
"""Server for the MemoryTransport for testing with."""
230
"""See bzrlib.transport.Server.setUp."""
234
self._scheme = "memory+%s:" % id(self)
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)
244
"""See bzrlib.transport.Server.tearDown."""
245
# unregister this server
248
"""See bzrlib.transport.Server.get_url."""
252
def get_test_permutations():
253
"""Return the permutations to be used in testing."""
254
return [(MemoryTransport, MemoryServer),