/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/log.py

  • Committer: John Arbash Meinel
  • Date: 2009-12-22 16:28:47 UTC
  • mto: This revision was merged to the branch mainline in revision 4922.
  • Revision ID: john@arbash-meinel.com-20091222162847-tvnsc69to4l4uf5r
Implement a permute_for_extension helper.

Use it for all of the 'simple' extension permutations.
It basically permutes all tests in the current module, by setting TestCase.module.
Which works well for most of our extension tests. Some had more advanced
handling of permutations (extra permutations, custom vars, etc.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
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
 
16
 
 
17
"""Transport decorator that logs transport operations to .bzr.log."""
 
18
 
 
19
 
 
20
# see also the transportstats plugin, which gives you some summary information
 
21
# in a machine-readable dump
 
22
 
 
23
import StringIO
 
24
import cStringIO
 
25
import time
 
26
import types
 
27
 
 
28
from bzrlib.trace import mutter
 
29
from bzrlib.transport.decorator import (
 
30
    TransportDecorator,
 
31
    )
 
32
from bzrlib.transport.trace import (
 
33
    DecoratorServer,
 
34
    TransportTraceDecorator,
 
35
    )
 
36
 
 
37
 
 
38
 
 
39
 
 
40
class TransportLogDecorator(TransportDecorator):
 
41
    """Decorator for Transports that logs interesting operations to .bzr.log.
 
42
 
 
43
    In general we want to log things that usually take a network round trip
 
44
    and may be slow.
 
45
 
 
46
    Not all operations are logged yet.
 
47
 
 
48
    See also TransportTraceDecorator, that records a machine-readable log in 
 
49
    memory for eg testing.
 
50
    """
 
51
 
 
52
    def __init__(self, *args, **kw):
 
53
        super(TransportLogDecorator, self).__init__(*args, **kw)
 
54
        def _make_hook(hookname):
 
55
            def _hook(relpath, *args, **kw):
 
56
                return self._log_and_call(hookname, relpath, *args, **kw)
 
57
            return _hook
 
58
        for methodname in (
 
59
            'append_bytes',
 
60
            'append_file',
 
61
            'copy_to',
 
62
            'delete',
 
63
            'get',
 
64
            'has',
 
65
            'open_write_stream',
 
66
            'mkdir',
 
67
            'move',
 
68
            'put_bytes', 'put_bytes_non_atomic', 'put_file put_file_non_atomic',
 
69
            'list_dir', 'lock_read', 'lock_write',
 
70
            'readv', 'rename', 'rmdir',
 
71
            'stat',
 
72
            'ulock',
 
73
            ):
 
74
            setattr(self, methodname, _make_hook(methodname))
 
75
 
 
76
    @classmethod
 
77
    def _get_url_prefix(self):
 
78
        return 'log+'
 
79
 
 
80
    def iter_files_recursive(self):
 
81
        # needs special handling because it does not have a relpath parameter
 
82
        mutter("%s %s"
 
83
            % ('iter_files_recursive', self._decorated.base))
 
84
        return self._call_and_log_result('iter_files_recursive', (), {})
 
85
 
 
86
    def _log_and_call(self, methodname, relpath, *args, **kwargs):
 
87
        if kwargs:
 
88
            kwargs_str = dict(kwargs)
 
89
        else:
 
90
            kwargs_str = ''
 
91
        mutter("%s %s %s %s"
 
92
               % (methodname, self._decorated.abspath(relpath),
 
93
                  self._shorten(self._strip_tuple_parens(args)),
 
94
                  kwargs_str))
 
95
        return self._call_and_log_result(methodname, (relpath,) + args, kwargs)
 
96
 
 
97
    def _call_and_log_result(self, methodname, args, kwargs):
 
98
        before = time.time()
 
99
        try:
 
100
            result = getattr(self._decorated, methodname)(*args, **kwargs)
 
101
        except Exception, e:
 
102
            mutter("  --> %s" % e)
 
103
            mutter("      %.03fs" % (time.time() - before))
 
104
            raise
 
105
        return self._show_result(before, methodname, result)
 
106
 
 
107
    def _show_result(self, before, methodname, result):
 
108
        result_len = None
 
109
        if isinstance(result, types.GeneratorType):
 
110
            # We now consume everything from the generator so that we can show
 
111
            # the results and the time it took to get them.  However, to keep
 
112
            # compatibility with callers that may specifically expect a result
 
113
            # (see <https://launchpad.net/bugs/340347>) we also return a new
 
114
            # generator, reset to the starting position.
 
115
            result = list(result)
 
116
            return_result = iter(result)
 
117
        else:
 
118
            return_result = result
 
119
        if isinstance(result, (cStringIO.OutputType, StringIO.StringIO)):
 
120
            val = repr(result.getvalue())
 
121
            result_len = len(val)
 
122
            shown_result = "%s(%s) (%d bytes)" % (result.__class__.__name__,
 
123
                self._shorten(val), result_len)
 
124
        elif methodname == 'readv':
 
125
            num_hunks = len(result)
 
126
            total_bytes = sum((len(d) for o,d in result))
 
127
            shown_result = "readv response, %d hunks, %d total bytes" % (
 
128
                num_hunks, total_bytes)
 
129
            result_len = total_bytes
 
130
        else:
 
131
            shown_result = self._shorten(self._strip_tuple_parens(result))
 
132
        mutter("  --> %s" % shown_result)
 
133
        # The log decorator no longer shows the elapsed time or transfer rate
 
134
        # because they're available in the log prefixes and the transport
 
135
        # activity display respectively.
 
136
        if False:
 
137
            elapsed = time.time() - before
 
138
            if result_len and elapsed > 0:
 
139
                # this is the rate of higher-level data, not the raw network speed
 
140
                mutter("      %9.03fs %8dKB/s" % (elapsed, result_len/elapsed/1024))
 
141
            else:
 
142
                mutter("      %9.03fs" % (elapsed))
 
143
        return return_result
 
144
 
 
145
    def _shorten(self, x):
 
146
        if len(x) > 70:
 
147
            x = x[:67] + '...'
 
148
        return x
 
149
 
 
150
    def _strip_tuple_parens(self, t):
 
151
        t = repr(t)
 
152
        if t[0] == '(' and t[-1] == ')':
 
153
            t = t[1:-1]
 
154
        return t
 
155
 
 
156
 
 
157
class LogDecoratorServer(DecoratorServer):
 
158
    """Server for testing."""
 
159
 
 
160
    def get_decorator_class(self):
 
161
        return TransportLogDecorator
 
162
 
 
163
 
 
164
def get_test_permutations():
 
165
    """Return the permutations to be used in testing."""
 
166
    return [(TransportLogDecorator, LogDecoratorServer)]