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
25
from bzrlib.errors import TransportError, NoSuchFile, FileExists
24
from bzrlib.transport import Transport
26
from bzrlib.transport import Transport, register_transport, Server
26
28
class MemoryStat(object):
28
def __init__(self, size):
30
def __init__(self, size, is_dir, perms):
29
31
self.st_size = size
35
self.st_mode = S_IFREG | perms
37
self.st_mode = S_IFDIR | perms
32
40
class MemoryTransport(Transport):
33
"""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=""):
36
44
"""Set the 'base' path where files will be stored."""
37
super(MemoryTransport, self).__init__('in-memory:')
49
super(MemoryTransport, self).__init__(url)
50
self._cwd = url[url.find(':') + 1:]
41
54
def clone(self, offset=None):
42
55
"""See Transport.clone()."""
58
segments = offset.split('/')
59
cwdsegments = self._cwd.split('/')[:-1]
61
segment = segments.pop(0)
65
if len(cwdsegments) > 1:
68
cwdsegments.append(segment)
69
url = self.base[:self.base.find(':') + 1] + '/'.join(cwdsegments) + '/'
70
result = MemoryTransport(url)
71
result._dirs = self._dirs
72
result._files = self._files
45
75
def abspath(self, relpath):
46
76
"""See Transport.abspath()."""
47
return self.base + relpath
77
return self.base[:-1] + self._abspath(relpath)
49
79
def append(self, relpath, f):
50
80
"""See Transport.append()."""
51
self._check_parent(relpath)
52
self._files[relpath] = self._files.get(relpath, "") + f.read()
81
_abspath = self._abspath(relpath)
82
self._check_parent(_abspath)
83
orig_content, orig_mode = self._files.get(_abspath, ("", None))
84
self._files[_abspath] = (orig_content + f.read(), orig_mode)
54
def _check_parent(self, relpath):
55
dir = os.path.dirname(relpath)
86
def _check_parent(self, _abspath):
87
dir = os.path.dirname(_abspath)
57
89
if not dir in self._dirs:
58
raise NoSuchFile(relpath)
90
raise NoSuchFile(_abspath)
60
92
def has(self, relpath):
61
93
"""See Transport.has()."""
62
return relpath in self._files
94
_abspath = self._abspath(relpath)
95
return _abspath in self._files or _abspath in self._dirs
97
def delete(self, relpath):
98
"""See Transport.delete()."""
99
_abspath = self._abspath(relpath)
100
if not _abspath in self._files:
101
raise NoSuchFile(relpath)
102
del self._files[_abspath]
64
104
def get(self, relpath):
65
105
"""See Transport.get()."""
66
if not relpath in self._files:
106
_abspath = self._abspath(relpath)
107
if not _abspath in self._files:
67
108
raise NoSuchFile(relpath)
68
return StringIO(self._files[relpath])
109
return StringIO(self._files[_abspath][0])
70
111
def put(self, relpath, f, mode=None):
71
112
"""See Transport.put()."""
72
self._check_parent(relpath)
73
self._files[relpath] = f.read()
113
_abspath = self._abspath(relpath)
114
self._check_parent(_abspath)
115
self._files[_abspath] = (f.read(), mode)
75
117
def mkdir(self, relpath, mode=None):
76
118
"""See Transport.mkdir()."""
77
self._check_parent(relpath)
78
if relpath in self._dirs:
119
_abspath = self._abspath(relpath)
120
self._check_parent(_abspath)
121
if _abspath in self._dirs:
79
122
raise FileExists(relpath)
80
self._dirs.add(relpath)
123
self._dirs[_abspath]=mode
82
125
def listable(self):
83
126
"""See Transport.listable."""
86
129
def iter_files_recursive(self):
87
return iter(self._files)
89
# def list_dir(self, relpath):
130
for file in self._files:
131
if file.startswith(self._cwd):
132
yield file[len(self._cwd):]
134
def list_dir(self, relpath):
135
"""See Transport.list_dir()."""
136
_abspath = self._abspath(relpath)
137
if _abspath != '/' and _abspath not in self._dirs:
138
raise NoSuchFile(relpath)
140
for path in self._files:
141
if (path.startswith(_abspath) and
142
path[len(_abspath) + 1:].find('/') == -1 and
143
len(path) > len(_abspath)):
144
result.append(path[len(_abspath) + 1:])
145
for path in self._dirs:
146
if (path.startswith(_abspath) and
147
path[len(_abspath) + 1:].find('/') == -1 and
148
len(path) > len(_abspath) and
149
path[len(_abspath)] == '/'):
150
result.append(path[len(_abspath) + 1:])
153
def rmdir(self, relpath):
154
"""See Transport.rmdir."""
155
_abspath = self._abspath(relpath)
156
if _abspath in self._files:
157
self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
158
for path in self._files:
159
if path.startswith(_abspath):
160
self._translate_error(IOError(errno.EBUSY, relpath), relpath)
161
for path in self._dirs:
162
if path.startswith(_abspath) and path != _abspath:
163
self._translate_error(IOError(errno.EBUSY, relpath), relpath)
164
if not _abspath in self._dirs:
165
raise NoSuchFile(relpath)
166
del self._dirs[_abspath]
92
168
def stat(self, relpath):
93
169
"""See Transport.stat()."""
94
return MemoryStat(len(self._files[relpath]))
170
_abspath = self._abspath(relpath)
171
if _abspath in self._files:
172
return MemoryStat(len(self._files[_abspath][0]), False,
173
self._files[_abspath][1])
175
return MemoryStat(0, True, None)
176
elif _abspath in self._dirs:
177
return MemoryStat(0, True, self._dirs[_abspath])
179
raise NoSuchFile(relpath)
96
181
# def lock_read(self, relpath):
99
184
# def lock_write(self, relpath):
187
def _abspath(self, relpath):
188
"""Generate an internal absolute path."""
189
if relpath.find('..') != -1:
190
raise AssertionError('relpath contains ..')
192
return self._cwd[:-1]
193
if relpath.endswith('/'):
194
relpath = relpath[:-1]
195
if relpath.startswith('./'):
196
relpath = relpath[2:]
197
return self._cwd + relpath
200
class MemoryServer(Server):
201
"""Server for the MemoryTransport for testing with."""
204
"""See bzrlib.transport.Server.setUp."""
205
self._scheme = "memory+%s:" % id(self)
206
register_transport(self._scheme, MemoryTransport)
209
"""See bzrlib.transport.Server.tearDown."""
210
# unregister this server
213
"""See bzrlib.transport.Server.get_url."""
217
def get_test_permutations():
218
"""Return the permutations to be used in testing."""
219
return [(MemoryTransport, MemoryServer),