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