forked from extern/podman-compose
move logic from rec_merge to normalize_service
Signed-off-by: Sergei Biriukov <svbiriukov@gmail.com>
This commit is contained in:
parent
8c66b1cda7
commit
85d5d5dcc9
@ -1237,12 +1237,13 @@ class Podman:
|
||||
|
||||
|
||||
def normalize_service(service, sub_dir=""):
|
||||
# make `build.context` relative to sub_dir
|
||||
# TODO: should we make volume and secret relative too?
|
||||
if "build" in service:
|
||||
build = service["build"]
|
||||
if is_str(build):
|
||||
service["build"] = {"context": build}
|
||||
if sub_dir and "build" in service:
|
||||
build = service["build"]
|
||||
context = build if is_str(build) else build.get("context", None)
|
||||
context = context or ""
|
||||
context = build.get("context", None) or ""
|
||||
if context or sub_dir:
|
||||
if context.startswith("./"):
|
||||
context = context[2:]
|
||||
@ -1251,10 +1252,7 @@ def normalize_service(service, sub_dir=""):
|
||||
context = context.rstrip("/")
|
||||
if not context:
|
||||
context = "."
|
||||
if is_str(build):
|
||||
service["build"] = context
|
||||
else:
|
||||
service["build"]["context"] = context
|
||||
service["build"]["context"] = context
|
||||
for key in ("env_file", "security_opt", "volumes"):
|
||||
if key not in service:
|
||||
continue
|
||||
@ -1291,17 +1289,6 @@ def clone(value):
|
||||
return value.copy() if is_list(value) or is_dict(value) else value
|
||||
|
||||
|
||||
def parse_build(build):
|
||||
build_parsed = {}
|
||||
if is_str(build):
|
||||
build_parsed["context"] = build
|
||||
elif is_dict(build):
|
||||
build_parsed = build
|
||||
else:
|
||||
raise ValueError(f"invalid type of build value [{type(build)}]")
|
||||
return build_parsed
|
||||
|
||||
|
||||
def rec_merge_one(target, source):
|
||||
"""
|
||||
update target from source recursively
|
||||
@ -1310,21 +1297,11 @@ def rec_merge_one(target, source):
|
||||
for key, value in source.items():
|
||||
if key in target:
|
||||
continue
|
||||
if key == "build":
|
||||
target[key] = parse_build(value)
|
||||
else:
|
||||
target[key] = clone(value)
|
||||
target[key] = clone(value)
|
||||
done.add(key)
|
||||
for key, value in target.items():
|
||||
if key in done:
|
||||
continue
|
||||
if key == "build":
|
||||
target_parsed = parse_build(value)
|
||||
source_parsed = {}
|
||||
if key in source:
|
||||
source_parsed = parse_build(source[key])
|
||||
target["build"] = rec_merge_one(target_parsed, source_parsed)
|
||||
continue
|
||||
if key not in source:
|
||||
continue
|
||||
value2 = source[key]
|
||||
|
165
pytests/test_build_can_merge_str_and_dict.py
Normal file
165
pytests/test_build_can_merge_str_and_dict.py
Normal file
@ -0,0 +1,165 @@
|
||||
import copy
|
||||
import os
|
||||
import argparse
|
||||
import yaml
|
||||
from podman_compose import normalize_service, PodmanCompose
|
||||
|
||||
|
||||
test_cases_simple = [
|
||||
({"test": "test"}, {"test": "test"}),
|
||||
({"build": "."}, {"build": {"context": "."}}),
|
||||
({"build": "./dir-1"}, {"build": {"context": "./dir-1"}}),
|
||||
({"build": {"context": "./dir-1"}}, {"build": {"context": "./dir-1"}}),
|
||||
(
|
||||
{"build": {"dockerfile": "dockerfile-1"}},
|
||||
{"build": {"dockerfile": "dockerfile-1"}},
|
||||
),
|
||||
(
|
||||
{"build": {"context": "./dir-1", "dockerfile": "dockerfile-1"}},
|
||||
{"build": {"context": "./dir-1", "dockerfile": "dockerfile-1"}},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_normalize_service_simple():
|
||||
for test_case, expected in copy.deepcopy(test_cases_simple):
|
||||
test_original = copy.deepcopy(test_case)
|
||||
test_case = normalize_service(test_case)
|
||||
test_result = expected == test_case
|
||||
if not test_result:
|
||||
print("test: ", test_original)
|
||||
print("expected: ", expected)
|
||||
print("actual: ", test_case)
|
||||
assert test_result
|
||||
|
||||
|
||||
test_cases_sub_dir = [
|
||||
({"test": "test"}, {"test": "test"}),
|
||||
({"build": "."}, {"build": {"context": "./sub_dir/."}}),
|
||||
({"build": "./dir-1"}, {"build": {"context": "./sub_dir/dir-1"}}),
|
||||
({"build": {"context": "./dir-1"}}, {"build": {"context": "./sub_dir/dir-1"}}),
|
||||
(
|
||||
{"build": {"dockerfile": "dockerfile-1"}},
|
||||
{"build": {"context": "./sub_dir", "dockerfile": "dockerfile-1"}},
|
||||
),
|
||||
(
|
||||
{"build": {"context": "./dir-1", "dockerfile": "dockerfile-1"}},
|
||||
{"build": {"context": "./sub_dir/dir-1", "dockerfile": "dockerfile-1"}},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_normalize_service_with_sub_dir():
|
||||
for test_case, expected in copy.deepcopy(test_cases_sub_dir):
|
||||
test_original = copy.deepcopy(test_case)
|
||||
test_case = normalize_service(test_case, sub_dir="./sub_dir")
|
||||
test_result = expected == test_case
|
||||
if not test_result:
|
||||
print("test: ", test_original)
|
||||
print("expected: ", expected)
|
||||
print("actual: ", test_case)
|
||||
assert test_result
|
||||
|
||||
|
||||
test_cases_merges = [
|
||||
({}, {}, {}),
|
||||
({}, {"test": "test"}, {"test": "test"}),
|
||||
({"test": "test"}, {}, {"test": "test"}),
|
||||
({"test": "test-1"}, {"test": "test-2"}, {"test": "test-2"}),
|
||||
({}, {"build": "."}, {"build": {"context": "."}}),
|
||||
({"build": "."}, {}, {"build": {"context": "."}}),
|
||||
({"build": "./dir-1"}, {"build": "./dir-2"}, {"build": {"context": "./dir-2"}}),
|
||||
({}, {"build": {"context": "./dir-1"}}, {"build": {"context": "./dir-1"}}),
|
||||
({"build": {"context": "./dir-1"}}, {}, {"build": {"context": "./dir-1"}}),
|
||||
(
|
||||
{"build": {"context": "./dir-1"}},
|
||||
{"build": {"context": "./dir-2"}},
|
||||
{"build": {"context": "./dir-2"}},
|
||||
),
|
||||
(
|
||||
{},
|
||||
{"build": {"dockerfile": "dockerfile-1"}},
|
||||
{"build": {"dockerfile": "dockerfile-1"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "dockerfile-1"}},
|
||||
{},
|
||||
{"build": {"dockerfile": "dockerfile-1"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./dockerfile-1"}},
|
||||
{"build": {"dockerfile": "./dockerfile-2"}},
|
||||
{"build": {"dockerfile": "./dockerfile-2"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./dockerfile-1"}},
|
||||
{"build": {"context": "./dir-2"}},
|
||||
{"build": {"dockerfile": "./dockerfile-1", "context": "./dir-2"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./dockerfile-1", "context": "./dir-1"}},
|
||||
{"build": {"dockerfile": "./dockerfile-2", "context": "./dir-2"}},
|
||||
{"build": {"dockerfile": "./dockerfile-2", "context": "./dir-2"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./dockerfile-1"}},
|
||||
{"build": {"dockerfile": "./dockerfile-2", "args": ["ENV1=1"]}},
|
||||
{"build": {"dockerfile": "./dockerfile-2", "args": ["ENV1=1"]}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./dockerfile-2", "args": ["ENV1=1"]}},
|
||||
{"build": {"dockerfile": "./dockerfile-1"}},
|
||||
{"build": {"dockerfile": "./dockerfile-1", "args": ["ENV1=1"]}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./dockerfile-2", "args": ["ENV1=1"]}},
|
||||
{"build": {"dockerfile": "./dockerfile-1", "args": ["ENV2=2"]}},
|
||||
{"build": {"dockerfile": "./dockerfile-1", "args": ["ENV1=1", "ENV2=2"]}},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test__parse_compose_file_when_multiple_composes() -> None:
|
||||
for test_input, test_override, expected_result in copy.deepcopy(test_cases_merges):
|
||||
compose_test_1 = {"services": {"test-service": test_input}}
|
||||
compose_test_2 = {"services": {"test-service": test_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_compose = {}
|
||||
if podman_compose.services:
|
||||
podman_compose.services["test-service"].pop("_deps")
|
||||
actual_compose = podman_compose.services["test-service"]
|
||||
if actual_compose != expected_result:
|
||||
print("compose: ", test_input)
|
||||
print("override: ", test_override)
|
||||
print("result: ", expected_result)
|
||||
compose_expected = expected_result
|
||||
|
||||
assert compose_expected == actual_compose
|
||||
|
||||
|
||||
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,91 +0,0 @@
|
||||
import copy
|
||||
|
||||
import pytest
|
||||
|
||||
from podman_compose import rec_merge_one
|
||||
|
||||
test_cases = [
|
||||
({}, {"build": "."}, {"build": {"context": "."}}),
|
||||
({"build": "."}, {}, {"build": {"context": "."}}),
|
||||
({"build": "./dir-1"}, {"build": "./dir-2"}, {"build": {"context": "./dir-2"}}),
|
||||
({}, {"build": {"context": "./dir-1"}}, {"build": {"context": "./dir-1"}}),
|
||||
({"build": {"context": "./dir-1"}}, {}, {"build": {"context": "./dir-1"}}),
|
||||
(
|
||||
{"build": {"context": "./dir-1"}},
|
||||
{"build": {"context": "./dir-2"}},
|
||||
{"build": {"context": "./dir-2"}},
|
||||
),
|
||||
(
|
||||
{},
|
||||
{"build": {"dockerfile": "./compose.yaml"}},
|
||||
{"build": {"dockerfile": "./compose.yaml"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./compose.yaml"}},
|
||||
{},
|
||||
{"build": {"dockerfile": "./compose.yaml"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./compose-1.yaml"}},
|
||||
{"build": {"dockerfile": "./compose-2.yaml"}},
|
||||
{"build": {"dockerfile": "./compose-2.yaml"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./compose-1.yaml"}},
|
||||
{"build": {"context": "./dir-2"}},
|
||||
{"build": {"dockerfile": "./compose-1.yaml", "context": "./dir-2"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./compose-1.yaml", "context": "./dir-1"}},
|
||||
{"build": {"dockerfile": "./compose-2.yaml", "context": "./dir-2"}},
|
||||
{"build": {"dockerfile": "./compose-2.yaml", "context": "./dir-2"}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./compose-1.yaml"}},
|
||||
{"build": {"dockerfile": "./compose-2.yaml", "args": ["ENV1=1"]}},
|
||||
{"build": {"dockerfile": "./compose-2.yaml", "args": ["ENV1=1"]}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./compose-2.yaml", "args": ["ENV1=1"]}},
|
||||
{"build": {"dockerfile": "./compose-1.yaml"}},
|
||||
{"build": {"dockerfile": "./compose-1.yaml", "args": ["ENV1=1"]}},
|
||||
),
|
||||
(
|
||||
{"build": {"dockerfile": "./compose-2.yaml", "args": ["ENV1=1"]}},
|
||||
{"build": {"dockerfile": "./compose-1.yaml", "args": ["ENV2=2"]}},
|
||||
{"build": {"dockerfile": "./compose-1.yaml", "args": ["ENV1=1", "ENV2=2"]}},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_rec_merge_one_for_build():
|
||||
for base, override, expected in copy.deepcopy(test_cases):
|
||||
base_original = copy.deepcopy(base)
|
||||
base = rec_merge_one(base, override)
|
||||
test_result = expected == base
|
||||
if not test_result:
|
||||
print("base: ", base_original)
|
||||
print("override: ", override)
|
||||
print("expected: ", expected)
|
||||
print("actual: ", base)
|
||||
assert test_result
|
||||
|
||||
|
||||
test_cases_with_exceptions = [
|
||||
({}, {"build": 1234}, ValueError),
|
||||
({"build": 1234}, {}, ValueError),
|
||||
({"build": 1234}, {"build": 1234}, ValueError),
|
||||
({"build": []}, {}, ValueError),
|
||||
({}, {"build": []}, ValueError),
|
||||
({"build": []}, {"build": []}, ValueError),
|
||||
]
|
||||
|
||||
|
||||
def test_rec_merge_one_for_build_eception():
|
||||
for base, override, expected_exception in copy.deepcopy(test_cases_with_exceptions):
|
||||
base_original = copy.deepcopy(base)
|
||||
with pytest.raises(expected_exception):
|
||||
base = rec_merge_one(base, override)
|
||||
print("base: ", base_original)
|
||||
print("override: ", override)
|
||||
print("expected: ", expected_exception)
|
Loading…
Reference in New Issue
Block a user