diff --git a/contrib/wix/help.wxs b/contrib/wix/help.wxs --- a/contrib/wix/help.wxs +++ b/contrib/wix/help.wxs @@ -47,6 +47,7 @@ + diff --git a/mercurial/help.py b/mercurial/help.py --- a/mercurial/help.py +++ b/mercurial/help.py @@ -311,6 +311,8 @@ internalstable = sorted([ loaddoc('changegroups', subdir='internals')), (['config'], _('Config Registrar'), loaddoc('config', subdir='internals')), + (['extensions', 'extension'], _('Extension API'), + loaddoc('extensions', subdir='internals')), (['requirements'], _('Repository Requirements'), loaddoc('requirements', subdir='internals')), (['revlogs'], _('Revision Logs'), diff --git a/mercurial/help/internals/extensions.txt b/mercurial/help/internals/extensions.txt new file mode 100644 --- /dev/null +++ b/mercurial/help/internals/extensions.txt @@ -0,0 +1,321 @@ +Extensions allow the creation of new features and using them directly from +the main hg command line as if they were built-in commands. The extensions +have full access to the *internal* API. + +Use of Mercurial's internal API very likely makes your code subject to +Mercurial's license. Before going any further, read the License page. + +There are NO guarantees that third-party code calling into Mercurial's +internals won't break from release to release. If you do use Mercurial's API +for published third-party code, we expect you to test your code before each +major Mercurial release. This will prevent various bug reports from your users +when they upgrade their copy of Mercurial. + +File Layout +=========== + +Extensions are usually written as simple python modules. Larger ones are +better split into multiple modules of a single package (see the convert +extension). The package root module gives its name to the extension and +implements the ``cmdtable`` and optional callbacks described below. + +Command table +============= + +To write your own extension, your python module can provide an optional dict +named ``cmdtable`` with entries describing each command. A command should be +registered to the ``cmdtable`` by ``@command`` decorator. + +Example using ``@command`` decorator (requires Mercurial 1.9):: + + from mercurial import cmdutil + from mercurial.i18n import _ + + cmdtable = {} + command = cmdutil.command(cmdtable) + + @command('print-parents', + [('s', 'short', None, _('print short form')), + ('l', 'long', None, _('print long form'))], + _('[options] node')) + def printparents(ui, repo, node, **opts): + ... + +The cmdtable dictionary +----------------------- + +The ``cmdtable`` dictionary uses as key the new command names, and, as value, +a tuple containing: + +1. the function to be called when the command is used. +2. a list of options the command can take. +3. a command line synopsis for the command (the function docstring is used for + the full help). + +List of options +--------------- + +All the command flag options are documented in the mercurial/fancyopts.py +sources. + +The options list is a list of tuples containing: + +1. the short option letter, or ``''`` if no short option is available + (for example, ``o`` for a ``-o`` option). +2. the long option name (for example, ``option`` for a ``--option`` option). +3. a default value for the option. +4. a help string for the option (it's possible to omit the "hg newcommand" + part and only the options and parameter substring is needed). + +Command function signatures +--------------------------- + +Functions that implement new commands always receive a ``ui`` and usually +a ``repo`` parameter. The rest of parameters are taken from the command line +items that don't start with a dash and are passed in the same order they were +written. If no default value is given in the parameter list they are required. + +If there is no repo to be associated with the command and consequently no +``repo`` passed, then ``norepo=True`` should be passed to the ``@command`` +decorator:: + + @command('mycommand', [], norepo=True) + def mycommand(ui, **opts): + ... + +For examples of ``norepo``, see the convert extension. + +Command function docstrings +=========================== + +The docstring of your function is used as the main help text, shown by +``hg help mycommand``. The docstring should be formatted using a simple +subset of reStructuredText markup. The supported constructs include: + +Paragraphs:: + + This is a paragraph. + + Paragraphs are separated + by blank lines. + +A verbatim block is introduced with a double colon followed by an indented +block. The double colon is turned into a single colon on display:: + + Some text:: + + verbatim + text + !! + +We have field lists:: + + :key1: value1 + :key2: value2 + +Bullet lists:: + + - foo + - bar + +Enumerated lists:: + + 1. foo + 2. bar + +Inline markup:: + + ``*bold*``, ``monospace``, :hg:`command` + +Mark Mercurial commands with ``:hg:`` to make a nice link to the corresponding +documentation. We'll expand the support if new constructs can be parsed +without too much trouble. + +Communicating with the user +=========================== + +Besides the ``ui`` methods, like ``ui.write(*msg)`` or +``ui.prompt(msg, default="y")``, an extension can add help text for each +of its commands and the extension itself. + +The module docstring will be used as help string when ``hg help extensionname`` +is used and, similarly, the help string for a command and the docstring +belonging to the function that's wrapped by the command will be shown when +``hg help command`` is invoked. + +Setup Callbacks +=============== + +Extensions are loaded in phases. All extensions are processed in a given phase +before the next phase begins. In the first phase, all extension modules are +loaded and registered with Mercurial. This means that you can find all enabled +extensions with ``extensions.find`` in the following phases. + +ui setup +-------- + +Extensions can implement an optional callback named ``uisetup``. ``uisetup`` +is called when the extension is first loaded and receives a ui object:: + + def uisetup(ui): + # ... + +Extension setup +--------------- + +Extensions can implement an optional callback named ``extsetup``. It is +called after all the extension are loaded, and can be useful in case one +extension optionally depends on another extension. Signature:: + + def extsetup(): + # ... + +Mercurial version 8e6019b16a7d and later (that is post-1.3.1) will pass +a ``ui``` argument to ``extsetup``:: + + def extsetup(ui): + # ... + +Command table setup +------------------- + +After ``extsetup``, the ``cmdtable`` is copied into the global command table +in Mercurial. + +Repository setup +---------------- + +Extensions can implement an optional callback named ``reposetup``. It is +called after the main Mercurial repository initialization, and can be used +to setup any local state the extension might need. + +As other command functions it receives an ``ui`` object and a ``repo`` object +(no additional parameters for this, though):: + + def reposetup(ui, repo): + #do initialization here. + +It is important to take into account that the ``ui`` object that is received +by the ``reposetup`` function is not the same as the one received by the +``uisetup`` and ``extsetup`` functions. This is particularly important when +setting up hooks as described in the following section, since not all hooks +use the same ``ui`` object and hence different hooks must be configured in +different setup functions. + +Wrapping methods on the ui and repo classes +------------------------------------------- + +Because extensions can be loaded *per repository*, you should avoid using +``extensions.wrapfunction()`` on methods of the ``ui`` and ``repo`` objects. +Instead, create a subclass of the specific class of the instance passed into +the ``*setup()`` hook; e.g. use ``ui.__class__`` as the base class, then +reassign your new class to ``ui.__class__`` again. Mercurial will then use +your updated ``ui`` or ``repo`` instance only for repositories where your +extension is enabled (or copies thereof, reusing your new class). + +For example:: + + def uisetup(ui): + class echologui(ui.__class__): + def log(self, service, *msg, **opts): + if msg: + self.write('%s: %s\n' % (service, msg[0] % msg[1:])) + super(echologui, self).log(service, *msg, **opts) + + ui.__class__ = echologui + +Configuring Hooks +================= + +Some extensions must use hooks to do their work. These required hooks can +be configured manually by the user by modifying the ``[hook]`` section of +their hgrc, but they can also be configured automatically by calling the +``ui.setconfig('hooks', ...)`` function in one of the setup functions +described above. + +The main difference between manually modifying the hooks section in the hgrc +and using ``ui.setconfig()`` is that when using ``ui.setconfig()`` you have +access to the actual hook function object, which you can pass directly to +``ui.setconfig()``, while when you use the hooks section of the hgrc file +you must refer to the hook function by using the +``python:modulename.functioname`` idiom (e.g. ``python:hgext.notify.hook``). + +For example:: + + # Define hooks -- note that the actual function name it irrelevant. + def preupdatehook(ui, repo, **kwargs): + ui.write("Pre-update hook triggered\n") + + def updatehook(ui, repo, **kwargs): + ui.write("Update hook triggered\n") + + def uisetup(ui): + # When pre- and post- hooks are configured by means of + # the ui.setconfig() function, you must use the ui object passed + # to uisetup or extsetup. + ui.setconfig("hooks", "pre-update.myextension", preupdatehook) + + def reposetup(ui, repo): + # Repository-specific hooks can be configured here. These include + # the update hook. + ui.setconfig("hooks", "update.myextension", updatehook) + +Note how different hooks may need to be configured in different setup +functions. In the example you can see that the ``update`` hook must be +configured in the ``reposetup`` function, while the ``pre-update`` hook +must be configured on the ``uisetup`` or the ``extsetup`` functions. + +Marking compatible versions +=========================== + +Every extension should use the ``testedwith`` variable to specify Mercurial +releases it's known to be compatible with. This helps us and users diagnose +where problems are coming from:: + + testedwith = '2.0 2.0.1 2.1 2.1.1 2.1.2' + +Do not use the ``internal`` marker in third-party extensions; we will +immediately drop all bug reports mentioning your extension if we catch you +doing this. + +Similarly, an extension can use the ``buglink`` variable to specify how users +should report issues with the extension. This link will be included in the +error message if the extension produces errors:: + + buglink = 'https://bitbucket.org/USER/REPO/issues' + +Wrap up: what belongs where? +============================ + +You will find here a list of most common tasks, based on setups from the +extensions included in Mercurial core. + +uisetup +------- + +* Changes to ``ui.__class__`` . The ``ui`` object that will be used to run + the command has not yet been created. Changes made here will affect ``ui`` + objects created after this, and in particular the ``ui`` that will be passed + to ``runcommand`` +* Command wraps (``extensions.wrapcommand``) +* Changes that need to be visible by other extensions: because initialization + occurs in phases (all extensions run ``uisetup``, then all run ``extsetup``), + a change made here will be visible by other extensions during ``extsetup``. +* Monkeypatches or function wraps (``extensions.wrapfunction``) of ``dispatch`` + module members +* Setup of ``pre-*`` and ``post-*`` hooks +* ``pushkey`` setup + +extsetup +-------- + +* Changes depending on the status of other extensions. (``if extensions.find('mq')``) +* Add a global option to all commands +* Extend revsets + +reposetup +--------- + +* All hooks but ``pre-*`` and ``post-*`` +* Modify configuration variables +* Changes to ``repo.__class__``, ``repo.dirstate.__class__`` diff --git a/tests/test-help.t b/tests/test-help.t --- a/tests/test-help.t +++ b/tests/test-help.t @@ -1066,6 +1066,7 @@ internals topic renders index of availab censor Censor changegroups Changegroups config Config Registrar + extensions Extension API requirements Repository Requirements revlogs Revision Logs wireprotocol Wire Protocol @@ -3404,6 +3405,13 @@ Sub-topic indexes rendered properly Config Registrar + + extensions + + + Extension API + + requirements