/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/recordcounter.py

Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.

This is used to replace various ad hoc implementations of the same logic,
notably the version used in registry's _LazyObjectGetter which had a bug when
getting a module without also getting a member.  And of course, this new
function has unit tests, unlike the replaced code.

This also adds a KnownHooksRegistry subclass to provide a more natural home for
some other logic.

I'm not thrilled about the name of the new module or the new functions, but it's
hard to think of good names for such generic functionality.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2010 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
"""Record counting support for showing progress of revision fetch."""
 
17
 
 
18
 
 
19
class RecordCounter(object):
 
20
    """Container for maintains estimates of work requires for fetch.
 
21
 
 
22
    Instance of this class is used along with a progress bar to provide
 
23
    the user an estimate of the amount of work pending for a fetch (push,
 
24
    pull, branch, checkout) operation.
 
25
    """
 
26
    def __init__(self):
 
27
        self.initialized = False
 
28
        self.current = 0
 
29
        self.key_count = 0
 
30
        self.max = 0
 
31
 
 
32
        # Users of RecordCounter instance update progress bar every
 
33
        # _STEP_ records. We choose are reasonably high number to keep
 
34
        # display updates from being too frequent. This is an odd number
 
35
        # to ensure that the last digit of the records fetched in
 
36
        # fetches vs estimate ratio changes periodically.
 
37
        self.STEP = 7
 
38
 
 
39
    def is_initialized(self):
 
40
        return self.initialized
 
41
 
 
42
    def _estimate_max(self, key_count):
 
43
        """Estimate the maximum amount of 'inserting stream' work.
 
44
 
 
45
        This is just an estimate.
 
46
        """
 
47
        # Note: The magic number below is based of empirical data
 
48
        # based on 3 seperate projects. Estimatation can probably
 
49
        # be improved but this should work well for most cases.
 
50
        # The project used for the estimate (with approx. numbers) were:
 
51
        # lp:bzr with records_fetched = 7 * revs_required
 
52
        # lp:emacs with records_fetched = 8 * revs_required
 
53
        # bzr-svn checkout of lp:parrot = 10.63 * revs_required
 
54
        # Hence, 10.3 was chosen as for a realistic progress bar as:
 
55
        # 1. If records fetched is is lower than 10.3x then we simply complete
 
56
        #    with 10.3x. Under promise, over deliver.
 
57
        # 2. In case of remote fetch, when we start the count fetch vs estimate
 
58
        #    display with revs_required/estimate, having a multiplier with a
 
59
        #    decimal point produces a realistic looking _estimate_ number rather
 
60
        #    than using something like 3125/31250 (for 10x)
 
61
        # 3. Based on the above data, the possibility of overshooting this
 
62
        #    factor is minimal, and in case of an overshoot the estimate value
 
63
        #    should not need to be corrected too many times.
 
64
        return int(key_count * 10.3)
 
65
 
 
66
    def setup(self, key_count, current=0):
 
67
        """Setup RecordCounter with basic estimate of work pending.
 
68
 
 
69
        Setup self.max and self.current to reflect the amount of work
 
70
        pending for a fetch.
 
71
        """
 
72
        self.current = current
 
73
        self.key_count = key_count
 
74
        self.max = self._estimate_max(key_count)
 
75
        self.initialized = True
 
76
 
 
77
    def increment(self, count):
 
78
        """Increment self.current by count.
 
79
 
 
80
        Apart from incrementing self.current by count, also ensure
 
81
        that self.max > self.current.
 
82
        """
 
83
        self.current += count
 
84
        if self.current > self.max:
 
85
            self.max += self.key_count
 
86