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 = []
77
78
def get(self, relpath):
78
79
"""See Transport.get()."""
79
self._activity.append(('get', relpath))
80
self._trace(('get', relpath))
80
81
return self._decorated.get(relpath)
82
83
def get_smart_client(self):
93
94
def mkdir(self, relpath, mode=None):
94
95
"""See Transport.mkdir()."""
96
self._trace(('mkdir', relpath, mode))
95
97
return self._decorated.mkdir(relpath, mode)
97
99
def open_write_stream(self, relpath, mode=None):
101
103
def put_file(self, relpath, f, mode=None):
102
104
"""See Transport.put_file()."""
103
105
return self._decorated.put_file(relpath, f, mode)
105
107
def put_bytes(self, relpath, bytes, mode=None):
106
108
"""See Transport.put_bytes()."""
107
self._activity.append(('put_bytes', relpath, len(bytes), mode))
109
self._trace(('put_bytes', relpath, len(bytes), mode))
108
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)
110
120
def listable(self):
111
121
"""See Transport.listable."""
112
122
return self._decorated.listable()
114
124
def iter_files_recursive(self):
115
125
"""See Transport.iter_files_recursive()."""
116
126
return self._decorated.iter_files_recursive()
118
128
def list_dir(self, relpath):
119
129
"""See Transport.list_dir()."""
120
130
return self._decorated.list_dir(relpath)
122
132
def readv(self, relpath, offsets, adjust_for_latency=False,
123
133
upper_limit=None):
124
"""See Transport.readv."""
125
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,
127
138
return self._decorated.readv(relpath, offsets, adjust_for_latency,
134
145
def rename(self, rel_from, rel_to):
135
146
self._activity.append(('rename', rel_from, rel_to))
136
147
return self._decorated.rename(rel_from, rel_to)
138
149
def rmdir(self, relpath):
139
150
"""See Transport.rmdir."""
151
self._trace(('rmdir', relpath))
140
152
return self._decorated.rmdir(relpath)
142
154
def stat(self, relpath):
151
163
"""See Transport.lock_write."""
152
164
return self._decorated.lock_write(relpath)
155
class TraceServer(DecoratorServer):
156
"""Server for the TransportTraceDecorator for testing with."""
158
def get_decorator_class(self):
159
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)
162
174
def get_test_permutations():
163
175
"""Return the permutations to be used in testing."""
164
return [(TransportTraceDecorator, TraceServer)]
176
from bzrlib.tests import test_server
177
return [(TransportTraceDecorator, test_server.TraceServer)]