Python: ConfigParser – пример использования

Автор: | 11/07/2015
 

PythonДля управления билдом нашего приложения – имеется утилита RDSmanager, написанная на Python 2.7.

Одна из его задач – управления конфигурациями в INI-файле, который выглядит примерно так:

[version_1_0_2_staging]
MATH_DLL = 7a00ca94-b68d-4c89-a004-d3a4f5e7cf56
MATH_DLL_XML = 738174f7-f310-4989-8cae-da1690487e7c
ASSETMANAGER_API_DLL = 2e9e3807-4f8a-4ae1-a873-4a8f6d152eaf
ASSETMANAGER_API_DLL_XML = 024130cf-cbd9-41c2-b432-db9bc8565220
...
[debug]
MATH_DLL = 7b73c8f2-c5b6-435d-b310-37628302d1a0
MATH_DLL_XML = 5a349f50-76c3-456e-a885-f893c501a050
NETWORK_IMPL_DLL = 90a7b774-aa9a-4b85-b5e7-822333860588
...

В самом RDSmanager имеется функция для определения опций, в которой в частности вызывается с управления конфигурациями.

В argparse используется subparsers для разделения опций:

...
parser_unity = subparsers.add_parser('unity', help='Unity application')
parser_unity.set_defaults(func=handler_unity)
...
    # UUIDs management
parser_unity.add_argument('-u', '--uuidgen', action='store', dest='unity_uuidgen',
                          help='Generate UUIDs for each module in Plugins.sln. Must be called with 'config_name' as first argument and optionally - with `-b ci` option')
parser_unity.add_argument('-l', '--configlist', action='store_true', dest='unity_configlist',
                          help='Display configuration names in uuids.ini')
parser_unity.add_argument('-x', '--remove', action='store', dest='unity_uuid_remove',
                          help='Remove configuration from uuids.ini. Must be called with config_name to delete')
...

И функция, которая обрабатывает сабпарсер parser_unity:

...
def handler_unity(action_list):
...
   if action_list.unity_uuidgen:
        logger.logger.info('Running UUID generator with %s' % action_list.unity_uuidgen)
        from lib.unity.uuidgen import UuuidManagment
        u = UuuidManagment(logger, RDS_BASEDIR)
        u.uuidgen(action_list.unity_uuidgen, action_list.unity_buildtype)

    if action_list.unity_configlist:
        logger.logger.info('Running configlist')
        from lib.unity.uuidgen import UuuidManagment
        u = UuuidManagment(logger, RDS_BASEDIR)
        u.configlist()

    if action_list.unity_uuid_remove:
        from lib.unity.uuidgen import UuuidManagment
        u = UuuidManagment(logger, RDS_BASEDIR)
        u.config_remove(action_list.unity_uuid_remove)
...

Собственно – сам класс:

#!/usr/bin/env python

import uuid
import os
import sys
import subprocess

from lib.external import ConfigParser
from lib.unity.external import modules_list, checkhome, mod_proj
from lib.external.external import isdev
from lib.unity.tag_checker import parser
from lib.external.exceptions import *

"""Generates UUIDs for modules and module's XML files.
    Will save output to file RDSmanager/conf/unity/uuids.ini
    Must be enclosed with configuration name, e.g. 'beta_1_1', 'debug' etc."""


class UuuidManagment(object):

    """Class for data in uuids.ini file management"""

    def __init__(self, logger, rds_basedir):

        self.config = ConfigParser.ConfigParser()
        self.config_file = os.path.join(rds_basedir, 'conf', 'unity', 'uuids.ini')
        self.config.read(self.config_file)
        self.configs = self.config.sections()

        self.logger = logger
        self.rds_basedir = rds_basedir

    def gitsave(self, outfile, config_name):

        """Save updated uuids.ini to repository"""

        os.chdir(self.rds_basedir)

        try:
            self.logger.logger.info('Updating uuids.ini list...')
            subprocess.call('git pull')
            self.logger.logger.info('Done.')
            subprocess.call('git add %s' % outfile)
            subprocess.call('git commit -m "Add new configuration set `%s`"' % config_name)
            subprocess.call('git push origin')
        except WindowsError as error:
            self.logger.logger.info('ERROR: %s' % error)
            sys.exit(1)

    def configlist(self):

        """Return list of actually created configs in uuids.list file"""

        if self.configs:
            self.logger.logger.info('nCurrently avalable configurations: n')
            for conf in self.configs:
                self.logger.logger.info(conf)
        else:
            raise NoConfigError(self.logger, 'No configs in %s found' % self.config_file)

    def uuidgen(self, config_name, build_type):

        """For new UUIDs set generation.
           Must be called with new config_name name"""

        workdir = checkhome(self.logger)
        modules = modules_list(workdir)

        if not os.path.isfile(self.config_file):
            raise NoConfigError(self.logger, 'No config file %s found' % self.config_file)

        if config_name in self.config.sections():
            self.logger.logger.info('Config with name %s already exist!nYou can check all configs with RDSmanager -l option.' % config_name)
            sys.exit(1)

        self.config.add_section(config_name)

        for modname in modules:

            mod_proj_file = mod_proj(workdir, modname)

            try:
                mod_tag = parser(self.logger, modname, mod_proj_file)
                if mod_tag:
                    if 'CLOUD' in mod_tag:
                        if not isdev(build_type):
                            self.config.set(config_name, modname.upper() + '_DLL', str(uuid.uuid4()))
                            self.config.set(config_name, modname.upper() + '_DLL_XML', str(uuid.uuid4()))
                        else:
                            self.config.set(config_name, modname.upper() + '_DLL', modname + '.dll')
                            self.config.set(config_name, modname.upper() + '_DLL_XML', modname + '.dll' + '.xml')

            except AttributeError:
                pass

        additional = {
            'PRODUCTGROUPEDITOR_BUNDLE': 'ProductGroupEditor.unity3d',
            'CATALOGUE_BUNDLE': 'CatalogueBundle.unity3d',
            'EDITINGMODE_BUNDLE': 'EditingMenuBundle.unity3d',
            'SHELFEDITOR_BUNDLE': 'ShelfEditorBundle.unity3d',
            'MAIN_APPLICATION': 'MainApplication/web/web.unity3d',
            'REPLAY_BUNDLE': 'Replay.unity3d',
            'UNITYUI_BUNDLE': 'UnityUI.unity3d',
            'CONFIG_XML': 'config.xml'
        }

        for name in additional.keys():
            if not isdev(build_type):
                self.config.set(config_name, name, str(uuid.uuid4()))
            else:
                 for mod_var, mod_name in additional.items():
                     self.config.set(config_name, mod_var, mod_name)

        self.config.read(self.config_file)

        self.logger.logger.info('Config %s created:n' % config_name)
        for i in self.config.items(config_name):
            self.logger.logger.info(i)

        with open(self.config_file, 'w+') as out:
            self.config.write(out)

        self.gitsave(self.config_file, config_name)

    def config_remove(self, config_name):

        """Remove config_name specified in argument from uuids.ini"""

        self.logger.logger.info('Removing %s' % config_name)

        self.config.remove_section(config_name)

        with open(self.config_file, 'w') as out:
            self.config.write(out)

        self.gitsave(self.config_file, config_name)

Примеры использования.

Список имеющихся конфигураций:

d:RDSrdsmanager>RDSmanager.py unity -l
RDSmanager started at 10, Jul 2015 at 11:01:33
Running configlist

Currently avalable configurations:

develop
debug
qa
version_1_0_2_staging

Добавить новую, с именем test:

d:RDSrdsmanager>RDSmanager.py unity -u test -b ci
RDSmanager started at 10, Jul 2015 at 11:01:56
Running UUID generator with test
WARNING: variable BAMBOO_WORKING_DIRECTORY not found. Will look for RDS_HOME variable...
Using d:RDSbuilddir as workdir

Config test created:

('MATH_DLL', '8546cf29-ca90-4eb0-972b-69f0d7aab0c3')
('MATH_DLL_XML', '2bab667a-1d8d-4811-96b4-f6e81bf9954e')
('ASSETMANAGER_API_DLL', 'f505ddeb-46bc-46a1-9a37-36881afe0b2d')
('ASSETMANAGER_API_DLL_XML', '7ce86064-799e-4aee-be7a-c8dc25210eb5')
...

Удалить конфигурацию с именем test:

d:RDSrdsmanager>RDSmanager.py unity -x test
RDSmanager started at 10, Jul 2015 at 11:03:00
Removing test
Updating uuids.ini list...
...
Done.
[master a85e51d] Add new configuration set `test`
 1 file changed, 64 deletions(-)
...