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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Implementation of Transport that decorates another transport.
19
This does not change the transport behaviour at all, but provides all the
19
This does not change the transport behaviour at all, but provides all the
20
20
stub functions to allow other decorators to be written easily.
23
from bzrlib import transport
26
class TransportDecorator(transport.Transport):
23
from bzrlib.transport import get_transport, Transport, Server
26
class TransportDecorator(Transport):
27
27
"""A no-change decorator for Transports.
29
29
Subclasses of this are new transports that are based on an
30
underlying transport and can override or intercept some
31
behavior. For example ReadonlyTransportDecorator prevents
32
all write attempts, and FakeNFSTransportDecorator simulates
30
underlying transport and can override or intercept some
31
behavior. For example ReadonlyTransportDecorator prevents
32
all write attempts, and FakeNFSTransportDecorator simulates
35
35
This decorator class is not directly usable as a decorator:
37
37
method to return the url prefix for the subclass.
40
def __init__(self, url, _decorated=None, _from_transport=None):
41
"""Set the 'base' path of the transport.
43
:param _decorated: A private parameter for cloning.
44
:param _from_transport: Is available for subclasses that
45
need to share state across clones.
40
def __init__(self, url, _decorated=None):
41
"""Set the 'base' path where files will be stored.
43
_decorated is a private parameter for cloning."""
47
44
prefix = self._get_url_prefix()
48
if not url.startswith(prefix):
49
raise ValueError("url %r doesn't start with decorator prefix %r" %
51
not_decorated_url = url[len(prefix):]
45
assert url.startswith(prefix), \
46
"url %r doesn't start with decorator prefix %r" % \
48
decorated_url = url[len(prefix):]
52
49
if _decorated is None:
53
self._decorated = transport.get_transport(not_decorated_url)
50
self._decorated = get_transport(decorated_url)
55
52
self._decorated = _decorated
56
super(TransportDecorator, self).__init__(prefix + self._decorated.base)
53
super(TransportDecorator, self).__init__(
54
prefix + self._decorated.base)
58
56
def abspath(self, relpath):
59
57
"""See Transport.abspath()."""
60
58
return self._get_url_prefix() + self._decorated.abspath(relpath)
62
def append_file(self, relpath, f, mode=None):
63
"""See Transport.append_file()."""
64
return self._decorated.append_file(relpath, f, mode=mode)
66
def append_bytes(self, relpath, bytes, mode=None):
67
"""See Transport.append_bytes()."""
68
return self._decorated.append_bytes(relpath, bytes, mode=mode)
70
def _can_roundtrip_unix_modebits(self):
71
"""See Transport._can_roundtrip_unix_modebits()."""
72
return self._decorated._can_roundtrip_unix_modebits()
60
def append(self, relpath, f, mode=None):
61
"""See Transport.append()."""
62
return self._decorated.append(relpath, f, mode=mode)
74
64
def clone(self, offset=None):
75
65
"""See Transport.clone()."""
76
66
decorated_clone = self._decorated.clone(offset)
77
67
return self.__class__(
78
self._get_url_prefix() + decorated_clone.base, decorated_clone,
68
self._get_url_prefix() + decorated_clone.base, decorated_clone)
81
70
def delete(self, relpath):
82
71
"""See Transport.delete()."""
117
96
"""See Transport.mkdir()."""
118
97
return self._decorated.mkdir(relpath, mode)
120
def open_write_stream(self, relpath, mode=None):
121
"""See Transport.open_write_stream."""
122
return self._decorated.open_write_stream(relpath, mode=mode)
124
def put_file(self, relpath, f, mode=None):
125
"""See Transport.put_file()."""
126
return self._decorated.put_file(relpath, f, mode)
128
def put_bytes(self, relpath, bytes, mode=None):
129
"""See Transport.put_bytes()."""
130
return self._decorated.put_bytes(relpath, bytes, mode)
99
def put(self, relpath, f, mode=None):
100
"""See Transport.put()."""
101
return self._decorated.put(relpath, f, mode)
132
103
def listable(self):
133
104
"""See Transport.listable."""
134
105
return self._decorated.listable()
136
107
def iter_files_recursive(self):
137
108
"""See Transport.iter_files_recursive()."""
138
109
return self._decorated.iter_files_recursive()
140
111
def list_dir(self, relpath):
141
112
"""See Transport.list_dir()."""
142
113
return self._decorated.list_dir(relpath)
144
def _readv(self, relpath, offsets):
145
"""See Transport._readv."""
146
return self._decorated._readv(relpath, offsets)
148
def recommended_page_size(self):
149
"""See Transport.recommended_page_size()."""
150
return self._decorated.recommended_page_size()
152
115
def rename(self, rel_from, rel_to):
153
116
return self._decorated.rename(rel_from, rel_to)
155
118
def rmdir(self, relpath):
156
119
"""See Transport.rmdir."""
157
120
return self._decorated.rmdir(relpath)
122
def should_cache(self):
123
"""See Transport.should_cache()."""
124
return self._decorated.should_cache()
159
126
def stat(self, relpath):
160
127
"""See Transport.stat()."""
161
128
return self._decorated.stat(relpath)
168
135
"""See Transport.lock_write."""
169
136
return self._decorated.lock_write(relpath)
171
def _redirected_to(self, source, target):
172
redirected = self._decorated._redirected_to(source, target)
173
if redirected is not None:
174
return self.__class__(self._get_url_prefix() + redirected.base,
139
class DecoratorServer(Server):
140
"""Server for the TransportDecorator for testing with.
142
To use this when subclassing TransportDecorator, override override the
143
get_decorator_class method.
146
def setUp(self, server=None):
147
"""See bzrlib.transport.Server.setUp.
149
:server: decorate the urls given by server. If not provided a
150
LocalServer is created.
152
if server is not None:
153
self._made_server = False
154
self._server = server
156
from bzrlib.transport.local import LocalRelpathServer
157
self._made_server = True
158
self._server = LocalRelpathServer()
162
"""See bzrlib.transport.Server.tearDown."""
163
if self._made_server:
164
self._server.tearDown()
166
def get_decorator_class(self):
167
"""Return the class of the decorators we should be constructing."""
168
raise NotImplementedError(self.get_decorator_class)
170
def get_url_prefix(self):
171
"""What URL prefix does this decorator produce?"""
172
return self.get_decorator_class()._get_url_prefix()
174
def get_bogus_url(self):
175
"""See bzrlib.transport.Server.get_bogus_url."""
176
return self.get_url_prefix() + self._server.get_bogus_url()
179
"""See bzrlib.transport.Server.get_url."""
180
return self.get_url_prefix() + self._server.get_url()
180
183
def get_test_permutations():
181
184
"""Return the permutations to be used in testing.
183
186
The Decorator class is not directly usable, and testing it would not have
184
187
any benefit - its the concrete classes which need to be tested.