Skip to content

Commit

Permalink
Implement override and reset analog to docker-compose (https://docs.d…
Browse files Browse the repository at this point in the history
…ocker.com/compose/compose-file/13-merge/)

Signed-off-by: Sebastian Sellmeier <mail@sebastian-sellmeier.de>
  • Loading branch information
SebTM committed Feb 1, 2024
1 parent bce40c2 commit c47dddb
Showing 1 changed file with 66 additions and 4 deletions.
70 changes: 66 additions & 4 deletions podman_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ def port_dict_to_str(port_desc):


def norm_ports(ports_in):
if not ports_in:
if not ports_in or isinstance(ports_in, ResetTag):
ports_in = []
if isinstance(ports_in, str):
ports_in = [ports_in]
Expand Down Expand Up @@ -1149,6 +1149,51 @@ def flat_deps(services, with_extends=False):
for name, srv in services.items():
rec_deps(services, name)

###################
# Override and reset tags
###################

class OverrideTag(yaml.YAMLObject):
yaml_dumper = yaml.Dumper
yaml_loader = yaml.SafeLoader
yaml_tag = u'!override'

def __init__(self, value):
values = list()

for item in value:
values.append(item.value)

self.value = values

@classmethod
def from_yaml(cls, loader, node):
return OverrideTag(node.value)

@classmethod
def to_yaml(cls, dumper, data):
return dumper.represent_scalar(cls.yaml_tag, data.value)

class ResetTag(yaml.YAMLObject):
yaml_dumper = yaml.Dumper
yaml_loader = yaml.SafeLoader
yaml_tag = u'!reset'

@classmethod
def toJSON(self):
return self.yaml_tag

@classmethod
def from_yaml(cls, loader, node):
return ResetTag()

@classmethod
def to_yaml(cls, dumper, data):
return dumper.represent_scalar(cls.yaml_tag, '')

class ResetTagEncoder(json.JSONEncoder):
def default(self, o):
return o.yaml_tag

###################
# podman and compose classes
Expand Down Expand Up @@ -1293,6 +1338,9 @@ def normalize(compose):
"""
services = compose.get("services", None) or {}
for service in services.values():
if isinstance(service, ResetTag):
continue

normalize_service(service)
return compose

Expand Down Expand Up @@ -1330,6 +1378,8 @@ def rec_merge_one(target, source):
update target from source recursively
"""
done = set()
remove = set()

for key, value in source.items():
if key in target:
continue
Expand All @@ -1340,10 +1390,18 @@ def rec_merge_one(target, source):
continue
if key not in source:
continue

value2 = source[key]

if key in ("command", "entrypoint"):
target[key] = clone(value2)
continue
if isinstance(value, ResetTag) or isinstance(value2, ResetTag):
remove.add(key)
continue
if isinstance(value, OverrideTag) or isinstance(value2, OverrideTag):
target[key] = clone(value.value) if isinstance(value, OverrideTag) else clone(value2.value)
continue
if not isinstance(value2, type(value)):
value_type = type(value)
value2_type = type(value2)
Expand All @@ -1368,6 +1426,10 @@ def rec_merge_one(target, source):
rec_merge_one(value, value2)
else:
target[key] = value2

for key in remove:
del target[key]

return target


Expand Down Expand Up @@ -1629,13 +1691,13 @@ def _parse_compose_file(self):
compose["services"] = resolved_services
if not getattr(args, "no_normalize", None):
compose = normalize_final(compose, self.dirname)
self.merged_yaml = yaml.safe_dump(compose)
merged_json_b = json.dumps(compose, separators=(",", ":")).encode("utf-8")
self.merged_yaml = yaml.dump(compose)
merged_json_b = json.dumps(compose, separators=(",", ":"), cls=ResetTagEncoder).encode("utf-8")
self.yaml_hash = hashlib.sha256(merged_json_b).hexdigest()
compose["_dirname"] = dirname
# debug mode
if len(files) > 1:
log(" ** merged:\n", json.dumps(compose, indent=2))
log(" ** merged:\n", json.dumps(compose, indent=2, cls=ResetTagEncoder))
# ver = compose.get('version', None)

if not project_name:
Expand Down

0 comments on commit c47dddb

Please sign in to comment.