Rev 6395: Configuration option value can be overridden by os environ variables in file:///home/vila/src/bzr/bugs/907279-override-from-env/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Thu Dec 22 08:53:35 UTC 2011
At file:///home/vila/src/bzr/bugs/907279-override-from-env/
------------------------------------------------------------
revno: 6395
revision-id: v.ladeuil+lp at free.fr-20111222085335-modhecpx6s1io7ku
parent: v.ladeuil+lp at free.fr-20111221142526-pnwau0xnalimujts
fixes bug: https://launchpad.net/bugs/907279
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 907279-override-from-env
timestamp: Thu 2011-12-22 09:53:35 +0100
message:
Configuration option value can be overridden by os environ variables
-------------- next part --------------
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py 2011-12-21 14:25:26 +0000
+++ b/bzrlib/config.py 2011-12-22 08:53:35 +0000
@@ -2343,12 +2343,16 @@
encoutered, in which config files it can be stored.
"""
- def __init__(self, name, default=None, default_from_env=None,
+ def __init__(self, name, override_from_env=None,
+ default=None, default_from_env=None,
help=None, from_unicode=None, invalid=None):
"""Build an option definition.
:param name: the name used to refer to the option.
+ :param override_from_env: A list of environment variables which can
+ provide override any configuration setting.
+
:param default: the default value to use when none exist in the config
stores. This is either a string that ``from_unicode`` will convert
into the proper type, a callable returning a unicode string so that
@@ -2373,9 +2377,12 @@
'warning' (emit a warning), 'error' (emit an error message and
terminates).
"""
+ if override_from_env is None:
+ override_from_env = []
if default_from_env is None:
default_from_env = []
self.name = name
+ self.override_from_env = override_from_env
# Convert the default value to a unicode string so all values are
# strings internally before conversion (via from_unicode) is attempted.
if default is None:
@@ -2420,6 +2427,17 @@
raise errors.ConfigOptionValueError(self.name, unicode_value)
return converted
+ def get_override(self):
+ value = None
+ for var in self.override_from_env:
+ try:
+ # If the env variable is defined, its value takes precedence
+ value = os.environ[var].decode(osutils.get_user_encoding())
+ break
+ except KeyError:
+ continue
+ return value
+
def get_default(self):
value = None
for var in self.default_from_env:
@@ -3353,17 +3371,6 @@
if expand is None:
expand = _get_expand_default_value()
value = None
- # Ensuring lazy loading is achieved by delaying section matching (which
- # implies querying the persistent storage) until it can't be avoided
- # anymore by using callables to describe (possibly empty) section
- # lists.
- for sections in self.sections_def:
- for store, section in sections():
- value = section.get(name)
- if value is not None:
- break
- if value is not None:
- break
# If the option is registered, it may provide additional info about
# value handling
try:
@@ -3371,6 +3378,7 @@
except KeyError:
# Not registered
opt = None
+
def expand_and_convert(val):
# This may need to be called twice if the value is None or ends up
# being None during expansion or conversion.
@@ -3385,11 +3393,29 @@
if opt is not None:
val = opt.convert_from_unicode(val)
return val
- value = expand_and_convert(value)
- if opt is not None and value is None:
- # If the option is registered, it may provide a default value
- value = opt.get_default()
- value = expand_and_convert(value)
+
+ # First of all, check if the environment can override the configuration
+ # value
+ if opt is not None and opt.override_from_env:
+ value = opt.get_override()
+ value = expand_and_convert(value)
+ if value is None:
+ # Ensuring lazy loading is achieved by delaying section matching
+ # (which implies querying the persistent storage) until it can't be
+ # avoided anymore by using callables to describe (possibly empty)
+ # section lists.
+ for sections in self.sections_def:
+ for store, section in sections():
+ value = section.get(name)
+ if value is not None:
+ break
+ if value is not None:
+ break
+ value = expand_and_convert(value)
+ if opt is not None and value is None:
+ # If the option is registered, it may provide a default value
+ value = opt.get_default()
+ value = expand_and_convert(value)
for hook in ConfigHooks['get']:
hook(self, name, value)
return value
=== modified file 'bzrlib/tests/test_config.py'
--- a/bzrlib/tests/test_config.py 2011-12-21 14:25:26 +0000
+++ b/bzrlib/tests/test_config.py 2011-12-22 08:53:35 +0000
@@ -3395,6 +3395,36 @@
self.assertRaises(TypeError, conf_stack.get, 'foo')
+class TestStackWithSimpleStore(tests.TestCase):
+
+ def setUp(self):
+ super(TestStackWithSimpleStore, self).setUp()
+ self.overrideAttr(config, 'option_registry', config.OptionRegistry())
+ self.registry = config.option_registry
+
+ def get_conf(self, content=None):
+ return config.MemoryStack(content)
+
+
+ def test_override_value_from_env(self):
+ self.registry.register(
+ config.Option('foo', default='bar', override_from_env=['FOO']))
+ self.overrideEnv('FOO', 'quux')
+ # Env variable provides a default taking over the option one
+ conf = self.get_conf('foo=store')
+ self.assertEquals('quux', conf.get('foo'))
+
+ def test_first_override_value_from_env_wins(self):
+ self.registry.register(
+ config.Option('foo', default='bar',
+ override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
+ self.overrideEnv('FOO', 'foo')
+ self.overrideEnv('BAZ', 'baz')
+ # The first env var set wins
+ conf = self.get_conf('foo=store')
+ self.assertEquals('foo', conf.get('foo'))
+
+
class TestMemoryStack(tests.TestCase):
def test_get(self):
More information about the bazaar-commits
mailing list