1
# Copyright (C) 2005 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
16
"""Implementation of Transport that uses memory for its storage."""
22
from cStringIO import StringIO
24
from bzrlib.trace import mutter
25
from bzrlib.errors import TransportError, NoSuchFile, FileExists
26
from bzrlib.transport import Transport, register_transport, Server
28
class MemoryStat(object):
30
def __init__(self, size, is_dir):
33
self.st_mode = S_IFREG
35
self.st_mode = S_IFDIR
38
class MemoryTransport(Transport):
39
"""This is the transport agent for local filesystem access."""
41
def __init__(self, url=""):
42
"""Set the 'base' path where files will be stored."""
47
super(MemoryTransport, self).__init__(url)
48
self._cwd = url[url.find(':') + 1:]
52
def clone(self, offset=None):
53
"""See Transport.clone()."""
56
segments = offset.split('/')
57
cwdsegments = self._cwd.split('/')[:-1]
59
segment = segments.pop(0)
63
if len(cwdsegments) > 1:
66
cwdsegments.append(segment)
67
url = self.base[:self.base.find(':') + 1] + '/'.join(cwdsegments) + '/'
68
result = MemoryTransport(url)
69
result._dirs = self._dirs
70
result._files = self._files
73
def abspath(self, relpath):
74
"""See Transport.abspath()."""
75
return self.base[:-1] + self._abspath(relpath)
77
def append(self, relpath, f):
78
"""See Transport.append()."""
79
_abspath = self._abspath(relpath)
80
self._check_parent(_abspath)
81
self._files[_abspath] = self._files.get(_abspath, "") + f.read()
83
def _check_parent(self, _abspath):
84
dir = os.path.dirname(_abspath)
86
if not dir in self._dirs:
87
raise NoSuchFile(_abspath)
89
def has(self, relpath):
90
"""See Transport.has()."""
91
_abspath = self._abspath(relpath)
92
return _abspath in self._files or _abspath in self._dirs
94
def delete(self, relpath):
95
"""See Transport.delete()."""
96
_abspath = self._abspath(relpath)
97
if not _abspath in self._files:
98
raise NoSuchFile(relpath)
99
del self._files[_abspath]
101
def get(self, relpath):
102
"""See Transport.get()."""
103
_abspath = self._abspath(relpath)
104
if not _abspath in self._files:
105
raise NoSuchFile(relpath)
106
return StringIO(self._files[_abspath])
108
def put(self, relpath, f, mode=None):
109
"""See Transport.put()."""
110
_abspath = self._abspath(relpath)
111
self._check_parent(_abspath)
112
self._files[_abspath] = f.read()
114
def mkdir(self, relpath, mode=None):
115
"""See Transport.mkdir()."""
116
_abspath = self._abspath(relpath)
117
self._check_parent(_abspath)
118
if _abspath in self._dirs:
119
raise FileExists(relpath)
120
self._dirs.add(_abspath)
123
"""See Transport.listable."""
126
def iter_files_recursive(self):
127
for file in self._files:
128
if file.startswith(self._cwd):
129
yield file[len(self._cwd):]
131
def list_dir(self, relpath):
132
"""See Transport.list_dir()."""
133
_abspath = self._abspath(relpath)
134
if _abspath != '/' and _abspath not in self._dirs:
135
raise NoSuchFile(relpath)
137
for path in self._files:
138
if (path.startswith(_abspath) and
139
path[len(_abspath) + 1:].find('/') == -1 and
140
len(path) > len(_abspath)):
141
result.append(path[len(_abspath) + 1:])
142
for path in self._dirs:
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:])
149
def stat(self, relpath):
150
"""See Transport.stat()."""
151
_abspath = self._abspath(relpath)
152
if _abspath in self._files:
153
return MemoryStat(len(self._files[_abspath]), False)
154
elif _abspath in self._dirs or _abspath == '':
155
return MemoryStat(0, True)
157
raise NoSuchFile(relpath)
159
# def lock_read(self, relpath):
162
# def lock_write(self, relpath):
165
def _abspath(self, relpath):
166
"""Generate an internal absolute path."""
167
if relpath.find('..') != -1:
168
raise AssertionError('relpath contains ..')
170
return self._cwd[:-1]
171
if relpath.endswith('/'):
172
relpath = relpath[:-1]
173
return self._cwd + relpath
176
class MemoryServer(Server):
177
"""Server for the MemoryTransport for testing with."""
180
"""See bzrlib.transport.Server.setUp."""
181
self._scheme = "memory+%s:" % id(self)
182
register_transport(self._scheme, MemoryTransport)
185
"""See bzrlib.transport.Server.tearDown."""
186
# unregister this server
189
"""See bzrlib.transport.Server.get_url."""