diff options
-rw-r--r-- | openstack/common/cfg.py | 96 | ||||
-rw-r--r-- | tests/unit/test_cfg.py | 47 |
2 files changed, 122 insertions, 21 deletions
diff --git a/openstack/common/cfg.py b/openstack/common/cfg.py index c492ef1..08efeb7 100644 --- a/openstack/common/cfg.py +++ b/openstack/common/cfg.py @@ -1,6 +1,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2011 Red Hat, Inc. +# Copyright 2012 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -325,6 +325,52 @@ class ConfigFileValueError(Error): pass +def _get_config_dirs(project=None): + """Return a list of directors where config files may be located. + + :param project: an optional project name + + If a project is specified, following directories are returned:: + + ~/.${project}/ + ~/ + /etc/${project}/ + /etc/ + + Otherwise, these directories:: + + ~/ + /etc/ + """ + fix_path = lambda p: os.path.abspath(os.path.expanduser(p)) + + cfg_dirs = [ + fix_path(os.path.join('~', '.' + project)) if project else None, + fix_path('~'), + os.path.join('/etc', project) if project else None, + '/etc' + ] + + return filter(bool, cfg_dirs) + + +def _search_dirs(dirs, basename, extension=""): + """Search a list of directories for a given filename. + + Iterator over the supplied directories, returning the first file + found with the supplied name and extension. + + :param dirs: a list of directories + :param basename: the filename, e.g. 'glance-api' + :param extension: the file extension, e.g. '.conf' + :returns: the path to a matching file, or None + """ + for d in dirs: + path = os.path.join(d, '%s%s' % (basename, extension)) + if os.path.exists(path): + return path + + def find_config_files(project=None, prog=None, extension='.conf'): """Return a list of default configuration files. @@ -353,26 +399,12 @@ def find_config_files(project=None, prog=None, extension='.conf'): if prog is None: prog = os.path.basename(sys.argv[0]) - fix_path = lambda p: os.path.abspath(os.path.expanduser(p)) - - cfg_dirs = [ - fix_path(os.path.join('~', '.' + project)) if project else None, - fix_path('~'), - os.path.join('/etc', project) if project else None, - '/etc' - ] - cfg_dirs = filter(bool, cfg_dirs) - - def search_dirs(dirs, basename, extension): - for d in dirs: - path = os.path.join(d, '%s%s' % (basename, extension)) - if os.path.exists(path): - return path + cfg_dirs = _get_config_dirs(project) config_files = [] if project: - config_files.append(search_dirs(cfg_dirs, project, extension)) - config_files.append(search_dirs(cfg_dirs, prog, extension)) + config_files.append(_search_dirs(cfg_dirs, project, extension)) + config_files.append(_search_dirs(cfg_dirs, prog, extension)) return filter(bool, config_files) @@ -1060,6 +1092,34 @@ class ConfigOpts(collections.Mapping): This it the default behaviour.""" self._oparser.enable_interspersed_args() + def find_file(self, name): + """Locate a file located alongside the config files. + + Search for a file with the supplied basename in the directories + which we have already loaded config files from and other known + configuration directories. + + The directory, if any, supplied by the config_dir option is + searched first. Then the config_file option is iterated over + and each of the base directories of the config_files values + are searched. Failing both of these, the standard directories + searched by the module level find_config_files() function is + used. The first matching file is returned. + + :param basename: the filename, e.g. 'policy.json' + :returns: the path to a matching file, or None + """ + dirs = [] + if self.config_dir: + dirs.append(self.config_dir) + + for cf in reversed(self.config_file): + dirs.append(os.path.dirname(cf)) + + dirs.extend(_get_config_dirs(self.project)) + + return _search_dirs(dirs, name) + def log_opt_values(self, logger, lvl): """Log the value of all registered opts. diff --git a/tests/unit/test_cfg.py b/tests/unit/test_cfg.py index 1d8bdca..785a324 100644 --- a/tests/unit/test_cfg.py +++ b/tests/unit/test_cfg.py @@ -1,6 +1,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2011 Red Hat, Inc. +# Copyright 2012 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -80,9 +80,13 @@ class BaseTestCase(unittest.TestCase): self.remove_tempfiles() self.stubs.UnsetAll() - def create_tempfiles(self, files): + def create_tempfiles(self, files, ext='.conf'): for (basename, contents) in files: - (fd, path) = tempfile.mkstemp(prefix=basename, suffix='.conf') + if not os.path.isabs(basename): + (fd, path) = tempfile.mkstemp(prefix=basename, suffix=ext) + else: + path = basename + ext + fd = os.open(path, os.O_CREAT|os.O_WRONLY) self.tempfiles.append(path) try: os.write(fd, contents) @@ -1002,6 +1006,43 @@ class SadPathTestCase(BaseTestCase): self.conf.set_override, 'foo', 'bar', group='blaa') +class FindFileTestCase(BaseTestCase): + + def test_find_policy_file(self): + policy_file = '/etc/policy.json' + + self.stubs.Set(os.path, 'exists', lambda p: p == policy_file) + + self.assertEquals(self.conf.find_file('foo.json'), None) + self.assertEquals(self.conf.find_file('policy.json'), policy_file) + + def test_find_policy_file_with_config_file(self): + dir = tempfile.mkdtemp() + self.tempdirs.append(dir) + + paths = self.create_tempfiles([(os.path.join(dir, 'test.conf'), + '[DEFAULT]'), + (os.path.join(dir, 'policy.json'), + '{}')], + ext='') + + self.conf(['--config-file', paths[0]]) + + self.assertEquals(self.conf.find_file('policy.json'), paths[1]) + + def test_find_policy_file_with_config_dir(self): + dir = tempfile.mkdtemp() + self.tempdirs.append(dir) + + path = self.create_tempfiles([(os.path.join(dir, 'policy.json'), + '{}')], + ext='')[0] + + self.conf(['--config-dir', dir]) + + self.assertEquals(self.conf.find_file('policy.json'), path) + + class OptDumpingTestCase(BaseTestCase): class FakeLogger: |