5416.1.6
by Martin Pool
Change 'uncommit' command to use confirm_action not get_boolean |
1 |
========================= |
2 |
Interacting with the user |
|
3 |
========================= |
|
5409.4.1
by Martin Pool
Split out user interaction developer guide to a separate file |
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 |
||
5416.1.4
by Martin Pool
Brief developer guide entry about confirmations |
27 |
Confirmation |
5416.1.11
by Martin Pool
Add ConfirmationUserInterfacePolicy that lets specific confirmations be configured off. |
28 |
============ |
5416.1.4
by Martin Pool
Brief developer guide entry about confirmations |
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 |
|
5416.1.11
by Martin Pool
Add ConfirmationUserInterfacePolicy that lets specific confirmations be configured off. |
40 |
implemented at present.) GUIs can have a "don't ask me again" option |
41 |
keyed by the confirmation id. |
|
5416.1.4
by Martin Pool
Brief developer guide entry about confirmations |
42 |
|
5416.1.5
by Martin Pool
Add list of confirmation ids |
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 |
||
5416.1.10
by Martin Pool
Use confirm_action before proceeding with an unedited commit message template |
48 |
``bzrlib.builtins.uncommit`` |
49 |
Before the ``uncommit`` command actually changes the branch. |
|
50 |
||
5416.1.6
by Martin Pool
Change 'uncommit' command to use confirm_action not get_boolean |
51 |
``bzrlib.lockdir.break`` |
5416.1.5
by Martin Pool
Add list of confirmation ids |
52 |
Before breaking a lock. |
53 |
||
5416.1.10
by Martin Pool
Use confirm_action before proceeding with an unedited commit message template |
54 |
``bzrlib.msgeditor.unchanged`` |
55 |
Proceed even though the user made no changes to the template message. |
|
5416.1.6
by Martin Pool
Change 'uncommit' command to use confirm_action not get_boolean |
56 |
|
5416.1.11
by Martin Pool
Add ConfirmationUserInterfacePolicy that lets specific confirmations be configured off. |
57 |
Interactive confirmations can be overridden by using a |
58 |
`ConfirmationUserInterfacePolicy` decorator as the default |
|
59 |
ui_factory. |
|
60 |
||
5409.4.1
by Martin Pool
Split out user interaction developer guide to a separate file |
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. |