.. :doctest:

The config module reads a config file and massages the data.

    >>> from __future__ import print_function
    >>> from __future__ import unicode_literals
    >>> from checkoutmanager import config

Instantiation with a non-exising config file raises and error:

    >>> config.Config('non/existing/configfile')
    Traceback (most recent call last):
    ...
    AssertionError

Grab the sample config file:

    >>> import pkg_resources
    >>> sample_config = pkg_resources.resource_filename(
    ...     'checkoutmanager.tests', 'testconfig.cfg')
    >>> print(open(sample_config).read())
    # Sample config file.  Should be placed as
    ...

Instantiate our config object with the config filename:

    >>> conf = config.Config(sample_config)

The config file is loaded into a configparser instance:

    >>> conf.parser
    <...SafeConfigParser ...>

Query for found sections (which we call groupings).  Sorted, btw:

    >>> conf.groupings
    ['dotfolders', 'recipes']


Determine vcs url and directory name
------------------------------------

There's a helper method for extracting a vcs url and directory name from a
spec.  A spec is an url followed by an optional directory name:

    >>> config.extract_spec('aaa bbb')
    ('aaa', 'bbb')
    >>> config.extract_spec('aaa     bbb')
    ('aaa', 'bbb')

More than three parts raises an error:

    >>> config.extract_spec('aaa bbb ccc')
    Traceback (most recent call last):
    ...
    AssertionError: aaa bbb ccc

If no second part is given, a directory name is extracted from the last path
part of the spec:

    >>> config.extract_spec('aaa') == ('aaa', 'aaa')
    True
    >>> config.extract_spec('aaa/bbb') == ('aaa/bbb', 'bbb')
    True
    >>> config.extract_spec('aaa/bbb/') == ('aaa/bbb/', 'bbb')
    True

/trunk is splitted off:

    >>> config.extract_spec('aaa/bbb/trunk') == ('aaa/bbb/trunk', 'bbb')
    True

Unless we specify a directory ourselves:

    >>> config.extract_spec('aaa/bbb/trunk somewhere') == (
    ... 'aaa/bbb/trunk', 'somewhere')
    True

And a branch gets named after the branch:

    >>> config.extract_spec('aaa/bbb/branches/reinout-fix') == (
    ... 'aaa/bbb/branches/reinout-fix', 'bbb-reinout-fix')
    True

Launchpad is also recognized:

    >>> config.extract_spec('lp:myproject') == ('lp:myproject', 'myproject')
    True

Git has some special cases too:

    >>> config.extract_spec('git@github.com:collective/Products.Poi.git') == (
    ... 'git@github.com:collective/Products.Poi.git', 'Products.Poi')
    True
    >>> config.extract_spec('git@git.example.org:projectname') == (
    ... 'git@git.example.org:projectname', 'projectname')
    True

Find directories
----------------

Base purpose: return the wrapped directories:

    >>> for d in conf.directories():
    ...     print(d)
    <DirInfo (bzr) for HOMEDIR/.emacs.d>
    <DirInfo (bzr) for HOMEDIR/.subversion>
    <DirInfo (svn) for HOMEDIR/svn/recipes/blablabla>
    <DirInfo (svn) for HOMEDIR/svn/recipes/customername>
    <DirInfo (svn) for HOMEDIR/svn/recipes/differentname>
    <DirInfo (svn) for HOMEDIR/svn/recipes/yetanother-reinout-fix>
    <DirInfo (svn) for HOMEDIR/svn/recipes/yetanother>

We can restrict to a certain group:

    >>> for d in conf.directories(group='recipes'):
    ...     print(d)
    <DirInfo (svn) for HOMEDIR/svn/recipes/blablabla>
    <DirInfo (svn) for HOMEDIR/svn/recipes/customername>
    <DirInfo (svn) for HOMEDIR/svn/recipes/differentname>
    <DirInfo (svn) for HOMEDIR/svn/recipes/yetanother-reinout-fix>
    <DirInfo (svn) for HOMEDIR/svn/recipes/yetanother>

We can ignore certain directories and support globbing to do so:

    >>> import os
    >>> os.mkdir(os.path.join(homedir, 'svn'))
    >>> os.mkdir(os.path.join(homedir, 'svn', 'recipes'))
    >>> os.mkdir(os.path.join(homedir, 'svn', 'recipes', 'missing'))
    >>> os.mkdir(os.path.join(homedir, 'svn', 'recipes', 'ignored_missing'))
    >>> conf.report_missing(group='recipes') # doctest: +ELLIPSIS
    Unconfigured items in HOMEDIR/svn/recipes [svn]:
        HOMEDIR/svn/recipes/missing
