~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to doc/developers/ui.txt

  • Committer: Martin Pool
  • Date: 2005-04-28 07:24:55 UTC
  • Revision ID: mbp@sourcefrog.net-20050428072453-7b99afa993a1e549
todo

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
=========================
2
 
Interacting with the user
3
 
=========================
4
 
 
5
 
Getting Input
6
 
=============
7
 
 
8
 
Processing Command Lines
9
 
------------------------
10
 
 
11
 
bzrlib has a standard framework for parsing command lines and calling
12
 
processing routines associated with various commands. See builtins.py
13
 
for numerous examples.
14
 
 
15
 
 
16
 
Standard Parameter Types
17
 
------------------------
18
 
 
19
 
There are some common requirements in the library: some parameters need to be
20
 
unicode safe, some need byte strings, and so on. At the moment we have
21
 
only codified one specific pattern: Parameters that need to be unicode
22
 
should be checked via ``bzrlib.osutils.safe_unicode``. This will coerce the
23
 
input into unicode in a consistent fashion, allowing trivial strings to be
24
 
used for programmer convenience, but not performing unpredictably in the
25
 
presence of different locales.
26
 
 
27
 
Confirmation
28
 
============
29
 
 
30
 
There are some operations, such as uncommitting, or breaking a lock, where
31
 
bzr may want to get confirmation from the user before proceeding.
32
 
However in some circumstances bzr should just go ahead without asking: if
33
 
it's being used from a noninteractive program, or if the user's asked to
34
 
never be asked for this particular confirmation or for any confirmations
35
 
at all.
36
 
 
37
 
We provide a special UIFactory method `confirm_action` to do this.  It
38
 
takes a `confirmation_id` parameter that acts as a symbolic name for the
39
 
type of confirmation, so the user can configure them off.  (This is not
40
 
implemented at present.)  GUIs can have a "don't ask me again" option
41
 
keyed by the confirmation id.
42
 
 
43
 
Confirmation ids look like Python paths to the logical code that should
44
 
use them.  (Because code may move or the check may for implementation
45
 
reasons be done elsewhere, they need not perfectly correspond to the place
46
 
they're used, and they should stay stable even when the code moves.)
47
 
 
48
 
``bzrlib.builtins.uncommit``
49
 
    Before the ``uncommit`` command actually changes the branch.
50
 
 
51
 
``bzrlib.lockdir.break``
52
 
    Before breaking a lock.
53
 
 
54
 
``bzrlib.msgeditor.unchanged``
55
 
    Proceed even though the user made no changes to the template message.
56
 
 
57
 
Interactive confirmations can be overridden by using a
58
 
`ConfirmationUserInterfacePolicy` decorator as the default
59
 
ui_factory.
60
 
 
61
 
 
62
 
Writing Output
63
 
==============
64
 
 
65
 
(The strategy described here is what we want to get to, but it's not
66
 
consistently followed in the code at the moment.)
67
 
 
68
 
bzrlib is intended to be a generically reusable library.  It shouldn't
69
 
write messages to stdout or stderr, because some programs that use it
70
 
might want to display that information through a GUI or some other
71
 
mechanism.
72
 
 
73
 
We can distinguish two types of output from the library:
74
 
 
75
 
 1. Structured data representing the progress or result of an
76
 
    operation.  For example, for a commit command this will be a list
77
 
    of the modified files and the finally committed revision number
78
 
    and id.
79
 
 
80
 
    These should be exposed either through the return code or by calls
81
 
    to a callback parameter.
82
 
 
83
 
    A special case of this is progress indicators for long-lived
84
 
    operations, where the caller should pass a ProgressBar object.
85
 
 
86
 
 2. Unstructured log/debug messages, mostly for the benefit of the
87
 
    developers or users trying to debug problems.  This should always
88
 
    be sent through ``bzrlib.trace`` and Python ``logging``, so that
89
 
    it can be redirected by the client.
90
 
 
91
 
The distinction between the two is a bit subjective, but in general if
92
 
there is any chance that a library would want to see something as
93
 
structured data, we should make it so.
94
 
 
95
 
The policy about how output is presented in the text-mode client
96
 
should be only in the command-line tool.
97
 
 
98
 
 
99
 
Progress and Activity Indications
100
 
---------------------------------
101
 
 
102
 
bzrlib has a way for code to display to the user that stuff is happening
103
 
during a long operation.  There are two particular types: *activity* which
104
 
means that IO is happening on a Transport, and *progress* which means that
105
 
higher-level application work is occurring.  Both are drawn together by
106
 
the `ui_factory`.
107
 
 
108
 
Transport objects are responsible for calling `report_transport_activity`
109
 
when they do IO.
110
 
 
111
 
Progress uses a model/view pattern: application code acts on a
112
 
`ProgressTask` object, which notifies the UI when it needs to be
113
 
displayed.  Progress tasks form a stack.  To create a new progress task on
114
 
top of the stack, call `bzrlib.ui.ui_factory.nested_progress_bar()`, then
115
 
call `update()` on the returned ProgressTask.  It can be updated with just
116
 
a text description, with a numeric count, or with a numeric count and
117
 
expected total count.  If an expected total count is provided the view
118
 
can show the progress moving along towards the expected total.
119
 
 
120
 
The user should call `finish` on the `ProgressTask` when the logical
121
 
operation has finished, so it can be removed from the stack.
122
 
 
123
 
Progress tasks have a complex relationship with generators: it's a very
124
 
good place to use them, but because python2.4 does not allow ``finally``
125
 
blocks in generators it's hard to clean them up properly.  In this case
126
 
it's probably better to have the code calling the generator allocate a
127
 
progress task for its use and then call `finalize` when it's done, which
128
 
will close it if it was not already closed.  The generator should also
129
 
finish the progress task when it exits, because it may otherwise be a long
130
 
time until the finally block runs.
131
 
 
132
 
 
133
 
Message guidelines
134
 
------------------
135
 
 
136
 
When filenames or similar variables are presented inline within a message,
137
 
they should be enclosed in double quotes (ascii 0x22, not chiral unicode
138
 
quotes)::
139
 
 
140
 
  bzr: ERROR: No such file "asdf"
141
 
 
142
 
When we print just a list of filenames there should not be any quoting:
143
 
see `bug 544297`_.
144
 
 
145
 
.. _bug 544297: https://bugs.launchpad.net/bugs/544297
146
 
 
147
 
https://wiki.ubuntu.com/UnitsPolicy provides a good explanation about
148
 
which unit should be used when. Roughly speaking, IEC standard applies
149
 
for base-2 units and SI standard applies for base-10 units:
150
 
 
151
 
* for network bandwidth and disk sizes, use base-10 (Mbits/s, kB/s, GB)
152
 
 
153
 
* for RAM sizes, use base-2 (GiB, TiB)
154
 
 
155
 
 
156
 
 
157
 
Displaying help
158
 
===============
159
 
 
160
 
Bazaar has online help for various topics through ``bzr help COMMAND`` or
161
 
equivalently ``bzr command -h``.  We also have help on command options,
162
 
and on other help topics.  (See ``help_topics.py``.)
163
 
 
164
 
As for python docstrings, the first paragraph should be a single-sentence
165
 
synopsis of the command. These are user-visible and should be prefixed with
166
 
``__doc__ =`` so help works under ``python -OO`` with docstrings stripped.
167
 
 
168
 
The help for options should be one or more proper sentences, starting with
169
 
a capital letter and finishing with a full stop (period).
170
 
 
171
 
All help messages and documentation should have two spaces between
172
 
sentences.
173
 
 
174
 
 
175
 
Handling Errors and Exceptions
176
 
==============================
177
 
 
178
 
Commands should return non-zero when they encounter circumstances that
179
 
the user should really pay attention to - which includes trivial shell
180
 
pipelines.
181
 
 
182
 
Recommended values are:
183
 
 
184
 
    0. OK.
185
 
    1. Conflicts in merge-like operations, or changes are present in
186
 
       diff-like operations.
187
 
    2. Unrepresentable diff changes (i.e. binary files that we cannot show
188
 
       a diff of).
189
 
    3. An error or exception has occurred.
190
 
    4. An internal error occurred (one that shows a traceback.)
191
 
 
192
 
Errors are handled through Python exceptions. Exceptions should be defined
193
 
inside bzrlib.errors, so that we can see the whole tree at a glance.
194
 
 
195
 
We broadly classify errors as either being either internal or not,
196
 
depending on whether ``internal_error`` is set or not.  If we think it's our
197
 
fault, we show a backtrace, an invitation to report the bug, and possibly
198
 
other details.  This is the default for errors that aren't specifically
199
 
recognized as being caused by a user error.  Otherwise we show a briefer
200
 
message, unless -Derror was given.
201
 
 
202
 
Many errors originate as "environmental errors" which are raised by Python
203
 
or builtin libraries -- for example IOError.  These are treated as being
204
 
our fault, unless they're caught in a particular tight scope where we know
205
 
that they indicate a user errors.  For example if the repository format
206
 
is not found, the user probably gave the wrong path or URL.  But if one of
207
 
the files inside the repository is not found, then it's our fault --
208
 
either there's a bug in bzr, or something complicated has gone wrong in
209
 
the environment that means one internal file was deleted.
210
 
 
211
 
Many errors are defined in ``bzrlib/errors.py`` but it's OK for new errors
212
 
to be added near the place where they are used.
213
 
 
214
 
Exceptions are formatted for the user by conversion to a string
215
 
(eventually calling their ``__str__`` method.)  As a convenience the
216
 
``._fmt`` member can be used as a template which will be mapped to the
217
 
error's instance dict.
218
 
 
219
 
New exception classes should be defined when callers might want to catch
220
 
that exception specifically, or when it needs a substantially different
221
 
format string.
222
 
 
223
 
#. If it is something that a caller can recover from, a custom exception
224
 
   is reasonable.
225
 
 
226
 
#. If it is a data consistency issue, using a builtin like
227
 
   ``ValueError``/``TypeError`` is reasonable.
228
 
 
229
 
#. If it is a programmer error (using an api incorrectly)
230
 
   ``AssertionError`` is reasonable.
231
 
 
232
 
#. Otherwise, use ``BzrError`` or ``InternalBzrError``.
233
 
 
234
 
Exception strings should start with a capital letter and should not have a
235
 
final fullstop.  If long, they may contain newlines to break the text.