mirror of https://github.com/docker/compose.git
Support ${VAR:?err} syntax for mandatory variables
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
bcc13d7fae
commit
e400c05de0
|
@ -60,6 +60,15 @@ def interpolate_value(name, config_key, value, section, interpolator):
|
|||
name=name,
|
||||
section=section,
|
||||
string=e.string))
|
||||
except UnsetRequiredSubstitution as e:
|
||||
raise ConfigurationError(
|
||||
'Missing mandatory value for "{config_key}" option in {section} "{name}": {err}'.format(
|
||||
config_key=config_key,
|
||||
name=name,
|
||||
section=section,
|
||||
err=e.err
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def recursive_interpolate(obj, interpolator, config_path):
|
||||
|
@ -79,21 +88,54 @@ def recursive_interpolate(obj, interpolator, config_path):
|
|||
|
||||
|
||||
class TemplateWithDefaults(Template):
|
||||
idpattern = r'[_a-z][_a-z0-9]*(?::?-[^}]*)?'
|
||||
pattern = r"""
|
||||
%(delim)s(?:
|
||||
(?P<escaped>%(delim)s) |
|
||||
(?P<named>%(id)s) |
|
||||
{(?P<braced>%(bid)s)} |
|
||||
(?P<invalid>)
|
||||
)
|
||||
""" % {
|
||||
'delim': re.escape('$'),
|
||||
'id': r'[_a-z][_a-z0-9]*',
|
||||
'bid': r'[_a-z][_a-z0-9]*(?:(?P<sep>:?[-?])[^}]*)?',
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def process_braced_group(braced, sep, mapping):
|
||||
if ':-' == sep:
|
||||
var, _, default = braced.partition(':-')
|
||||
return mapping.get(var) or default
|
||||
elif '-' == sep:
|
||||
var, _, default = braced.partition('-')
|
||||
return mapping.get(var, default)
|
||||
|
||||
elif ':?' == sep:
|
||||
var, _, err = braced.partition(':?')
|
||||
result = mapping.get(var)
|
||||
if not result:
|
||||
raise UnsetRequiredSubstitution(err)
|
||||
return result
|
||||
elif '?' == sep:
|
||||
var, _, err = braced.partition('?')
|
||||
if var in mapping:
|
||||
return mapping.get(var)
|
||||
raise UnsetRequiredSubstitution(err)
|
||||
|
||||
# Modified from python2.7/string.py
|
||||
def substitute(self, mapping):
|
||||
# Helper function for .sub()
|
||||
|
||||
def convert(mo):
|
||||
# Check the most common path first.
|
||||
named = mo.group('named') or mo.group('braced')
|
||||
braced = mo.group('braced')
|
||||
if braced is not None:
|
||||
sep = mo.group('sep')
|
||||
result = self.process_braced_group(braced, sep, mapping)
|
||||
if result:
|
||||
return result
|
||||
|
||||
if named is not None:
|
||||
if ':-' in named:
|
||||
var, _, default = named.partition(':-')
|
||||
return mapping.get(var) or default
|
||||
if '-' in named:
|
||||
var, _, default = named.partition('-')
|
||||
return mapping.get(var, default)
|
||||
val = mapping[named]
|
||||
return '%s' % (val,)
|
||||
if mo.group('escaped') is not None:
|
||||
|
@ -110,6 +152,11 @@ class InvalidInterpolation(Exception):
|
|||
self.string = string
|
||||
|
||||
|
||||
class UnsetRequiredSubstitution(Exception):
|
||||
def __init__(self, custom_err_msg):
|
||||
self.err = custom_err_msg
|
||||
|
||||
|
||||
PATH_JOKER = '[^.]+'
|
||||
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ class ConsoleWarningFormatterTestCase(unittest.TestCase):
|
|||
def test_format_unicode_info(self):
|
||||
message = b'\xec\xa0\x95\xec\x88\x98\xec\xa0\x95'
|
||||
output = self.formatter.format(make_log_record(logging.INFO, message))
|
||||
print(output)
|
||||
assert output == message.decode('utf-8')
|
||||
|
||||
def test_format_unicode_warn(self):
|
||||
|
|
|
@ -9,6 +9,7 @@ from compose.config.interpolation import interpolate_environment_variables
|
|||
from compose.config.interpolation import Interpolator
|
||||
from compose.config.interpolation import InvalidInterpolation
|
||||
from compose.config.interpolation import TemplateWithDefaults
|
||||
from compose.config.interpolation import UnsetRequiredSubstitution
|
||||
from compose.const import COMPOSEFILE_V2_0 as V2_0
|
||||
from compose.const import COMPOSEFILE_V2_3 as V2_3
|
||||
from compose.const import COMPOSEFILE_V3_4 as V3_4
|
||||
|
@ -357,9 +358,46 @@ def test_interpolate_with_value(defaults_interpolator):
|
|||
def test_interpolate_missing_with_default(defaults_interpolator):
|
||||
assert defaults_interpolator("ok ${missing:-def}") == "ok def"
|
||||
assert defaults_interpolator("ok ${missing-def}") == "ok def"
|
||||
assert defaults_interpolator("ok ${BAR:-/non:-alphanumeric}") == "ok /non:-alphanumeric"
|
||||
|
||||
|
||||
def test_interpolate_with_empty_and_default_value(defaults_interpolator):
|
||||
assert defaults_interpolator("ok ${BAR:-def}") == "ok def"
|
||||
assert defaults_interpolator("ok ${BAR-def}") == "ok "
|
||||
|
||||
|
||||
def test_interpolate_mandatory_values(defaults_interpolator):
|
||||
assert defaults_interpolator("ok ${FOO:?bar}") == "ok first"
|
||||
assert defaults_interpolator("ok ${FOO?bar}") == "ok first"
|
||||
assert defaults_interpolator("ok ${BAR?bar}") == "ok "
|
||||
|
||||
with pytest.raises(UnsetRequiredSubstitution) as e:
|
||||
defaults_interpolator("not ok ${BAR:?high bar}")
|
||||
assert e.value.err == 'high bar'
|
||||
|
||||
with pytest.raises(UnsetRequiredSubstitution) as e:
|
||||
defaults_interpolator("not ok ${BAZ?dropped the bazz}")
|
||||
assert e.value.err == 'dropped the bazz'
|
||||
|
||||
|
||||
def test_interpolate_mandatory_no_err_msg(defaults_interpolator):
|
||||
with pytest.raises(UnsetRequiredSubstitution) as e:
|
||||
defaults_interpolator("not ok ${BAZ?}")
|
||||
|
||||
assert e.value.err == ''
|
||||
|
||||
|
||||
def test_interpolate_mixed_separators(defaults_interpolator):
|
||||
assert defaults_interpolator("ok ${BAR:-/non:-alphanumeric}") == "ok /non:-alphanumeric"
|
||||
assert defaults_interpolator("ok ${BAR:-:?wwegegr??:?}") == "ok :?wwegegr??:?"
|
||||
assert defaults_interpolator("ok ${BAR-:-hello}") == 'ok '
|
||||
|
||||
with pytest.raises(UnsetRequiredSubstitution) as e:
|
||||
defaults_interpolator("not ok ${BAR:?xazz:-redf}")
|
||||
assert e.value.err == 'xazz:-redf'
|
||||
|
||||
assert defaults_interpolator("ok ${BAR?...:?bar}") == "ok "
|
||||
|
||||
|
||||
def test_unbraced_separators(defaults_interpolator):
|
||||
assert defaults_interpolator("ok $FOO:-bar") == "ok first:-bar"
|
||||
assert defaults_interpolator("ok $BAZ?error") == "ok ?error"
|
||||
|
|
Loading…
Reference in New Issue