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
30
from bzrlib.errors import (
31
37
from bzrlib.trace import mutter
32
from bzrlib.transport import (Transport, register_transport, Server)
38
from bzrlib.transport import (
39
AppendBasedFileStream,
33
46
import bzrlib.urlutils as urlutils
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):
128
150
"""See Transport.put_file()."""
129
151
_abspath = self._abspath(relpath)
130
152
self._check_parent(_abspath)
131
self._files[_abspath] = (f.read(), mode)
154
if type(bytes) is not str:
155
# Although not strictly correct, we raise UnicodeEncodeError to be
156
# compatible with other transports.
157
raise UnicodeEncodeError(
158
'undefined', bytes, 0, 1,
159
'put_file must be given a file of bytes, not unicode.')
160
self._files[_abspath] = (bytes, mode)
133
163
def mkdir(self, relpath, mode=None):
134
164
"""See Transport.mkdir()."""
138
168
raise FileExists(relpath)
139
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
141
178
def listable(self):
142
179
"""See Transport.listable."""
146
183
for file in self._files:
147
184
if file.startswith(self._cwd):
148
185
yield urlutils.escape(file[len(self._cwd):])
150
187
def list_dir(self, relpath):
151
188
"""See Transport.list_dir()."""
152
189
_abspath = self._abspath(relpath)
185
222
del container[path]
186
223
do_renames(self._files)
187
224
do_renames(self._dirs)
189
226
def rmdir(self, relpath):
190
227
"""See Transport.rmdir."""
191
228
_abspath = self._abspath(relpath)
192
229
if _abspath in self._files:
193
230
self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
194
231
for path in self._files:
195
if path.startswith(_abspath):
232
if path.startswith(_abspath + '/'):
196
233
self._translate_error(IOError(errno.ENOTEMPTY, relpath),
198
235
for path in self._dirs:
199
if path.startswith(_abspath) and path != _abspath:
236
if path.startswith(_abspath + '/') and path != _abspath:
200
237
self._translate_error(IOError(errno.ENOTEMPTY, relpath), relpath)
201
238
if not _abspath in self._dirs:
202
239
raise NoSuchFile(relpath)
206
243
"""See Transport.stat()."""
207
244
_abspath = self._abspath(relpath)
208
245
if _abspath in self._files:
209
return MemoryStat(len(self._files[_abspath][0]), False,
246
return MemoryStat(len(self._files[_abspath][0]), False,
210
247
self._files[_abspath][1])
211
248
elif _abspath in self._dirs:
212
249
return MemoryStat(0, True, self._dirs[_abspath])
224
261
def _abspath(self, relpath):
225
262
"""Generate an internal absolute path."""
226
263
relpath = urlutils.unescape(relpath)
227
if relpath.find('..') != -1:
228
raise AssertionError('relpath contains ..')
231
if relpath[0] == '/':
264
if relpath[:1] == '/':
234
if (self._cwd == '/'):
236
return self._cwd[:-1]
237
if relpath.endswith('/'):
238
relpath = relpath[:-1]
239
if relpath.startswith('./'):
240
relpath = relpath[2:]
241
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)
244
282
class _MemoryLock(object):
245
283
"""This makes a lock."""
247
285
def __init__(self, path, transport):
248
assert isinstance(transport, MemoryTransport)
250
287
self.transport = transport
251
288
if self.path in self.transport._locks: