Skip to content

Commit b24a60b

Browse files
committed
Merge pull request #1226 from aanand/merge-multi-value-options
Merge multi-value options when extending (cherry picked from commit e708f4f) Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
1 parent 461b600 commit b24a60b

2 files changed

Lines changed: 90 additions & 11 deletions

File tree

compose/config.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,23 @@ def merge_service_dicts(base, override):
195195
if 'build' in override and 'image' in d:
196196
del d['image']
197197

198-
for k in ALLOWED_KEYS:
199-
if k not in ['environment', 'volumes']:
200-
if k in override:
201-
d[k] = override[k]
198+
list_keys = ['ports', 'expose', 'external_links']
199+
200+
for key in list_keys:
201+
if key in base or key in override:
202+
d[key] = base.get(key, []) + override.get(key, [])
203+
204+
list_or_string_keys = ['dns', 'dns_search']
205+
206+
for key in list_or_string_keys:
207+
if key in base or key in override:
208+
d[key] = to_list(base.get(key)) + to_list(override.get(key))
209+
210+
already_merged_keys = ['environment', 'volumes'] + list_keys + list_or_string_keys
211+
212+
for k in set(ALLOWED_KEYS) - set(already_merged_keys):
213+
if k in override:
214+
d[k] = override[k]
202215

203216
return d
204217

@@ -354,6 +367,15 @@ def expand_path(working_dir, path):
354367
return os.path.abspath(os.path.join(working_dir, path))
355368

356369

370+
def to_list(value):
371+
if value is None:
372+
return []
373+
elif isinstance(value, six.string_types):
374+
return [value]
375+
else:
376+
return value
377+
378+
357379
def get_service_name_from_net(net_config):
358380
if not net_config:
359381
return

tests/unit/config_test.py

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,40 +39,40 @@ def test_config_validation(self):
3939
config.make_service_dict('foo', {'ports': ['8000']})
4040

4141

42-
class MergeTest(unittest.TestCase):
43-
def test_merge_volumes_empty(self):
42+
class MergeVolumesTest(unittest.TestCase):
43+
def test_empty(self):
4444
service_dict = config.merge_service_dicts({}, {})
4545
self.assertNotIn('volumes', service_dict)
4646

47-
def test_merge_volumes_no_override(self):
47+
def test_no_override(self):
4848
service_dict = config.merge_service_dicts(
4949
{'volumes': ['/foo:/code', '/data']},
5050
{},
5151
)
5252
self.assertEqual(set(service_dict['volumes']), set(['/foo:/code', '/data']))
5353

54-
def test_merge_volumes_no_base(self):
54+
def test_no_base(self):
5555
service_dict = config.merge_service_dicts(
5656
{},
5757
{'volumes': ['/bar:/code']},
5858
)
5959
self.assertEqual(set(service_dict['volumes']), set(['/bar:/code']))
6060

61-
def test_merge_volumes_override_explicit_path(self):
61+
def test_override_explicit_path(self):
6262
service_dict = config.merge_service_dicts(
6363
{'volumes': ['/foo:/code', '/data']},
6464
{'volumes': ['/bar:/code']},
6565
)
6666
self.assertEqual(set(service_dict['volumes']), set(['/bar:/code', '/data']))
6767

68-
def test_merge_volumes_add_explicit_path(self):
68+
def test_add_explicit_path(self):
6969
service_dict = config.merge_service_dicts(
7070
{'volumes': ['/foo:/code', '/data']},
7171
{'volumes': ['/bar:/code', '/quux:/data']},
7272
)
7373
self.assertEqual(set(service_dict['volumes']), set(['/bar:/code', '/quux:/data']))
7474

75-
def test_merge_volumes_remove_explicit_path(self):
75+
def test_remove_explicit_path(self):
7676
service_dict = config.merge_service_dicts(
7777
{'volumes': ['/foo:/code', '/quux:/data']},
7878
{'volumes': ['/bar:/code', '/data']},
@@ -113,6 +113,63 @@ def test_merge_build_or_image_override_with_other(self):
113113
)
114114

115115

116+
class MergeListsTest(unittest.TestCase):
117+
def test_empty(self):
118+
service_dict = config.merge_service_dicts({}, {})
119+
self.assertNotIn('ports', service_dict)
120+
121+
def test_no_override(self):
122+
service_dict = config.merge_service_dicts(
123+
{'ports': ['10:8000', '9000']},
124+
{},
125+
)
126+
self.assertEqual(set(service_dict['ports']), set(['10:8000', '9000']))
127+
128+
def test_no_base(self):
129+
service_dict = config.merge_service_dicts(
130+
{},
131+
{'ports': ['10:8000', '9000']},
132+
)
133+
self.assertEqual(set(service_dict['ports']), set(['10:8000', '9000']))
134+
135+
def test_add_item(self):
136+
service_dict = config.merge_service_dicts(
137+
{'ports': ['10:8000', '9000']},
138+
{'ports': ['20:8000']},
139+
)
140+
self.assertEqual(set(service_dict['ports']), set(['10:8000', '9000', '20:8000']))
141+
142+
143+
class MergeStringsOrListsTest(unittest.TestCase):
144+
def test_no_override(self):
145+
service_dict = config.merge_service_dicts(
146+
{'dns': '8.8.8.8'},
147+
{},
148+
)
149+
self.assertEqual(set(service_dict['dns']), set(['8.8.8.8']))
150+
151+
def test_no_base(self):
152+
service_dict = config.merge_service_dicts(
153+
{},
154+
{'dns': '8.8.8.8'},
155+
)
156+
self.assertEqual(set(service_dict['dns']), set(['8.8.8.8']))
157+
158+
def test_add_string(self):
159+
service_dict = config.merge_service_dicts(
160+
{'dns': ['8.8.8.8']},
161+
{'dns': '9.9.9.9'},
162+
)
163+
self.assertEqual(set(service_dict['dns']), set(['8.8.8.8', '9.9.9.9']))
164+
165+
def test_add_list(self):
166+
service_dict = config.merge_service_dicts(
167+
{'dns': '8.8.8.8'},
168+
{'dns': ['9.9.9.9']},
169+
)
170+
self.assertEqual(set(service_dict['dns']), set(['8.8.8.8', '9.9.9.9']))
171+
172+
116173
class EnvTest(unittest.TestCase):
117174
def test_parse_environment_as_list(self):
118175
environment =[

0 commit comments

Comments
 (0)