progress bar redesign

Robert Collins robertc at robertcollins.net
Mon Nov 19 21:57:09 GMT 2007


So, I looked at making progress show the most recent bar easily, and I
think the module is a little ripe. So here's a sketch of what I think
might be nice as a replacement design, which I'm going to start hacking
on now. I don't plan to fix all the glitches, but I think the design I'm
proposing will make it easier to experiment and do things like have
non-linear weighting between phases. I'd like a critique on this please.

UI:

TaskDisplay
 - use case - display task information to the user
 - holds a task
 - shows the task, messages, clears screen etc.
 - may be subclassed to deal with specific task types (e.g. if we want
   to support rendering a plain CountedTask we can do that)

Core:
CountedTask
 - use case - tracking tasks where we don't know the total amount of
   work needed, only that work is being done. E.g. downloading a byte
   stream.
 - a task that is being worked on
 - has a static message e.g. 'fetching' or 'reading index'.
 - has a current counter
 - has a tick_size
 - has a tick() that just advances the current counter by tick_size and 
   returns current
 - has a render_counter() method, so we can do things like '204 bytes'
   and 'depth 2' for different things being counted.
   (This might actually belong in a separate side-class, dunno yet)

There are a number of useful task decorators/subclasses

KnownLengthTask(CountedTask)
 - use case - tracking tasks where we know a priori (or early on) the
   total amount of work needed for the task.
 - adds a total counter to a task, and can give percentage complete etc.

TaskStack(KnownLengthTask)
 - use case - handling the ability to give feedback from different
   layers in bzrlib without needing global information.
 - handles a stack of sub tasks
 - accepts subtasks and sets their tick_size to match the stacks needs
 - when a task is removed the newly exposed task is advanced.

RateEstimator(object)
 - use case - bytes per second download counter
 - decorates a Task to provide rate estimates by examining the return of
   tick()

TaskTimer(RateEstimator)
 - use case - provide ETA/Elapsed time figures
 - adds a start time, and guesses at eta using KnownLengthTask's api.


Client API:

ProgressBar(object)
 - use case - provide a simple api for use by code in bzrlib
 - holds a TaskDisplay and a Task.
 - offers clear(), update(), tick(), message(), finished()
 - returned by the ui get_nested_progress_bar api.


Examples:

So for fetching, at runtime we might have:
in WorkingTree.pull (top level call):
a pb holding a TTYTaskDisplay, and the root TaskStack, with message
'Pulling', and total 2 (1 for branch pull, 1 for the merge)
in branch.pull (first level down):
a pb holding the same TTYTaskDisplay, and a nested KnownLengthTask with
message 'Pulling' and length 3 (1 for determining if we will pull, 1 for
repo data fetching, and 1 for updating tags). The task will have had its
tick_size set to 0.33 (1 from the top, and 1/3 in the child).
in repository.fetch (second level down):
a pb holding the same TTYTaskDisplay, and a further nested
KnownLengthTask with message 'Transferring' and length 2 (1 for
spidering out history to determine the revisions to copy, 1 for the copy
itself). The tick_size here will be 0.165 (1/2 of 0.33)
in repository.missing_revisions(third level down):
a pb with the same TTYTaskDisplay, and a nested CountedTask instance
with message 'find revisions'. We don't know how much has to be read to
spider the revisions, so we just count the history depth we've read,
it's tick_size will be set to 1.

Now, for display there are several interesting things. We don't want to
show 4 text strings:
'pulling/pulling/transferring/find revisions'
is quite long, and further nesting would start to jump around hugely. In
fact, the WT element on the stack is only interesting so that we give
monotonically increasing progress when a bar is shown. The overall
operation name is interesting. And I think the lowest level operation is
probably something we can make be interesting with a little thought. 

So for this case, I'd like bzr to show:
/ [======              ] Pulling [0.17/2]:Find revisions [depth 304]


What do you all think?

-Rob

-- 
GPG key available at: <http://www.robertcollins.net/keys.txt>.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20071120/b623cf61/attachment.pgp 


More information about the bazaar mailing list