Configuring Breezy ================== .. contents:: :depth: 2 As a Breezy developer there are a few things you need to know about configuration: * how to add a new option, * how add a new stack, * how add a new store. The first sections in this document summarize the steps needed when adding a new configuration item, the rest of the document gives more internal details on how this is implemented. Get an option value ------------------- Options values are obtained with ``stack.get(option_name)`` where ``stack`` is one of the daughter classes of ``config.Stack``, see their docstrings for a description of which sections are used from which stores. The value returned is of the type declared for that ``Option`` and if nothing is specifically declared you will get the default for that option. Add a new option ---------------- You add a new ``Option`` to the ``option_registry``, either inside ``breezy/config.py`` or during initialization of your plugin (use ``register_lazy`` in this case). New plugins should have systematic hierarchical names so that related values are grouped together:: option_registry.register( Option('dirstate.fdatasync', default=True, from_unicode=bool_from_store, help="Flush dirstate changes onto physical disk? ....")) You then need to decide which stack is appropriate to implement the Option policy: * which config files (aka ``Store``) needs to be queried, which sections are relevant and in what order, * which section will receive the modifications (if relevant). The docstrings for the existing stacks cover most of the known use cases. Modify an option value or delete an option ------------------------------------------ Just reading an option is what is needed most of the time, modifying option values or removing options is usually something that is not automated but left to the user (with ``brz config``). Nevertheless, if you need to save a modified option value, use ``.set(option_name, value)`` and ``.remove(option_name)`` to delete the option. Both methods are provided by the ``Stack`` object. But before doing that, you must be sure that the stack you're using have a writable section (this is true for ``GlobalStack`` which uses the ``DEFAULT`` section in ``breezy.conf`` and for ``BranchStack``which uses the no-name section in ``branch.conf``). Old and new configuration code ------------------------------ There is (as of late 2011) some older and some newer configuration code. The old code has specific methods for various checks or uses classes like ``GlobalConfig``. Don't add to to it; try to remove it. If you encounter an option using the old code you may want to migrate it. This generally involves: * registering the option, * replace the old config by a stack: * ``GlobalConfig`` became ``GlobalStack``, * ``LocationConfig`` became ``LocationStack``, * ``BranchConfig`` became ``BranchStack`` (or in this case, ``get_config()`` became ``get_config_stack()``. * replace the custom accessor calls with ``conf.get(option_name)``. The new config code provides some help for commonly encountered use cases that can allow further simplifications like: * providing a default value when the option is not defined in any way by the user, * convert the unicode string provided by the user into a suitable representation (integer, list, etc). If you start migrating a given option to the config stacks, don't stop mid-way, all its uses should be covered (tests included). There are some edge cases where updates via one API will be not be seen by the other API (see http://pad.lv/948339 and http://pad.lv/948344 for details). Roughly, the old API always trigger an IO while the new one cache values to avoid them. This works fine as long as a given option is handled via a single API. Adding a new stack ------------------ Stacks capture the various places an option can be declared by the user with associated levels of generality and query them in the appropriate order returning the first definition found. For example, the ``append_revisions_only`` option may be declared for all branches of a user in ``breezy.conf``, or for a hierarchy of branches in ``locations.conf`` or in a single branch in ``branch.conf``. Defining a new stack means you need a new way to expose these levels to the user that is not covered by the existing stacks. This is achieved by declaring: * which stores can provide a value for the option, * which sections apply to the stack instance, some filtering for a given context can be defined, * which (store, section) should receive the modifications. Mapping different sections to different stacks is a powerful way to organize the options and provide various levels of configuration to the user. This is achieved with ``Store`` and ``SectionMatcher`` objects. Adding a new store ------------------ The following stores are used by ``brz`` in ways that illustrate various uses of sections. breezy.conf =========== ``brz`` itself defines two sections here: * ``DEFAULT`` where global options are defined, * ``ALIASES`` where command aliases are defined. This section is *not* available via ``GlobalStack``, instead, the ``brz alias`` command uses it for its own purposes. Plugins can define either additional options in the ``DEFAULT`` section or new sections for their own needs (this is not especially encouraged though). The ``bzr-bookmarks`` plugin defines a ``BOOKMARKS`` section there for example. location.conf ============= ``brz`` defines sections corresponding to URLs there and includes the relevant sections in ``LocationStack`` and ``BranchStack``. No no-name section is recognized in this file. branch.conf =========== This file defines the option for a given branch and uses only the no-name section. Option ------ The Option object is used to define its properties: * name: a name: a valid python identifier (even if it's not used as an identifier in python itself). This is also used to register the option. * from_unicode: a callable accepting a unicode string and returning a suitable value for the option. If the string cannot be coerced it should return None. * override_from_env: a list of environment variables. The first variable set will be used as the option value overriding any other definition of the option. * default: the default value that Stack.get() should return if no value can be found for the option. This can also be a callable as long as it returns a unicode string. * default_from_env: a list of environment variables. The first variable set will provide a default value overriding 'default' which remains the default value if *no* environment variable is set. * help: a doc string describing the option, the first line should be a summary and can be followed by a blank line and a more detailed explanation. This will be displayed to the user with:: brz help