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 bzrlib.transport import decorator
26
class TransportTraceDecorator(decorator.TransportDecorator):
27
27
"""A tracing decorator for Transports.
29
29
Calls that potentially perform IO are logged to self._activity. The
34
34
operation please add a test to the tests of this transport, for the logging
35
35
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.
37
See also TransportLogDecorator, that records a machine-readable log in
38
memory for eg testing.
42
41
def __init__(self, url, _decorated=None, _from_transport=None):
43
42
"""Set the 'base' path where files will be stored.
45
44
_decorated is a private parameter for cloning.
47
TransportDecorator.__init__(self, url, _decorated)
46
super(TransportTraceDecorator, self).__init__(url, _decorated)
48
47
if _from_transport is None:
50
49
self._activity = []
63
62
def delete(self, relpath):
64
63
"""See Transport.delete()."""
64
self._activity.append(('delete', relpath))
65
65
return self._decorated.delete(relpath)
67
67
def delete_tree(self, relpath):
76
76
def get(self, relpath):
77
77
"""See Transport.get()."""
78
self._activity.append(('get', relpath))
78
self._trace(('get', relpath))
79
79
return self._decorated.get(relpath)
81
81
def get_smart_client(self):
92
92
def mkdir(self, relpath, mode=None):
93
93
"""See Transport.mkdir()."""
94
self._trace(('mkdir', relpath, mode))
94
95
return self._decorated.mkdir(relpath, mode)
96
97
def open_write_stream(self, relpath, mode=None):
100
101
def put_file(self, relpath, f, mode=None):
101
102
"""See Transport.put_file()."""
102
103
return self._decorated.put_file(relpath, f, mode)
104
105
def put_bytes(self, relpath, bytes, mode=None):
105
106
"""See Transport.put_bytes()."""
106
self._activity.append(('put_bytes', relpath, len(bytes), mode))
107
self._trace(('put_bytes', relpath, len(bytes), mode))
107
108
return self._decorated.put_bytes(relpath, bytes, mode)
110
def put_bytes_non_atomic(self, relpath, bytes, mode=None,
111
create_parent_dir=False, dir_mode=None):
112
"""See Transport.put_bytes_non_atomic."""
113
self._trace(('put_bytes_non_atomic', relpath, len(bytes), mode,
114
create_parent_dir, dir_mode))
115
return self._decorated.put_bytes_non_atomic(relpath, bytes, mode=mode,
116
create_parent_dir=create_parent_dir, dir_mode=dir_mode)
109
118
def listable(self):
110
119
"""See Transport.listable."""
111
120
return self._decorated.listable()
113
122
def iter_files_recursive(self):
114
123
"""See Transport.iter_files_recursive()."""
115
124
return self._decorated.iter_files_recursive()
117
126
def list_dir(self, relpath):
118
127
"""See Transport.list_dir()."""
119
128
return self._decorated.list_dir(relpath)
121
130
def readv(self, relpath, offsets, adjust_for_latency=False,
122
131
upper_limit=None):
123
"""See Transport.readv."""
124
self._activity.append(('readv', relpath, offsets, adjust_for_latency,
132
# we override at the readv() level rather than _readv() so that any
133
# latency adjustments will be done by the underlying transport
134
self._trace(('readv', relpath, offsets, adjust_for_latency,
126
136
return self._decorated.readv(relpath, offsets, adjust_for_latency,
131
141
return self._decorated.recommended_page_size()
133
143
def rename(self, rel_from, rel_to):
144
self._activity.append(('rename', rel_from, rel_to))
134
145
return self._decorated.rename(rel_from, rel_to)
136
147
def rmdir(self, relpath):
137
148
"""See Transport.rmdir."""
149
self._trace(('rmdir', relpath))
138
150
return self._decorated.rmdir(relpath)
140
152
def stat(self, relpath):
149
161
"""See Transport.lock_write."""
150
162
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
164
def _trace(self, operation_tuple):
165
"""Record that a transport operation occured.
167
:param operation: Tuple of transport call name and arguments.
169
self._activity.append(operation_tuple)
160
172
def get_test_permutations():
161
173
"""Return the permutations to be used in testing."""
162
return [(TransportTraceDecorator, TraceServer)]
174
from bzrlib.tests import test_server
175
return [(TransportTraceDecorator, test_server.TraceServer)]