summaryrefslogtreecommitdiffstats
path: root/keystone/openstack
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2012-05-03 21:14:53 +0100
committerMark McLoughlin <markmc@redhat.com>2012-05-03 21:14:53 +0100
commit8dc3baa45a6ce404d8745ff2c4e619157e07b2d5 (patch)
tree13873631224300bc7518a1f65204525f7be13e04 /keystone/openstack
parent43d792ff14b126eae10f7edee2f3f582c66b08ec (diff)
downloadkeystone-8dc3baa45a6ce404d8745ff2c4e619157e07b2d5.tar.gz
keystone-8dc3baa45a6ce404d8745ff2c4e619157e07b2d5.tar.xz
keystone-8dc3baa45a6ce404d8745ff2c4e619157e07b2d5.zip
Sync to newer openstack-common
Changes since last sync are: - cfg: * Support for directory source of config files * Provide file extension when when looking for files * Some refactoring of the cfg cache * Add caching to openstack.common.cfg - setup: * Handle authors existed before VCS was around. Change-Id: If3f0515a911a315dc1329b99299fdbc3592fce24
Diffstat (limited to 'keystone/openstack')
-rw-r--r--keystone/openstack/common/cfg.py112
-rw-r--r--keystone/openstack/common/setup.py12
2 files changed, 91 insertions, 33 deletions
diff --git a/keystone/openstack/common/cfg.py b/keystone/openstack/common/cfg.py
index a83e8638..76f0e4d3 100644
--- a/keystone/openstack/common/cfg.py
+++ b/keystone/openstack/common/cfg.py
@@ -90,16 +90,21 @@ the purposes of --help and CLI arg validation)::
def add_common_opts(conf):
conf.register_cli_opts(cli_opts)
-The config manager has a single CLI option defined by default, --config-file::
+The config manager has two CLI options defined by default, --config-file
+and --config-dir::
class ConfigOpts(object):
- config_file_opt = MultiStrOpt('config-file',
- ...
-
def __init__(self, ...):
- ...
- self.register_cli_opt(self.config_file_opt)
+
+ opts = [
+ MultiStrOpt('config-file',
+ ...),
+ StrOpt('config-dir',
+ ...),
+ ]
+
+ self.register_cli_opts(opts)
Option values are parsed from any supplied config files using
openstack.common.iniparser. If none are specified, a default set is used
@@ -221,6 +226,8 @@ log files:
import collections
import copy
+import glob
+import functools
import optparse
import os
import string
@@ -318,11 +325,12 @@ class ConfigFileValueError(Error):
pass
-def find_config_files(project=None, prog=None):
+def find_config_files(project=None, prog=None, extension='.conf'):
"""Return a list of default configuration files.
:param project: an optional project name
:param prog: the program name, defaulting to the basename of sys.argv[0]
+ :param extension: the type of the config file
We default to two config files: [${project}.conf, ${prog}.conf]
@@ -355,16 +363,16 @@ def find_config_files(project=None, prog=None):
]
cfg_dirs = filter(bool, cfg_dirs)
- def search_dirs(dirs, basename):
+ def search_dirs(dirs, basename, extension):
for d in dirs:
- path = os.path.join(d, basename)
+ path = os.path.join(d, '%s%s' % (basename, extension))
if os.path.exists(path):
return path
config_files = []
if project:
- config_files.append(search_dirs(cfg_dirs, '%s.conf' % project))
- config_files.append(search_dirs(cfg_dirs, '%s.conf' % prog))
+ config_files.append(search_dirs(cfg_dirs, project, extension))
+ config_files.append(search_dirs(cfg_dirs, prog, extension))
return filter(bool, config_files)
@@ -821,14 +829,37 @@ class ConfigOpts(collections.Mapping):
usage=self.usage)
self._cparser = None
- self.register_cli_opt(
- MultiStrOpt('config-file',
- default=self.default_config_files,
- metavar='PATH',
- help='Path to a config file to use. Multiple config '
- 'files can be specified, with values in later '
- 'files taking precedence. The default files used '
- 'are: %s' % (self.default_config_files, )))
+ self.__cache = {}
+
+ opts = [
+ MultiStrOpt('config-file',
+ default=self.default_config_files,
+ metavar='PATH',
+ help='Path to a config file to use. Multiple config '
+ 'files can be specified, with values in later '
+ 'files taking precedence. The default files '
+ ' used are: %s' %
+ (self.default_config_files, )),
+ StrOpt('config-dir',
+ metavar='DIR',
+ help='Path to a config directory to pull *.conf '
+ 'files from. This file set is sorted, so as to '
+ 'provide a predictable parse order if individual '
+ 'options are over-ridden. The set is parsed after '
+ 'the file(s), if any, specified via --config-file, '
+ 'hence over-ridden options in the directory take '
+ 'precedence.'),
+ ]
+ self.register_cli_opts(opts)
+
+ def __clear_cache(f):
+ @functools.wraps(f)
+ def __inner(self, *args, **kwargs):
+ if kwargs.pop('clear_cache', True):
+ self.__cache.clear()
+ return f(self, *args, **kwargs)
+
+ return __inner
def __call__(self, args=None):
"""Parse command line arguments and config files.
@@ -840,6 +871,10 @@ class ConfigOpts(collections.Mapping):
The object may be called multiple times, each time causing the previous
set of values to be overwritten.
+ If the --config-dir option is set, any *.conf files from this
+ directory are pulled in, after all the file(s) specified by the
+ --config-file option.
+
:params args: command line arguments (defaults to sys.argv[1:])
:returns: the list of arguments left over after parsing options
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError
@@ -852,8 +887,14 @@ class ConfigOpts(collections.Mapping):
self._cli_values = vars(values)
- if self.config_file:
- self._parse_config_files(self.config_file)
+ def _list_config_dir():
+ return sorted(glob.glob(os.path.join(self.config_dir, '*.conf')))
+
+ from_file = list(self.config_file)
+
+ from_dir = _list_config_dir() if self.config_dir else []
+
+ self._parse_config_files(from_file + from_dir)
return args
@@ -864,7 +905,7 @@ class ConfigOpts(collections.Mapping):
:returns: the option value (after string subsititution) or a GroupAttr
:raises: NoSuchOptError,ConfigFileValueError,TemplateSubstitutionError
"""
- return self._substitute(self._get(name))
+ return self._get(name)
def __getitem__(self, key):
"""Look up an option value and perform string substitution."""
@@ -883,12 +924,14 @@ class ConfigOpts(collections.Mapping):
"""Return the number of options and option groups."""
return len(self._opts) + len(self._groups)
+ @__clear_cache
def reset(self):
"""Reset the state of the object to before it was called."""
self._args = None
self._cli_values = None
self._cparser = None
+ @__clear_cache
def register_opt(self, opt, group=None):
"""Register an option schema.
@@ -911,11 +954,13 @@ class ConfigOpts(collections.Mapping):
return True
+ @__clear_cache
def register_opts(self, opts, group=None):
"""Register multiple option schemas at once."""
for opt in opts:
- self.register_opt(opt, group)
+ self.register_opt(opt, group, clear_cache=False)
+ @__clear_cache
def register_cli_opt(self, opt, group=None):
"""Register a CLI option schema.
@@ -931,7 +976,7 @@ class ConfigOpts(collections.Mapping):
if self._args is not None:
raise ArgsAlreadyParsedError("cannot register CLI option")
- if not self.register_opt(opt, group):
+ if not self.register_opt(opt, group, clear_cache=False):
return False
if group is not None:
@@ -941,10 +986,11 @@ class ConfigOpts(collections.Mapping):
return True
+ @__clear_cache
def register_cli_opts(self, opts, group=None):
"""Register multiple CLI option schemas at once."""
for opt in opts:
- self.register_cli_opt(opt, group)
+ self.register_cli_opt(opt, group, clear_cache=False)
def register_group(self, group):
"""Register an option group.
@@ -959,6 +1005,7 @@ class ConfigOpts(collections.Mapping):
self._groups[group.name] = copy.copy(group)
+ @__clear_cache
def set_override(self, name, override, group=None):
"""Override an opt value.
@@ -973,6 +1020,7 @@ class ConfigOpts(collections.Mapping):
opt_info = self._get_opt_info(name, group)
opt_info['override'] = override
+ @__clear_cache
def set_default(self, name, default, group=None):
"""Override an opt's default value.
@@ -1056,6 +1104,18 @@ class ConfigOpts(collections.Mapping):
self._oparser.print_help(file)
def _get(self, name, group=None):
+ if isinstance(group, OptGroup):
+ key = (group.name, name)
+ else:
+ key = (group, name)
+ try:
+ return self.__cache[key]
+ except KeyError:
+ value = self._substitute(self._do_get(name, group))
+ self.__cache[key] = value
+ return value
+
+ def _do_get(self, name, group=None):
"""Look up an option value.
:param name: the opt name (or 'dest', more precisely)
@@ -1196,7 +1256,7 @@ class ConfigOpts(collections.Mapping):
def __getattr__(self, name):
"""Look up an option value and perform template substitution."""
- return self.conf._substitute(self.conf._get(name, self.group))
+ return self.conf._get(name, self.group)
def __getitem__(self, key):
"""Look up an option value and perform string substitution."""
diff --git a/keystone/openstack/common/setup.py b/keystone/openstack/common/setup.py
index 231b3384..60c731a9 100644
--- a/keystone/openstack/common/setup.py
+++ b/keystone/openstack/common/setup.py
@@ -138,10 +138,8 @@ def generate_authors():
"grep -v " + jenkins_email
changelog = _run_shell_command(git_log_cmd)
mailmap = parse_mailmap()
- new_authors_fh = open(new_authors, "w")
- new_authors_fh.write(canonicalize_emails(changelog, mailmap))
- if os.path.exists(old_authors):
- new_authors_fh.write("\n")
- with open(old_authors, "r") as old_authors_fh:
- new_authors_fh.write(''.join(old_authors_fh.readlines()))
- new_authors_fh.close()
+ with open(new_authors, 'w') as new_authors_fh:
+ new_authors_fh.write(canonicalize_emails(changelog, mailmap))
+ if os.path.exists(old_authors):
+ with open(old_authors, "r") as old_authors_fh:
+ new_authors_fh.write('\n' + old_authors_fh.read())