~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

  • Committer: Andrew Bennetts
  • Date: 2009-07-27 05:35:00 UTC
  • mfrom: (4570 +trunk)
  • mto: (4634.6.29 2.0)
  • mto: This revision was merged to the branch mainline in revision 4680.
  • Revision ID: andrew.bennetts@canonical.com-20090727053500-q76zsn2dx33jhmj5
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
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
16
16
 
17
17
 
18
18
"""Progress indicators.
25
25
import sys
26
26
import time
27
27
import os
28
 
import warnings
29
28
 
30
29
 
31
30
from bzrlib import (
32
31
    errors,
33
 
    osutils,
34
 
    trace,
35
 
    ui,
36
32
    )
37
33
from bzrlib.trace import mutter
38
34
from bzrlib.symbol_versioning import (
 
35
    deprecated_function,
39
36
    deprecated_in,
40
 
    deprecated_method,
41
37
    )
42
38
 
43
39
 
44
40
def _supports_progress(f):
45
 
    """Detect if we can use pretty progress bars on the output stream f.
 
41
    """Detect if we can use pretty progress bars on file F.
46
42
 
47
43
    If this returns true we expect that a human may be looking at that
48
44
    output, and that we can repaint a line to update it.
 
45
 
 
46
    This doesn't check the policy for whether we *should* use them.
49
47
    """
50
48
    isatty = getattr(f, 'isatty', None)
51
49
    if isatty is None:
52
50
        return False
53
51
    if not isatty():
54
52
        return False
 
53
    # The following case also handles Win32 - on that platform $TERM is
 
54
    # typically never set, so the case None is treated as a smart terminal,
 
55
    # not dumb.  <https://bugs.launchpad.net/bugs/334808>  win32 files do have
 
56
    # isatty methods that return true.
55
57
    if os.environ.get('TERM') == 'dumb':
56
58
        # e.g. emacs compile window
57
59
        return False
69
71
    will not necessarily respect all these fields.
70
72
    """
71
73
 
72
 
    def __init__(self, parent_task=None, ui_factory=None):
 
74
    def __init__(self, parent_task=None, ui_factory=None, progress_view=None):
 
75
        """Construct a new progress task.
 
76
 
 
77
        :param parent_task: Enclosing ProgressTask or None.
 
78
 
 
79
        :param progress_view: ProgressView to display this ProgressTask.
 
80
 
 
81
        :param ui_factory: The UI factory that will display updates; 
 
82
            deprecated in favor of passing progress_view directly.
 
83
 
 
84
        Normally you should not call this directly but rather through
 
85
        `ui_factory.nested_progress_bar`.
 
86
        """
73
87
        self._parent_task = parent_task
74
88
        self._last_update = 0
75
89
        self.total_cnt = None
76
90
        self.current_cnt = None
77
91
        self.msg = ''
 
92
        # TODO: deprecate passing ui_factory
78
93
        self.ui_factory = ui_factory
 
94
        self.progress_view = progress_view
79
95
        self.show_pct = False
80
96
        self.show_spinner = True
81
97
        self.show_eta = False,
94
110
        self.current_cnt = current_cnt
95
111
        if total_cnt:
96
112
            self.total_cnt = total_cnt
97
 
        self.ui_factory._progress_updated(self)
 
113
        if self.progress_view:
 
114
            self.progress_view.show_progress(self)
 
115
        else:
 
116
            self.ui_factory._progress_updated(self)
98
117
 
99
118
    def tick(self):
100
119
        self.update(self.msg)
101
120
 
102
121
    def finished(self):
103
 
        self.ui_factory._progress_finished(self)
 
122
        if self.progress_view:
 
123
            self.progress_view.task_finished(self)
 
124
        else:
 
125
            self.ui_factory._progress_finished(self)
104
126
 
105
127
    def make_sub_task(self):
106
 
        return ProgressTask(self, self.ui_factory)
 
128
        return ProgressTask(self, ui_factory=self.ui_factory,
 
129
            progress_view=self.progress_view)
107
130
 
108
131
    def _overall_completion_fraction(self, child_fraction=0.0):
109
132
        """Return fractional completion of this task and its parents
112
135
        if self.current_cnt is not None and self.total_cnt:
113
136
            own_fraction = (float(self.current_cnt) + child_fraction) / self.total_cnt
114
137
        else:
115
 
            own_fraction = None
 
138
            # if this task has no estimation, it just passes on directly
 
139
            # whatever the child has measured...
 
140
            own_fraction = child_fraction
116
141
        if self._parent_task is None:
117
142
            return own_fraction
118
143
        else:
130
155
 
131
156
    def clear(self):
132
157
        # XXX: shouldn't be here; put it in mutter or the ui instead
133
 
        self.ui_factory.clear_term()
134
 
 
135
 
 
 
158
        if self.progress_view:
 
159
            self.progress_view.clear()
 
160
        else:
 
161
            self.ui_factory.clear_term()
 
162
 
 
163
 
 
164
@deprecated_function(deprecated_in((1, 16, 0)))
136
165
def ProgressBar(to_file=None, **kwargs):
137
166
    """Abstract factory"""
138
167
    if to_file is None:
156
185
        return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
157
186
 
158
187
 
159
 
class ProgressBarStack(object):
160
 
    """A stack of progress bars.
161
 
 
162
 
    This class is deprecated: instead, ask the ui factory for a new progress
163
 
    task and finish it when it's done.
164
 
    """
165
 
 
166
 
    @deprecated_method(deprecated_in((1, 12, 0)))
167
 
    def __init__(self,
168
 
                 to_file=None,
169
 
                 show_pct=False,
170
 
                 show_spinner=True,
171
 
                 show_eta=False,
172
 
                 show_bar=True,
173
 
                 show_count=True,
174
 
                 to_messages_file=None,
175
 
                 klass=None):
176
 
        """Setup the stack with the parameters the progress bars should have."""
177
 
        if to_file is None:
178
 
            to_file = sys.stderr
179
 
        if to_messages_file is None:
180
 
            to_messages_file = sys.stdout
181
 
        self._to_file = to_file
182
 
        self._show_pct = show_pct
183
 
        self._show_spinner = show_spinner
184
 
        self._show_eta = show_eta
185
 
        self._show_bar = show_bar
186
 
        self._show_count = show_count
187
 
        self._to_messages_file = to_messages_file
188
 
        self._stack = []
189
 
        self._klass = klass or ProgressBar
190
 
 
191
 
    def top(self):
192
 
        if len(self._stack) != 0:
193
 
            return self._stack[-1]
194
 
        else:
195
 
            return None
196
 
 
197
 
    def bottom(self):
198
 
        if len(self._stack) != 0:
199
 
            return self._stack[0]
200
 
        else:
201
 
            return None
202
 
 
203
 
    def get_nested(self):
204
 
        """Return a nested progress bar."""
205
 
        if len(self._stack) == 0:
206
 
            func = self._klass
207
 
        else:
208
 
            func = self.top().child_progress
209
 
        new_bar = func(to_file=self._to_file,
210
 
                       show_pct=self._show_pct,
211
 
                       show_spinner=self._show_spinner,
212
 
                       show_eta=self._show_eta,
213
 
                       show_bar=self._show_bar,
214
 
                       show_count=self._show_count,
215
 
                       to_messages_file=self._to_messages_file,
216
 
                       _stack=self)
217
 
        self._stack.append(new_bar)
218
 
        return new_bar
219
 
 
220
 
    def return_pb(self, bar):
221
 
        """Return bar after its been used."""
222
 
        if bar is not self._stack[-1]:
223
 
            warnings.warn("%r is not currently active" % (bar,))
224
 
        else:
225
 
            self._stack.pop()
226
 
 
227
 
 
 
188
# NOTE: This is also deprecated; you should provide a ProgressView instead.
228
189
class _BaseProgressBar(object):
229
190
 
230
191
    def __init__(self,
271
232
        self.to_messages_file.write(fmt_string % args)
272
233
        self.to_messages_file.write('\n')
273
234
 
 
235
    @deprecated_function(deprecated_in((1, 16, 0)))
274
236
    def child_progress(self, **kwargs):
275
237
        return ChildProgress(**kwargs)
276
238
 
302
264
 
303
265
class DotsProgressBar(_BaseProgressBar):
304
266
 
 
267
    @deprecated_function(deprecated_in((1, 16, 0)))
305
268
    def __init__(self, **kwargs):
306
269
        _BaseProgressBar.__init__(self, **kwargs)
307
270
        self.last_msg = None
328
291
        self.tick()
329
292
 
330
293
 
331
 
 
332
 
 
333
294
class TTYProgressBar(_BaseProgressBar):
334
295
    """Progress bar display object.
335
296
 
352
313
    """
353
314
    SPIN_CHARS = r'/-\|'
354
315
 
355
 
 
 
316
    @deprecated_function(deprecated_in((1, 16, 0)))
356
317
    def __init__(self, **kwargs):
357
318
        from bzrlib.osutils import terminal_width
358
319
        _BaseProgressBar.__init__(self, **kwargs)
513
474
 
514
475
 
515
476
 
516
 
 
 
477
# DEPRECATED
517
478
class ChildProgress(_BaseProgressBar):
518
479
    """A progress indicator that pushes its data to the parent"""
519
480
 
 
481
    @deprecated_function(deprecated_in((1, 16, 0)))
520
482
    def __init__(self, _stack, **kwargs):
521
483
        _BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
522
484
        self.parent = _stack.top()
558
520
        self.parent.note(*args, **kwargs)
559
521
 
560
522
 
561
 
class InstrumentedProgress(TTYProgressBar):
562
 
    """TTYProgress variant that tracks outcomes"""
563
 
 
564
 
    def __init__(self, *args, **kwargs):
565
 
        self.always_throttled = True
566
 
        self.never_throttle = False
567
 
        TTYProgressBar.__init__(self, *args, **kwargs)
568
 
 
569
 
    def throttle(self, old_message):
570
 
        if self.never_throttle:
571
 
            result =  False
572
 
        else:
573
 
            result = TTYProgressBar.throttle(self, old_message)
574
 
        if result is False:
575
 
            self.always_throttled = False
576
 
 
577
 
 
578
523
def str_tdelta(delt):
579
524
    if delt is None:
580
525
        return "-:--:--"