~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to doc/developers/HACKING.txt

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-10 06:09:30 UTC
  • mfrom: (5409.4.1 ui-factory)
  • Revision ID: pqm@pqm.ubuntu.com-20100910060930-0ukm0h7txwadstll
(mbp) split out ui-factory docs (Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
359
359
can't fix.
360
360
 
361
361
 
362
 
Getting Input
363
 
=============
364
 
 
365
 
Processing Command Lines
366
 
------------------------
367
 
 
368
 
bzrlib has a standard framework for parsing command lines and calling
369
 
processing routines associated with various commands. See builtins.py
370
 
for numerous examples.
371
 
 
372
 
 
373
 
Standard Parameter Types
374
 
------------------------
375
 
 
376
 
There are some common requirements in the library: some parameters need to be
377
 
unicode safe, some need byte strings, and so on. At the moment we have
378
 
only codified one specific pattern: Parameters that need to be unicode
379
 
should be checked via ``bzrlib.osutils.safe_unicode``. This will coerce the
380
 
input into unicode in a consistent fashion, allowing trivial strings to be
381
 
used for programmer convenience, but not performing unpredictably in the
382
 
presence of different locales.
383
 
 
384
 
 
385
 
Writing Output
386
 
==============
387
 
 
388
 
(The strategy described here is what we want to get to, but it's not
389
 
consistently followed in the code at the moment.)
390
 
 
391
 
bzrlib is intended to be a generically reusable library.  It shouldn't
392
 
write messages to stdout or stderr, because some programs that use it
393
 
might want to display that information through a GUI or some other
394
 
mechanism.
395
 
 
396
 
We can distinguish two types of output from the library:
397
 
 
398
 
 1. Structured data representing the progress or result of an
399
 
    operation.  For example, for a commit command this will be a list
400
 
    of the modified files and the finally committed revision number
401
 
    and id.
402
 
 
403
 
    These should be exposed either through the return code or by calls
404
 
    to a callback parameter.
405
 
 
406
 
    A special case of this is progress indicators for long-lived
407
 
    operations, where the caller should pass a ProgressBar object.
408
 
 
409
 
 2. Unstructured log/debug messages, mostly for the benefit of the
410
 
    developers or users trying to debug problems.  This should always
411
 
    be sent through ``bzrlib.trace`` and Python ``logging``, so that
412
 
    it can be redirected by the client.
413
 
 
414
 
The distinction between the two is a bit subjective, but in general if
415
 
there is any chance that a library would want to see something as
416
 
structured data, we should make it so.
417
 
 
418
 
The policy about how output is presented in the text-mode client
419
 
should be only in the command-line tool.
420
 
 
421
 
 
422
 
Progress and Activity Indications
423
 
---------------------------------
424
 
 
425
 
bzrlib has a way for code to display to the user that stuff is happening
426
 
during a long operation.  There are two particular types: *activity* which
427
 
means that IO is happening on a Transport, and *progress* which means that
428
 
higher-level application work is occurring.  Both are drawn together by
429
 
the `ui_factory`.
430
 
 
431
 
Transport objects are responsible for calling `report_transport_activity`
432
 
when they do IO.
433
 
 
434
 
Progress uses a model/view pattern: application code acts on a
435
 
`ProgressTask` object, which notifies the UI when it needs to be
436
 
displayed.  Progress tasks form a stack.  To create a new progress task on
437
 
top of the stack, call `bzrlib.ui.ui_factory.nested_progress_bar()`, then
438
 
call `update()` on the returned ProgressTask.  It can be updated with just
439
 
a text description, with a numeric count, or with a numeric count and
440
 
expected total count.  If an expected total count is provided the view
441
 
can show the progress moving along towards the expected total.
442
 
 
443
 
The user should call `finish` on the `ProgressTask` when the logical
444
 
operation has finished, so it can be removed from the stack.
445
 
 
446
 
Progress tasks have a complex relationship with generators: it's a very
447
 
good place to use them, but because python2.4 does not allow ``finally``
448
 
blocks in generators it's hard to clean them up properly.  In this case
449
 
it's probably better to have the code calling the generator allocate a
450
 
progress task for its use and then call `finalize` when it's done, which
451
 
will close it if it was not already closed.  The generator should also
452
 
finish the progress task when it exits, because it may otherwise be a long
453
 
time until the finally block runs.
454
 
 
455
 
 
456
 
Message guidelines
457
 
------------------
458
 
 
459
 
When filenames or similar variables are presented inline within a message,
460
 
they should be enclosed in double quotes (ascii 0x22, not chiral unicode
461
 
quotes)::
462
 
 
463
 
  bzr: ERROR: No such file "asdf"
464
 
 
465
 
When we print just a list of filenames there should not be any quoting:
466
 
see `bug 544297`_.
467
 
 
468
 
.. _bug 544297: https://bugs.launchpad.net/bugs/544297
469
 
 
470
 
https://wiki.ubuntu.com/UnitsPolicy provides a good explanation about
471
 
which unit should be used when. Roughly speaking, IEC standard applies
472
 
for base-2 units and SI standard applies for base-10 units:
473
 
 
474
 
* for network bandwidth and disk sizes, use base-10 (Mbits/s, kB/s, GB)
475
 
 
476
 
* for RAM sizes, use base-2 (GiB, TiB)
477
 
 
478
 
 
479
 
 
480
 
Displaying help
481
 
===============
482
 
 
483
 
Bazaar has online help for various topics through ``bzr help COMMAND`` or
484
 
equivalently ``bzr command -h``.  We also have help on command options,
485
 
and on other help topics.  (See ``help_topics.py``.)
486
 
 
487
 
As for python docstrings, the first paragraph should be a single-sentence
488
 
synopsis of the command. These are user-visible and should be prefixed with
489
 
``__doc__ =`` so help works under ``python -OO`` with docstrings stripped.
490
 
 
491
 
The help for options should be one or more proper sentences, starting with
492
 
a capital letter and finishing with a full stop (period).
493
 
 
494
 
All help messages and documentation should have two spaces between
495
 
sentences.
496
 
 
497
 
 
498
 
Handling Errors and Exceptions
499
 
==============================
500
 
 
501
 
Commands should return non-zero when they encounter circumstances that
502
 
the user should really pay attention to - which includes trivial shell
503
 
pipelines.
504
 
 
505
 
Recommended values are:
506
 
 
507
 
    0. OK.
508
 
    1. Conflicts in merge-like operations, or changes are present in
509
 
       diff-like operations.
510
 
    2. Unrepresentable diff changes (i.e. binary files that we cannot show
511
 
       a diff of).
512
 
    3. An error or exception has occurred.
513
 
    4. An internal error occurred (one that shows a traceback.)
514
 
 
515
 
Errors are handled through Python exceptions. Exceptions should be defined
516
 
inside bzrlib.errors, so that we can see the whole tree at a glance.
517
 
 
518
 
We broadly classify errors as either being either internal or not,
519
 
depending on whether ``internal_error`` is set or not.  If we think it's our
520
 
fault, we show a backtrace, an invitation to report the bug, and possibly
521
 
other details.  This is the default for errors that aren't specifically
522
 
recognized as being caused by a user error.  Otherwise we show a briefer
523
 
message, unless -Derror was given.
524
 
 
525
 
Many errors originate as "environmental errors" which are raised by Python
526
 
or builtin libraries -- for example IOError.  These are treated as being
527
 
our fault, unless they're caught in a particular tight scope where we know
528
 
that they indicate a user errors.  For example if the repository format
529
 
is not found, the user probably gave the wrong path or URL.  But if one of
530
 
the files inside the repository is not found, then it's our fault --
531
 
either there's a bug in bzr, or something complicated has gone wrong in
532
 
the environment that means one internal file was deleted.
533
 
 
534
 
Many errors are defined in ``bzrlib/errors.py`` but it's OK for new errors
535
 
to be added near the place where they are used.
536
 
 
537
 
Exceptions are formatted for the user by conversion to a string
538
 
(eventually calling their ``__str__`` method.)  As a convenience the
539
 
``._fmt`` member can be used as a template which will be mapped to the
540
 
error's instance dict.
541
 
 
542
 
New exception classes should be defined when callers might want to catch
543
 
that exception specifically, or when it needs a substantially different
544
 
format string.
545
 
 
546
 
#. If it is something that a caller can recover from, a custom exception
547
 
   is reasonable.
548
 
 
549
 
#. If it is a data consistency issue, using a builtin like
550
 
   ``ValueError``/``TypeError`` is reasonable.
551
 
 
552
 
#. If it is a programmer error (using an api incorrectly)
553
 
   ``AssertionError`` is reasonable.
554
 
 
555
 
#. Otherwise, use ``BzrError`` or ``InternalBzrError``.
556
 
 
557
 
Exception strings should start with a capital letter and should not have a
558
 
final fullstop.  If long, they may contain newlines to break the text.
559
 
 
560
 
 
561
 
 
562
362
Documenting Changes
563
363
===================
564
364