aboutsummaryrefslogtreecommitdiffstats
path: root/doc/README.dev
blob: 2a09463b0d286c6935d8f61dda97ce32bc07c7f1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
Extending BE
============

To write a plugin, you simply create a new file in the becommands
directory.  Take a look at one of the simpler plugins (e.g. open.py)
for an example of how that looks, and to start getting a feel for the
libbe interface.

To fit into the current framework, your extension module should
provide the following elements:
  __desc__
    A short string describing the purpose of your plugin
  execute(args, manipulate_encodings=True, restrict_file_access=False,
          dir=".")
    The entry function for your plugin.  args is everything from
    sys.argv after the name of your plugin (e.g. for the command
    `be open abc', args=['abc']).

    manipulate_encodings should be passed through to any calls to
    bugdir.BugDir().  See the BugDir documentation for details.
    
    If restrict_file_access==True, you should call
      cmdutil.restrict_file_access(bugdir, path)
    before attempting to read or write a file.  See the
    restrict_file_access documentation for details.

    dir is a directory inside the repository of interest.

    Note: be supports command-completion.  To avoid raising errors you
    need to deal with possible '--complete' options and arguments.
    See the 'Command completion' section below for more information.
  help()
     Return the string to be output by `be help <yourplugin>',
     `be <yourplugin> --help', etc.

While that's all that's strictly necessary, many plugins (all the
current ones) use libbe.cmdutil.CmdOptionParser to provide a
consistent interface
  get_parser()
    Return an instance of CmdOptionParser("<usage string>").  You can
    alter the parser (e.g. add some more options) before returning it.

Again, you can just browse around in becommands to get a feel for things.


Testing
-------

Run any doctests in your plugin with
  be$ python test.py <yourplugin>
for example
  be$ python test.py merge


Command completion
------------------

BE implements a general framework to make it easy to support command
completion for arbitrary plugins.  In order to support this system,
all becommands should properly handle the '--complete' commandline
argument, returning a list of possible completions.  For example
  $ be --commands
      lists options accepted by be and the names of all available becommands.
  $ be list --commands
      lists options accepted by becommand/list
  $ be list --status --commands
      lists arguments accepted by the becommand/list --status option
  $ be show -- --commands
      lists possible vals for the first positional argument of becommand/show
This is a lot of information, but command-line completion is really
convenient for the user.  See becommand/list.py and becommand/show.py
for example implementations.  The basic idea is to raise
  cmdutil.GetCompletions(['list','of','possible','completions'])
once you've determined what that list should be.

However, command completion is not critical.  The first priority is to
implement the target functionality, with fancy shell sugar coming
later.  In recognition of this, cmdutil provides the default_complete
function which ensures that if '--complete' is any one of the
arguments, options, or option-arguments, GetCompletions will be raised
with and empty list.

Profiling
=========

Find out which 20 calls take the most cumulative time (time of
execution + childrens' times).

  $ python -m cProfile -o profile be [command] [args]
  $ python -c "import pstats; p=pstats.Stats('profile'); p.sort_stats('cumulative').print_stats(20)"

It's often useful to toss a
  import sys, traceback
  print >> sys.stderr, '-'*60, '\n', '\n'.join(traceback.format_stack()[-10:])
into expensive functions (e.g. libbe.util.subproc.invoke()), if you're
not sure why they're being called.