-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
- Loading branch information
Showing
6 changed files
with
179 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import os | ||
from string import Template | ||
from collections import defaultdict | ||
|
||
import six | ||
|
||
from .errors import ConfigurationError | ||
|
||
|
||
def interpolate_environment_variables(service_dict): | ||
return dict( | ||
(key, interpolate_value(service_dict['name'], key, val)) | ||
for (key, val) in service_dict.items() | ||
) | ||
|
||
|
||
def interpolate_value(service_name, config_key, value): | ||
try: | ||
return recursive_interpolate(value) | ||
except InvalidInterpolation as e: | ||
raise ConfigurationError( | ||
'Invalid interpolation format for "{config_key}" option ' | ||
'in service "{service_name}": "{string}"' | ||
.format( | ||
config_key=config_key, | ||
service_name=service_name, | ||
string=e.string, | ||
) | ||
) | ||
|
||
|
||
def recursive_interpolate(obj): | ||
if isinstance(obj, six.string_types): | ||
return interpolate(obj, os.environ) | ||
elif isinstance(obj, dict): | ||
return dict( | ||
(key, recursive_interpolate(val)) | ||
for (key, val) in obj.items() | ||
) | ||
elif isinstance(obj, list): | ||
return map(recursive_interpolate, obj) | ||
else: | ||
return obj | ||
|
||
|
||
def interpolate(string, mapping): | ||
try: | ||
return Template(string).substitute(defaultdict(lambda: "", mapping)) | ||
except ValueError: | ||
raise InvalidInterpolation(string) | ||
|
||
|
||
class InvalidInterpolation(Exception): | ||
def __init__(self, string): | ||
self.string = string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
tests/fixtures/environment-interpolation/docker-compose.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
web: | ||
# unbracketed name | ||
image: $IMAGE | ||
|
||
# array element | ||
ports: | ||
- "${HOST_PORT}:8000" | ||
|
||
# dictionary item value | ||
labels: | ||
mylabel: "${LABEL_VALUE}" | ||
|
||
# unset value | ||
hostname: "host-${UNSET_VALUE}" | ||
|
||
# escaped interpolation | ||
command: "$${ESCAPED}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import unittest | ||
|
||
from compose.config.interpolation import interpolate, InvalidInterpolation | ||
|
||
|
||
class InterpolationTest(unittest.TestCase): | ||
def test_valid_interpolations(self): | ||
self.assertEqual(interpolate('$foo', dict(foo='hi')), 'hi') | ||
self.assertEqual(interpolate('${foo}', dict(foo='hi')), 'hi') | ||
|
||
self.assertEqual(interpolate('${subject} love you', dict(subject='i')), 'i love you') | ||
self.assertEqual(interpolate('i ${verb} you', dict(verb='love')), 'i love you') | ||
self.assertEqual(interpolate('i love ${object}', dict(object='you')), 'i love you') | ||
|
||
def test_empty_value(self): | ||
self.assertEqual(interpolate('${foo}', dict(foo='')), '') | ||
|
||
def test_unset_value(self): | ||
self.assertEqual(interpolate('${foo}', dict()), '') | ||
|
||
def test_escaped_interpolation(self): | ||
self.assertEqual(interpolate('$${foo}', dict(foo='hi')), '${foo}') | ||
|
||
def test_invalid_strings(self): | ||
self.assertRaises(InvalidInterpolation, lambda: interpolate('${', dict())) | ||
self.assertRaises(InvalidInterpolation, lambda: interpolate('$}', dict())) | ||
self.assertRaises(InvalidInterpolation, lambda: interpolate('${}', dict())) | ||
self.assertRaises(InvalidInterpolation, lambda: interpolate('${ }', dict())) | ||
self.assertRaises(InvalidInterpolation, lambda: interpolate('${ foo}', dict())) | ||
self.assertRaises(InvalidInterpolation, lambda: interpolate('${foo }', dict())) | ||
self.assertRaises(InvalidInterpolation, lambda: interpolate('${foo!}', dict())) |