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 traces transport operations.
20
20
and then delegates it.
23
from bzrlib.transport.decorator import TransportDecorator, DecoratorServer
26
class TransportTraceDecorator(TransportDecorator):
23
from __future__ import absolute_import
25
from bzrlib.transport import decorator
28
class TransportTraceDecorator(decorator.TransportDecorator):
27
29
"""A tracing decorator for Transports.
29
31
Calls that potentially perform IO are logged to self._activity. The
34
36
operation please add a test to the tests of this transport, for the logging
35
37
of the operation you want logged.
37
Another future enhancement would be to log to bzrlib.trace.mutter when
38
trace+ is used from the command line (or perhaps as well/instead use
39
-Dtransport), to make tracing operations of the entire program easily.
39
See also TransportLogDecorator, that records a machine-readable log in
40
memory for eg testing.
42
43
def __init__(self, url, _decorated=None, _from_transport=None):
43
44
"""Set the 'base' path where files will be stored.
45
46
_decorated is a private parameter for cloning.
47
TransportDecorator.__init__(self, url, _decorated)
48
super(TransportTraceDecorator, self).__init__(url, _decorated)
48
49
if _from_transport is None:
50
51
self._activity = []
63
64
def delete(self, relpath):
64
65
"""See Transport.delete()."""
66
self._activity.append(('delete', relpath))
65
67
return self._decorated.delete(relpath)
67
69
def delete_tree(self, relpath):
76
78
def get(self, relpath):
77
79
"""See Transport.get()."""
78
self._activity.append(('get', relpath))
80
self._trace(('get', relpath))
79
81
return self._decorated.get(relpath)
81
83
def get_smart_client(self):
92
94
def mkdir(self, relpath, mode=None):
93
95
"""See Transport.mkdir()."""
96
self._trace(('mkdir', relpath, mode))
94
97
return self._decorated.mkdir(relpath, mode)
96
99
def open_write_stream(self, relpath, mode=None):
100
103
def put_file(self, relpath, f, mode=None):
101
104
"""See Transport.put_file()."""
102
105
return self._decorated.put_file(relpath, f, mode)
104
107
def put_bytes(self, relpath, bytes, mode=None):
105
108
"""See Transport.put_bytes()."""
106
self._activity.append(('put_bytes', relpath, len(bytes), mode))
109
self._trace(('put_bytes', relpath, len(bytes), mode))
107
110
return self._decorated.put_bytes(relpath, bytes, mode)
112
def put_bytes_non_atomic(self, relpath, bytes, mode=None,
113
create_parent_dir=False, dir_mode=None):
114
"""See Transport.put_bytes_non_atomic."""
115
self._trace(('put_bytes_non_atomic', relpath, len(bytes), mode,
116
create_parent_dir, dir_mode))
117
return self._decorated.put_bytes_non_atomic(relpath, bytes, mode=mode,
118
create_parent_dir=create_parent_dir, dir_mode=dir_mode)
109
120
def listable(self):
110
121
"""See Transport.listable."""
111
122
return self._decorated.listable()
113
124
def iter_files_recursive(self):
114
125
"""See Transport.iter_files_recursive()."""
115
126
return self._decorated.iter_files_recursive()
117
128
def list_dir(self, relpath):
118
129
"""See Transport.list_dir()."""
119
130
return self._decorated.list_dir(relpath)
121
132
def readv(self, relpath, offsets, adjust_for_latency=False,
122
133
upper_limit=None):
123
"""See Transport.readv."""
124
self._activity.append(('readv', relpath, offsets, adjust_for_latency,
134
# we override at the readv() level rather than _readv() so that any
135
# latency adjustments will be done by the underlying transport
136
self._trace(('readv', relpath, offsets, adjust_for_latency,
126
138
return self._decorated.readv(relpath, offsets, adjust_for_latency,
131
143
return self._decorated.recommended_page_size()
133
145
def rename(self, rel_from, rel_to):
146
self._activity.append(('rename', rel_from, rel_to))
134
147
return self._decorated.rename(rel_from, rel_to)
136
149
def rmdir(self, relpath):
137
150
"""See Transport.rmdir."""
151
self._trace(('rmdir', relpath))
138
152
return self._decorated.rmdir(relpath)
140
154
def stat(self, relpath):
149
163
"""See Transport.lock_write."""
150
164
return self._decorated.lock_write(relpath)
153
class TraceServer(DecoratorServer):
154
"""Server for the TransportTraceDecorator for testing with."""
156
def get_decorator_class(self):
157
return TransportTraceDecorator
166
def _trace(self, operation_tuple):
167
"""Record that a transport operation occured.
169
:param operation: Tuple of transport call name and arguments.
171
self._activity.append(operation_tuple)
160
174
def get_test_permutations():
161
175
"""Return the permutations to be used in testing."""
162
return [(TransportTraceDecorator, TraceServer)]
176
from bzrlib.tests import test_server
177
return [(TransportTraceDecorator, test_server.TraceServer)]