Rev 6363: Config doc refresh, clarifying the sections used in the implemented stacks. in file:///home/vila/src/bzr/experimental/config-explained/

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Dec 14 10:59:15 UTC 2011


At file:///home/vila/src/bzr/experimental/config-explained/

------------------------------------------------------------
revno: 6363
revision-id: v.ladeuil+lp at free.fr-20111214105915-fjmlk4zvbv9n1jvo
parent: pqm at pqm.ubuntu.com-20111212151207-xiz0tu02z1hxrq76
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: config-explained
timestamp: Wed 2011-12-14 11:59:15 +0100
message:
  Config doc refresh, clarifying the sections used in the implemented stacks.
-------------- next part --------------
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py	2011-12-09 16:15:52 +0000
+++ b/bzrlib/config.py	2011-12-14 10:59:15 +0000
@@ -3397,18 +3397,45 @@
 
 
 class GlobalStack(_CompatibleStack):
-    """Global options only stack."""
+    """Global options only stack.
+
+    The following sections are queried:
+
+    * command-line overrides,
+
+    * the 'DEFAULT' section in bazaar.conf
+
+    This stack will use the ``DEFAULT`` section in bazaar.conf as its
+    MutableSection.
+    """
 
     def __init__(self):
         # Get a GlobalStore
         gstore = GlobalStore()
         super(GlobalStack, self).__init__(
-            [self._get_overrides, NameMatcher(gstore, 'DEFAULT').get_sections],
+            [self._get_overrides,
+             NameMatcher(gstore, 'DEFAULT').get_sections],
+            # For modifications
             gstore, mutable_section_id='DEFAULT')
 
 
 class LocationStack(_CompatibleStack):
-    """Per-location options falling back to global options stack."""
+    """Per-location options falling back to global options stack.
+
+
+    The following sections are queried:
+
+    * command-line overrides,
+
+    * the sections matching ``location`` in ``locations.conf``, the order being
+      defined by the number of path components in the section glob, higher
+      numbers first (from most specific section to most generic).
+
+    * the 'DEFAULT' section in bazaar.conf
+
+    This stack will use the ``location`` section in locations.conf as its
+    MutableSection.
+    """
 
     def __init__(self, location):
         """Make a new stack for a location and global configuration.
@@ -3417,26 +3444,43 @@
         lstore = LocationStore()
         if location.startswith('file://'):
             location = urlutils.local_path_from_url(location)
-        matcher = LocationMatcher(lstore, location)
         gstore = GlobalStore()
         super(LocationStack, self).__init__(
             [self._get_overrides,
-             matcher.get_sections, NameMatcher(gstore, 'DEFAULT').get_sections],
+             LocationMatcher(lstore, location).get_sections,
+             NameMatcher(gstore, 'DEFAULT').get_sections],
+            # For modifications
             lstore, mutable_section_id=location)
 
 
 class BranchStack(_CompatibleStack):
-    """Per-location options falling back to branch then global options stack."""
+    """Per-location options falling back to branch then global options stack.
+
+    The following sections are queried:
+
+    * command-line overrides,
+
+    * the sections matching ``location`` in ``locations.conf``, the order being
+      defined by the number of path components in the section glob, higher
+      numbers first (from most specific section to most generic),
+
+    * the no-name section in branch.conf,
+
+    * the ``DEFAULT`` section in ``bazaar.conf``.
+
+    This stack will use the no-name section in ``branch.conf`` as its
+    """
 
     def __init__(self, branch):
+        lstore = LocationStore()
         bstore = branch._get_config_store()
-        lstore = LocationStore()
-        matcher = LocationMatcher(lstore, branch.base)
         gstore = GlobalStore()
         super(BranchStack, self).__init__(
             [self._get_overrides,
-             matcher.get_sections, bstore.get_sections,
+             LocationMatcher(lstore, branch.base).get_sections,
+             NameMatcher(bstore, None).get_sections,
              NameMatcher(gstore, 'DEFAULT').get_sections],
+            # For modifications
             bstore)
         self.branch = branch
 
@@ -3451,7 +3495,8 @@
     def __init__(self, bzrdir):
         cstore = bzrdir._get_config_store()
         super(RemoteControlStack, self).__init__(
-            [cstore.get_sections],
+            [NameMatcher(cstore, None).get_sections],
+            # For modifications
             cstore)
         self.bzrdir = bzrdir
 
@@ -3466,7 +3511,8 @@
     def __init__(self, branch):
         bstore = branch._get_config_store()
         super(RemoteBranchStack, self).__init__(
-            [bstore.get_sections],
+            [NameMatcher(bstore, None).get_sections],
+            # For modifications
             bstore)
         self.branch = branch
 

=== modified file 'doc/developers/configuration.txt'
--- a/doc/developers/configuration.txt	2011-12-01 11:40:05 +0000
+++ b/doc/developers/configuration.txt	2011-12-14 10:59:15 +0000
@@ -4,44 +4,178 @@
 .. contents::
    :depth: 2
 
-
-The short story
----------------
-
-As a Bazaar developer there are three things you need to know about
-configuration.
-
-1. Get a value.
-
-You construct or get a reference to a ConfigStack subclass that's relevant
-to the context where you want to look up a value. For instance, given a
-branch::
-
-  print branch.get_config_stack().get('log_format')
-
-This will look up the stack through all relevant configuration sources.
-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.
-
-2. Add a new option.
+As a Bazaar developer there are a few things you need to know about
+configuration:
+
+* add a new option,
+
+* add a new stack,
+
+* 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
-``bzrlib/config.py`` or during initialization of your plugin. New plugins
-should have systematic hierarchical names so that related values are grouped
-together::
+``bzrlib/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? ...."))
 
-
-3. Old and new configuration code.
+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 ``bzr 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 ``bazaar.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 by ``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).
+
+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 ``bazaar.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 ``bzr`` in ways that illustrate various
+uses of sections.
+
+bazaar.conf
+===========
+
+``bzr`` 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 ``bzr 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.
+
+pkgimport.conf
+==============
+
+The Ubuntu package importer defines a store and two stacks involving
+``pkgimport.conf``. A no-name section contains the options common to all
+packages and sections named after their corresponding package can also be
+defined.
+
+The ``ImporterStack`` uses ``locations.conf`` and the no-name section in
+``pkgimport.conf`` for the importer options.
+
+The ``PackageStack`` uses only ``pkgimport.conf`` and uses the section name
+after the package followed by the no-name section.
+
+location.conf
+=============
+
+``bzr`` 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
 ------
 
@@ -54,8 +188,9 @@
   suitable value for the option. If the string cannot be coerced it should
   return None.
 
-* default: the default value that Stack.get() should return if no
-  value can be found for 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
@@ -104,11 +239,11 @@
 A ``Store`` can contain one or more sections, each section is uniquely
 identified by a unicode string.
 
-``config.ConfigObjStore`` is an implementation that use ``ConfigObj``.
+``config.IniFileStore`` is an implementation that use ``ConfigObj``.
 
 Depending on the object it is associated with (or not) a ``Store`` also needs
-to implement a locking mechanism. ``LockableConfigObjStore`` implements such a
-mechanism for ``ConfigObj`` based stores.
+to implement a locking mechanism. ``LockableIniFileStore`` implements such a
+mechanism for ``IniFileStore`` based stores.
 
 Classes are provided for the usual Bazaar configuration files and could be
 used as examples to define new ones if needed. The associated tests provides a
@@ -119,8 +254,9 @@
 Filtering sections
 ------------------
 
-For some contexts, only some sections from a given store will apply. Defining
-which is what the ``SectionMatcher`` objects are about.
+For some contexts, only some sections from a given store will apply. The
+``SectionMatcher`` objects are used to define which sections in a store
+apply to a given context.
 
 The main constraint here is that a ``SectionMatcher`` should delay the loading
 of the associated store as long as possible. The constructor should collect
@@ -130,10 +266,10 @@
 Only ``ReadOnlySection`` objects are manipulated here but a
 ``SectionMatcher`` can return dedicated ``Section`` objects to provide
 additional context (the ``LocationSection`` add an ``extra_path`` attribute
-to implement the ``appendpath`` policy for example). If no sections match,
+to implement the section local options for example). If no sections match,
 an empty list is returned.
 
-Options local to a section can also be defined for special purposes and be
+Options local to a section can be defined for special purposes and be
 handled by ``Section.get()``. One such option is ``relpath`` which is
 defined in ``LocationSection`` as an alternative to the ``appendpath``
 policy.

=== modified file 'doc/developers/new-config-rationale.txt'
--- a/doc/developers/new-config-rationale.txt	2011-12-06 15:13:04 +0000
+++ b/doc/developers/new-config-rationale.txt	2011-12-14 10:59:15 +0000
@@ -60,13 +60,14 @@
 
   * should the option be inherited by more specific sections, (this was more
     or less the default in the old design, it is addressed by section
-    matchers in the new one).
+    matchers in the new one by letting users define options in whatever
+    relevant section and let the matcher select the right ones).
 
-  * should the inherited value append the relative path between the
-    section one and the location it applies to (see http://pad.lv/832013),
+  * should the inherited value append the relative path between the section
+    one and the location it applies to (see http://pad.lv/832013, fixed),
 
   * the default value (including calling any python code that may be
-    required to calculate this value)(see http://pad.lv/832064),
+    required to calculate this value)(see http://pad.lv/832064, fixed),
 
   * priority between sections in various config files (this is defined by
     the section matcher associated with a given config store for stacks,
@@ -78,9 +79,12 @@
   inconsistent. (Using only Stacks addresses that).
 
 * Access to the 'active' configuration option value from the command line
-  doesn't give access to the specific section. (This is only a concern if
-  the user has no other way to address a specific configuration option
-  including Store and Section when using ``bzr config``) (see http://pad.lv/725234).
+  doesn't give access to the specific section. This is a concern if the user
+  has no other way to address a specific configuration option including
+  Store and Section when using ``bzr config`` (see
+  http://pad.lv/725234). Plugins defining their own staks and/or stores also
+  have no way to properly plug into ``bzr config`` (see
+  http://pad.lv/788991).
 
 * Rules for configuration options are not clearly defined for remote
   branches (they may differ between dumb and smart servers the former will
@@ -91,7 +95,8 @@
   accessible to plugin authors either by supporting plugin configuration
   options in the configuration files or allowing the plugins to define their
   own configuration files. (Separating Section, Store and Stack starts
-  addressing that, a stack registry should complete the needed means).
+  addressing that, a stack registry should complete the needed means
+  http://pad.lv/832036).
 
 * While the actual configuration files support sections, they are used in
   mutually exclusive ways that make it impossible to offer the same set of
@@ -111,6 +116,10 @@
 
   * ``branch.conf`` doesn't use any section.
 
+  This is addressed by defining different stacks selecting the relevant
+  sections from the stores involved. ``ALIASES`` for example can define a
+  stack that select only the ``ALIASES`` section from ``bazaar.conf``.
+
 * There is no easy way to get configuration options for a given repository
   or an arbitrary path. Working trees and branches are generally organized
   in hierarchies and being able to share the option definitions is an often
@@ -120,21 +129,23 @@
   support conflict resolution options for a given file, directory or
   subtree (see http://pad.lv/359320).
 
-* Since sections allow different definitions for the same option, a total
-  order should be defined between sections to select the right definition
-  for a given context (paths or globs for ``locations.conf`` but other
-  schemes can be used, window names for qbzr for example). Allowing globs
-  for section names is harmful in this respect since the order is currently
-  defined as being the lexicographical one. The caveat here is that if the
-  order is always defined for a given set of sections it can change when one
-  or several globs are modified and the user may get surprising and unwanted
-  results in these cases. The lexicographical order is otherwise fine to
-  define what section is more specific than another. (This may not be a
-  problem in real life since longer globs are generally more specific than
-  shorter ones and explicit paths should also be longer than matching
+* Since sections allow different definitions for the same option (in the
+  same store), a total order should be defined between sections to select
+  the right definition for a given context (paths or globs for
+  ``locations.conf`` but other schemes can be used, window names for qbzr,
+  repository UUIDs for bzr-svn for example). Allowing globs for section
+  names is harmful in this respect since the order is currently defined as
+  being based on the number of path components. The caveat here is that if
+  the order is always defined for a given set of sections it can change when
+  one or several globs are modified and the user may get surprising and
+  unwanted results in these cases. The lexicographical order is otherwise
+  fine to define what section is more specific than another. (This may not
+  be a problem in real life since longer globs are generally more specific
+  than shorter ones and explicit paths should also be longer than matching
   globs. That may leave a glob and a path of equal length in a gray area but
   in practice using ``bzr config`` should give enough feedback to address
-  them. See also http://pad.lv/832046 asking for a less magical section matcher).
+  them. See also http://pad.lv/832046 asking for a less magical section
+  matcher).
 
 * Internally, configuration files (and their fallbacks, ``bazaar.conf`` and
   ``locations.conf`` for ``branch.conf``) are read every time *one* option is
@@ -144,15 +155,14 @@
 
 * The current implementation use a mix of transport-based and direct file
   systems operations (Addressed by Store implementation relying on
-  transports only).
+  transports only and the hpss implementing the corresponding verbs).
 
 * While the underlying ``ConfigObj`` implementation provides an
   interpolation feature, the ``bzrlib`` implementation doesn't provide an
   easy handling of templates where other configuration options can be
   interpolated. Instead, ``locations.conf`` (and only it) allows for
-  ``appendpath`` and ``norecurse``. (Partially implemented, cross-section
-  and cross-file interpolation still to be implemented, see
-  http://pad.lv/832013 for the remaining parts).
+  ``appendpath`` and ``norecurse``. (Cross-section, cross-file interpolation
+  and section local options are now implemented in the new design).
 
 * Inherited list values can't be modified, a more specific configuration can
   only redefine the whole list.
@@ -188,10 +198,12 @@
 Naming
 ------
 
-Option names are organized into a name space for a given configuration file
-(or a set of related configuration files). One such set includes
-``bazaar.conf``, ``locations.conf``, ``branch.conf``, etc. Plugins can
-define their own sets for their own needs.
+Option names are organized into a name space for a given stack. One such set
+includes ``bazaar.conf``, ``locations.conf``, ``branch.conf``, etc. Plugins
+can define their own sets for their own needs. While it is conceivable that
+the same option name can be used in unrelated configuration stacks, it seems
+better to define a single name space for all options if only to avoid
+ambiguities.
 
 Using a name space is meant to help:
 
@@ -242,7 +254,7 @@
 
 This also ensures compatibility with values provided via environment
 variables or from the command line (where no validation can be expected
-either)(done in the new design, some cases missing, see http://pad.lv/832064).
+either)(done in the new design).
 
 
 Option expansion



More information about the bazaar-commits mailing list