# HG changeset patch # User Denis Laxalde # Date 1474630566 -7200 # Node ID a9f26de5ea6ceddfe9534e17bd42d6cfb0d79a8d # Parent d2fcd81b7ca9ad0efa3df09cef1a69182c1c2413 Let configuration option be overridden by environment variables Related to #13889793. diff -r d2fcd81b7ca9 -r a9f26de5ea6c cubicweb/cwconfig.py --- a/cubicweb/cwconfig.py Fri Sep 23 09:51:10 2016 +0200 +++ b/cubicweb/cwconfig.py Fri Sep 23 13:36:06 2016 +0200 @@ -206,7 +206,7 @@ from cubicweb import (CW_SOFTWARE_ROOT, CW_MIGRATION_MAP, ConfigurationError, Binary, _) -from cubicweb.toolsutils import create_dir +from cubicweb.toolsutils import create_dir, option_value_from_env CONFIGURATIONS = [] @@ -416,6 +416,12 @@ 'group': 'email', 'level': 3, }), ) + + def __getitem__(self, key): + """Get configuration option, by first looking at environmnent.""" + file_value = super(CubicWebNoAppConfiguration, self).__getitem__(key) + return option_value_from_env(key, file_value) + # static and class methods used to get instance independant resources ## @staticmethod def cubicweb_version(): diff -r d2fcd81b7ca9 -r a9f26de5ea6c cubicweb/test/unittest_cwconfig.py --- a/cubicweb/test/unittest_cwconfig.py Fri Sep 23 09:51:10 2016 +0200 +++ b/cubicweb/test/unittest_cwconfig.py Fri Sep 23 13:36:06 2016 +0200 @@ -203,6 +203,15 @@ from cubes import file self.assertEqual(file.__path__, [join(self.custom_cubes_dir, 'file')]) + def test_config_value_from_environment(self): + self.assertIsNone(self.config['base-url']) + os.environ['CW_BASE_URL'] = 'https://www.cubicweb.org' + try: + self.assertEqual(self.config['base-url'], + 'https://www.cubicweb.org') + finally: + del os.environ['CW_BASE_URL'] + class FindPrefixTC(unittest.TestCase): def make_dirs(self, *args): diff -r d2fcd81b7ca9 -r a9f26de5ea6c cubicweb/test/unittest_toolsutils.py --- a/cubicweb/test/unittest_toolsutils.py Fri Sep 23 09:51:10 2016 +0200 +++ b/cubicweb/test/unittest_toolsutils.py Fri Sep 23 13:36:06 2016 +0200 @@ -17,10 +17,12 @@ # with CubicWeb. If not, see . +import os import tempfile import unittest -from cubicweb.toolsutils import RQLExecuteMatcher, read_config +from cubicweb.toolsutils import (RQLExecuteMatcher, option_value_from_env, + read_config) class RQLExecuteMatcherTests(unittest.TestCase): @@ -78,6 +80,15 @@ class ToolsUtilsTC(unittest.TestCase): + def test_option_value_from_env(self): + os.environ['CW_DB_HOST'] = 'here' + try: + self.assertEqual(option_value_from_env('db-host'), 'here') + self.assertEqual(option_value_from_env('db-host', 'nothere'), 'here') + self.assertEqual(option_value_from_env('db-hots', 'nothere'), 'nothere') + finally: + del os.environ['CW_DB_HOST'] + def test_read_config(self): with tempfile.NamedTemporaryFile() as f: f.write(SOURCES_CONTENT) @@ -96,6 +107,17 @@ } self.assertEqual(config, expected) + def test_read_config_env(self): + os.environ['CW_DB_HOST'] = 'here' + try: + with tempfile.NamedTemporaryFile() as f: + f.write(SOURCES_CONTENT) + f.seek(0) + config = read_config(f.name) + finally: + del os.environ['CW_DB_HOST'] + self.assertEqual(config['system']['db-host'], 'here') + if __name__ == '__main__': unittest.main() diff -r d2fcd81b7ca9 -r a9f26de5ea6c cubicweb/toolsutils.py --- a/cubicweb/toolsutils.py Fri Sep 23 09:51:10 2016 +0200 +++ b/cubicweb/toolsutils.py Fri Sep 23 13:36:06 2016 +0200 @@ -170,6 +170,15 @@ print('-> set permissions to 0600 for %s' % filepath) chmod(filepath, 0o600) + +def option_value_from_env(option, default=None): + """Return the value of configuration `option` from cannonical environment + variable. + """ + envvar = ('CW_' + '_'.join(option.split('-'))).upper() + return os.environ.get(envvar, default) + + def read_config(config_file, raise_if_unreadable=False): """read some simple configuration from `config_file` and return it as a dictionary. If `raise_if_unreadable` is false (the default), an empty @@ -194,7 +203,7 @@ sys.stderr.write('ignoring malformed line\n%r\n' % line) continue option = option.strip().replace(' ', '_') - value = value.strip() + value = option_value_from_env(option, value.strip()) current[option] = value or None except IOError as ex: if raise_if_unreadable: