mirror of
https://github.com/containers/podman-compose.git
synced 2025-04-29 20:04:46 +02:00
move logic from rec_merge to normalize_service
Signed-off-by: Sergei Biriukov <svbiriukov@gmail.com>
This commit is contained in:
parent
d1509468c3
commit
79bfad103c
@ -61,15 +61,6 @@ def is_list(list_object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_list_of_str(list_of_str_object):
|
|
||||||
if is_list(list_of_str_object):
|
|
||||||
for element in list_of_str_object:
|
|
||||||
if not is_str(element):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# identity filter
|
# identity filter
|
||||||
def filteri(a):
|
def filteri(a):
|
||||||
return filter(lambda i: i, a)
|
return filter(lambda i: i, a)
|
||||||
@ -1264,6 +1255,10 @@ def normalize_service(service, sub_dir=""):
|
|||||||
service["build"] = context
|
service["build"] = context
|
||||||
else:
|
else:
|
||||||
service["build"]["context"] = context
|
service["build"]["context"] = context
|
||||||
|
for key in ("command", "entrypoint"):
|
||||||
|
if key in service:
|
||||||
|
if is_str(service[key]):
|
||||||
|
service[key] = shlex.split(service[key])
|
||||||
for key in ("env_file", "security_opt", "volumes"):
|
for key in ("env_file", "security_opt", "volumes"):
|
||||||
if key not in service:
|
if key not in service:
|
||||||
continue
|
continue
|
||||||
@ -1300,20 +1295,6 @@ def clone(value):
|
|||||||
return value.copy() if is_list(value) or is_dict(value) else value
|
return value.copy() if is_list(value) or is_dict(value) else value
|
||||||
|
|
||||||
|
|
||||||
def clone_shell_value(target, key, value):
|
|
||||||
if is_str(value):
|
|
||||||
target[key] = shlex.split(value)
|
|
||||||
else:
|
|
||||||
target[key] = clone(value)
|
|
||||||
|
|
||||||
|
|
||||||
def check_shell_value_type(key, value):
|
|
||||||
if not is_str(value) and not is_list_of_str(value):
|
|
||||||
raise ValueError(
|
|
||||||
f"can't merge value of [{key}]: must be a string or a list of strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def rec_merge_one(target, source):
|
def rec_merge_one(target, source):
|
||||||
"""
|
"""
|
||||||
update target from source recursively
|
update target from source recursively
|
||||||
@ -1322,26 +1303,17 @@ def rec_merge_one(target, source):
|
|||||||
for key, value in source.items():
|
for key, value in source.items():
|
||||||
if key in target:
|
if key in target:
|
||||||
continue
|
continue
|
||||||
if key in ("command", "entrypoint"):
|
target[key] = clone(value)
|
||||||
check_shell_value_type(key, value)
|
|
||||||
clone_shell_value(target, key, value)
|
|
||||||
else:
|
|
||||||
target[key] = clone(value)
|
|
||||||
done.add(key)
|
done.add(key)
|
||||||
for key, value in target.items():
|
for key, value in target.items():
|
||||||
if key in done:
|
if key in done:
|
||||||
continue
|
continue
|
||||||
if key in ("command", "entrypoint"):
|
|
||||||
if key not in source:
|
|
||||||
check_shell_value_type(key, value)
|
|
||||||
clone_shell_value(target, key, value)
|
|
||||||
else:
|
|
||||||
check_shell_value_type(key, source[key])
|
|
||||||
clone_shell_value(target, key, source[key])
|
|
||||||
continue
|
|
||||||
if key not in source:
|
if key not in source:
|
||||||
continue
|
continue
|
||||||
value2 = source[key]
|
value2 = source[key]
|
||||||
|
if key in ("command", "entrypoint"):
|
||||||
|
target[key] = clone(value2)
|
||||||
|
continue
|
||||||
if not isinstance(value2, type(value)):
|
if not isinstance(value2, type(value)):
|
||||||
value_type = type(value)
|
value_type = type(value)
|
||||||
value2_type = type(value2)
|
value2_type = type(value2)
|
||||||
|
121
pytests/test_can_merge_cmd_ent.py
Normal file
121
pytests/test_can_merge_cmd_ent.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import copy
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import yaml
|
||||||
|
from podman_compose import normalize_service, PodmanCompose
|
||||||
|
|
||||||
|
test_keys = ["command", "entrypoint"]
|
||||||
|
|
||||||
|
test_cases_normalise_pre_merge = [
|
||||||
|
({"$$$": []}, {"$$$": []}),
|
||||||
|
({"$$$": ["sh"]}, {"$$$": ["sh"]}),
|
||||||
|
({"$$$": ["sh", "-c", "date"]}, {"$$$": ["sh", "-c", "date"]}),
|
||||||
|
({"$$$": "sh"}, {"$$$": ["sh"]}),
|
||||||
|
({"$$$": "sleep infinity"}, {"$$$": ["sleep", "infinity"]}),
|
||||||
|
(
|
||||||
|
{"$$$": "bash -c 'sleep infinity'"},
|
||||||
|
{"$$$": ["bash", "-c", "sleep infinity"]},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
test_cases_merges = [
|
||||||
|
({}, {"$$$": []}, {"$$$": []}),
|
||||||
|
({"$$$": []}, {}, {"$$$": []}),
|
||||||
|
({"$$$": []}, {"$$$": "sh-2"}, {"$$$": ["sh-2"]}),
|
||||||
|
({"$$$": "sh-2"}, {"$$$": []}, {"$$$": []}),
|
||||||
|
({}, {"$$$": "sh"}, {"$$$": ["sh"]}),
|
||||||
|
({"$$$": "sh"}, {}, {"$$$": ["sh"]}),
|
||||||
|
({"$$$": "sh-1"}, {"$$$": "sh-2"}, {"$$$": ["sh-2"]}),
|
||||||
|
({"$$$": ["sh-1"]}, {"$$$": "sh-2"}, {"$$$": ["sh-2"]}),
|
||||||
|
({"$$$": "sh-1"}, {"$$$": ["sh-2"]}, {"$$$": ["sh-2"]}),
|
||||||
|
({"$$$": "sh-1"}, {"$$$": ["sh-2", "sh-3"]}, {"$$$": ["sh-2", "sh-3"]}),
|
||||||
|
({"$$$": ["sh-1"]}, {"$$$": ["sh-2", "sh-3"]}, {"$$$": ["sh-2", "sh-3"]}),
|
||||||
|
({"$$$": ["sh-1", "sh-2"]}, {"$$$": ["sh-3", "sh-4"]}, {"$$$": ["sh-3", "sh-4"]}),
|
||||||
|
({}, {"$$$": ["sh-3", "sh 4"]}, {"$$$": ["sh-3", "sh 4"]}),
|
||||||
|
({"$$$": "sleep infinity"}, {"$$$": "sh"}, {"$$$": ["sh"]}),
|
||||||
|
({"$$$": "sh"}, {"$$$": "sleep infinity"}, {"$$$": ["sleep", "infinity"]}),
|
||||||
|
(
|
||||||
|
{},
|
||||||
|
{"$$$": "bash -c 'sleep infinity'"},
|
||||||
|
{"$$$": ["bash", "-c", "sleep infinity"]},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def template_to_expression(base, override, expected, key):
|
||||||
|
base_copy = copy.deepcopy(base)
|
||||||
|
override_copy = copy.deepcopy(override)
|
||||||
|
expected_copy = copy.deepcopy(expected)
|
||||||
|
|
||||||
|
expected_copy[key] = expected_copy.pop("$$$")
|
||||||
|
if "$$$" in base:
|
||||||
|
base_copy[key] = base_copy.pop("$$$")
|
||||||
|
if "$$$" in override:
|
||||||
|
override_copy[key] = override_copy.pop("$$$")
|
||||||
|
return base_copy, override_copy, expected_copy
|
||||||
|
|
||||||
|
|
||||||
|
def test_normalize_service():
|
||||||
|
for test_input_template, expected_template in test_cases_normalise_pre_merge:
|
||||||
|
for key in test_keys:
|
||||||
|
test_input, _, expected = template_to_expression(
|
||||||
|
test_input_template, {}, expected_template, key
|
||||||
|
)
|
||||||
|
test_input = normalize_service(test_input)
|
||||||
|
test_result = expected == test_input
|
||||||
|
if not test_result:
|
||||||
|
print("base_template: ", test_input_template)
|
||||||
|
print("expected: ", expected)
|
||||||
|
print("actual: ", test_input)
|
||||||
|
assert test_result
|
||||||
|
|
||||||
|
|
||||||
|
def test__parse_compose_file_when_multiple_composes() -> None:
|
||||||
|
for base_template, override_template, expected_template in copy.deepcopy(
|
||||||
|
test_cases_merges
|
||||||
|
):
|
||||||
|
for key in test_keys:
|
||||||
|
base, override, expected = template_to_expression(
|
||||||
|
base_template, override_template, expected_template, key
|
||||||
|
)
|
||||||
|
compose_test_1 = {"services": {"test-service": base}}
|
||||||
|
compose_test_2 = {"services": {"test-service": override}}
|
||||||
|
dump_yaml(compose_test_1, "test-compose-1.yaml")
|
||||||
|
dump_yaml(compose_test_2, "test-compose-2.yaml")
|
||||||
|
|
||||||
|
podman_compose = PodmanCompose()
|
||||||
|
set_args(podman_compose, ["test-compose-1.yaml", "test-compose-2.yaml"])
|
||||||
|
|
||||||
|
podman_compose._parse_compose_file() # pylint: disable=protected-access
|
||||||
|
|
||||||
|
actual = {}
|
||||||
|
if podman_compose.services:
|
||||||
|
podman_compose.services["test-service"].pop("_deps")
|
||||||
|
actual = podman_compose.services["test-service"]
|
||||||
|
if actual != expected:
|
||||||
|
print("compose: ", base)
|
||||||
|
print("override: ", override)
|
||||||
|
print("result: ", expected)
|
||||||
|
|
||||||
|
assert expected == actual
|
||||||
|
|
||||||
|
|
||||||
|
def set_args(podman_compose: PodmanCompose, file_names: list[str]) -> None:
|
||||||
|
podman_compose.global_args = argparse.Namespace()
|
||||||
|
podman_compose.global_args.file = file_names
|
||||||
|
podman_compose.global_args.project_name = None
|
||||||
|
podman_compose.global_args.env_file = None
|
||||||
|
podman_compose.global_args.profile = []
|
||||||
|
podman_compose.global_args.in_pod = True
|
||||||
|
|
||||||
|
|
||||||
|
def dump_yaml(compose: dict, name: str) -> None:
|
||||||
|
with open(name, "w", encoding="utf-8") as outfile:
|
||||||
|
yaml.safe_dump(compose, outfile, default_flow_style=False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_clean_test_yamls() -> None:
|
||||||
|
test_files = ["test-compose-1.yaml", "test-compose-2.yaml"]
|
||||||
|
for file in test_files:
|
||||||
|
if os.path.exists(file):
|
||||||
|
os.remove(file)
|
@ -1,10 +0,0 @@
|
|||||||
from podman_compose import is_list_of_str
|
|
||||||
|
|
||||||
|
|
||||||
def test_is_list_of_str():
|
|
||||||
assert is_list_of_str([])
|
|
||||||
assert is_list_of_str(["foo", "bar"])
|
|
||||||
assert not is_list_of_str(["foo", 1])
|
|
||||||
assert not is_list_of_str("foo")
|
|
||||||
assert not is_list_of_str(1)
|
|
||||||
assert not is_list_of_str(None)
|
|
@ -1,83 +0,0 @@
|
|||||||
import copy
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from podman_compose import rec_merge_one
|
|
||||||
|
|
||||||
|
|
||||||
test_keys = ["command", "entrypoint"]
|
|
||||||
test_cases = [
|
|
||||||
({}, {"$$$": []}, {"$$$": []}),
|
|
||||||
({"$$$": []}, {}, {"$$$": []}),
|
|
||||||
({"$$$": []}, {"$$$": "sh-2"}, {"$$$": ["sh-2"]}),
|
|
||||||
({"$$$": "sh-2"}, {"$$$": []}, {"$$$": []}),
|
|
||||||
({}, {"$$$": "sh"}, {"$$$": ["sh"]}),
|
|
||||||
({"$$$": "sh"}, {}, {"$$$": ["sh"]}),
|
|
||||||
({"$$$": "sh-1"}, {"$$$": "sh-2"}, {"$$$": ["sh-2"]}),
|
|
||||||
({"$$$": ["sh-1"]}, {"$$$": "sh-2"}, {"$$$": ["sh-2"]}),
|
|
||||||
({"$$$": "sh-1"}, {"$$$": ["sh-2"]}, {"$$$": ["sh-2"]}),
|
|
||||||
({"$$$": "sh-1"}, {"$$$": ["sh-2", "sh-3"]}, {"$$$": ["sh-2", "sh-3"]}),
|
|
||||||
({"$$$": ["sh-1"]}, {"$$$": ["sh-2", "sh-3"]}, {"$$$": ["sh-2", "sh-3"]}),
|
|
||||||
({"$$$": ["sh-1", "sh-2"]}, {"$$$": ["sh-3", "sh-4"]}, {"$$$": ["sh-3", "sh-4"]}),
|
|
||||||
({}, {"$$$": ["sh-3", "sh 4"]}, {"$$$": ["sh-3", "sh 4"]}),
|
|
||||||
({"$$$": "sleep infinity"}, {"$$$": "sh"}, {"$$$": ["sh"]}),
|
|
||||||
({"$$$": "sh"}, {"$$$": "sleep infinity"}, {"$$$": ["sleep", "infinity"]}),
|
|
||||||
(
|
|
||||||
{},
|
|
||||||
{"$$$": "bash -c 'sleep infinity'"},
|
|
||||||
{"$$$": ["bash", "-c", "sleep infinity"]},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
test_cases_with_exceptions = [
|
|
||||||
({}, {"$$$": 1234}, ValueError),
|
|
||||||
({"$$$": 1234}, {}, ValueError),
|
|
||||||
({"$$$": 1234}, {"$$$": 1234}, ValueError),
|
|
||||||
({"$$$": {}}, {}, ValueError),
|
|
||||||
({}, {"$$$": {}}, ValueError),
|
|
||||||
({"$$$": {}}, {"$$$": {}}, ValueError),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def template_to_expression(base, override, expected, key):
|
|
||||||
base_copy = copy.deepcopy(base)
|
|
||||||
override_copy = copy.deepcopy(override)
|
|
||||||
expected_copy = copy.deepcopy(expected)
|
|
||||||
|
|
||||||
expected_copy[key] = expected_copy.pop("$$$")
|
|
||||||
if "$$$" in base:
|
|
||||||
base_copy[key] = base_copy.pop("$$$")
|
|
||||||
if "$$$" in override:
|
|
||||||
override_copy[key] = override_copy.pop("$$$")
|
|
||||||
return base_copy, override_copy, expected_copy
|
|
||||||
|
|
||||||
|
|
||||||
def test_rec_merge_one_for_command_and_entrypoint():
|
|
||||||
for base_template, override_template, expected_template in test_cases:
|
|
||||||
for key in test_keys:
|
|
||||||
base, override, expected = template_to_expression(
|
|
||||||
base_template, override_template, expected_template, key
|
|
||||||
)
|
|
||||||
|
|
||||||
base = rec_merge_one(base, override)
|
|
||||||
test_result = expected == base
|
|
||||||
if not test_result:
|
|
||||||
print("base_template: ", base_template)
|
|
||||||
print("override_template: ", override_template)
|
|
||||||
print("expected: ", expected)
|
|
||||||
print("actual: ", base)
|
|
||||||
assert test_result
|
|
||||||
|
|
||||||
for (
|
|
||||||
base_template,
|
|
||||||
override_template,
|
|
||||||
expected_exception,
|
|
||||||
) in test_cases_with_exceptions:
|
|
||||||
for key in test_keys:
|
|
||||||
base, override, expected = template_to_expression(
|
|
||||||
base_template, override_template, {"$$$": ""}, key
|
|
||||||
)
|
|
||||||
|
|
||||||
with pytest.raises(expected_exception):
|
|
||||||
base = rec_merge_one(base, override)
|
|
||||||
print("base_template: ", base_template)
|
|
||||||
print("override_template: ", override_template)
|
|
||||||
print("expected: ", expected_exception)
|
|
Loading…
Reference in New Issue
Block a user