Skip to content

Commit

Permalink
feat: Diff diagrams
Browse files Browse the repository at this point in the history
  • Loading branch information
ewuerger committed Sep 28, 2023
1 parent 57a1f0e commit 3656abb
Showing 1 changed file with 115 additions and 2 deletions.
117 changes: 115 additions & 2 deletions model_diffsummary/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
from __future__ import annotations

import logging
import pathlib
import typing as t

import capellambse
import click
import yaml
from capellambse import model as m
from capellambse.model import common as c

Expand All @@ -34,9 +36,119 @@ def main(model: dict[str, t.Any], old_version: str, new_version: str):
old_model = capellambse.MelodyModel(**model, revision=old_version)
new_model = capellambse.MelodyModel(**model, revision=new_version)

result = _compare_all_objects(old_model, new_model)
metadata = {
"model": model["path"],
"old-revision": old_version,
"new-revision": new_version,
}
diagrams = _compare_all_diagrams(old_model, new_model)

print(result)
objects = _compare_all_objects(old_model, new_model)

result = {"metadata": metadata, "diagrams": diagrams, "objects": objects}

# pathlib.Path("test.yaml").write_text(yaml.dump(result), encoding="utf8")


def _compare_all_diagrams(
old: capellambse.MelodyModel, new: capellambse.MelodyModel
) -> t.Any:
result: t.Any = {"oa": {}, "la": {}, "pa": {}, "sa": {}}
for layer, diagtype in (
("oa", m.modeltypes.DiagramType.COC),
("oa", m.modeltypes.DiagramType.OAIB),
("oa", m.modeltypes.DiagramType.OPD),
("oa", m.modeltypes.DiagramType.OAB),
("sa", m.modeltypes.DiagramType.CC),
("sa", m.modeltypes.DiagramType.SDFB),
("sa", m.modeltypes.DiagramType.MCB),
("sa", m.modeltypes.DiagramType.SAB),
):
type_result = _compare_diagram_type(old, new, layer, diagtype)
result[layer][diagtype.name] = type_result
return result


def _compare_diagram_type(
old: capellambse.MelodyModel,
new: capellambse.MelodyModel,
layer: str,
diag_type: m.modeltypes.DiagramType,
) -> t.Any:
logging.debug("Collecting diagrams of type %s", diag_type.name)
changes = {}

old_diags = getattr(old, layer).diagrams.by_type(diag_type)
new_diags = getattr(new, layer).diagrams.by_type(diag_type)

old_uuids = {i.uuid for i in old_diags}
new_uuids = {i.uuid for i in new_diags}

if created_uuids := new_uuids - old_uuids:
changes["created"] = [new_diags.by_uuid(i).name for i in created_uuids]
if deleted_uuids := old_uuids - new_uuids:
changes["deleted"] = [old_diags.by_uuid(i).name for i in deleted_uuids]

# for i in old_uuids & new_uuids:
# if diff := _diag2diff(old_diags.by_uuid(i), new_diags.by_uuid(i)):
# changes.setdefault("modified", []).append(diff)
return changes


def _diag2diff(
old: m.diagram.Diagram, new: m.diagram.Diagram
) -> dict[str, t.Any] | None:
"""Serialize the differences between the old and new diagram.
This function is used for diagrams that were modified. Newly
introduced elements and removed elements are serialized.
The new (current) *display-name* is always serialized. If it didn't
change, it will not have the "previous" key.
The *layout_changes* flag indicates that the diagram has changed
positions, sizes or bendpoints for exchanges.
"""
changes: t.Any = {}

old_uuids = set(old.nodes.by_uuid)
new_uuids = set(new.nodes.by_uuid)

if created_uuids := new_uuids - old_uuids:
changes["introduced"] = [
_diagelt2dict(new.nodes.by_uuid(i)) for i in created_uuids
]
if deleted_uuids := old_uuids - new_uuids:
changes["removed"] = [
_diagelt2dict(old.nodes.by_uuid(i)) for i in deleted_uuids
]

old_diag = old.render(None)
new_diag = new.render(None)
changes["layout_changes"] = False
for i in old_uuids & new_uuids:
if _diagelt2diff(old_diag[i], new_diag[i]):
changes["layout_changes"] = True
return changes


def _diagelt2dict(obj: c.GenericElement) -> dict[str, t.Any]:
"""Serialize a diagram element into a dict.
This function is used for diagram elements that were either
introduced or deleted, in which case the id and the name are
serialized.
"""
result = _obj2dict(obj)
return {"id": result["id"], "name": result.get("name")}


def _diagelt2diff(
old: capellambse.diagram.DiagramElement,
new: capellambse.diagram.DiagramElement,
) -> dict[str, t.Any]:
# TODO
return {}


def _compare_all_objects(
Expand Down Expand Up @@ -78,6 +190,7 @@ def _compare_object_type(
for i in old_uuids & new_uuids:
if diff := _obj2diff(old.by_uuid(i), new.by_uuid(i)):
changes.setdefault("modified", []).append(diff)
return changes


def _obj2dict(obj: c.GenericElement) -> dict[str, t.Any]:
Expand Down

0 comments on commit 3656abb

Please sign in to comment.