diff --git a/capella2polarion/elements/api_helper.py b/capella2polarion/elements/api_helper.py index d72403f7..8d127fea 100644 --- a/capella2polarion/elements/api_helper.py +++ b/capella2polarion/elements/api_helper.py @@ -1,12 +1,16 @@ # Copyright DB Netz AG and contributors # SPDX-License-Identifier: Apache-2.0 """Capella2Polarion specific helper functions to use the API.""" +import base64 import collections.abc as cabc +import io import logging +import re import typing as t import polarion_rest_api_client as polarion_api from capellambse.model import common +from PIL import Image, ImageChops from capella2polarion.elements import serialize @@ -41,6 +45,10 @@ def patch_work_item( if new := receiver(obj, ctx): wid = ctx["POLARION_ID_MAP"][obj.uuid] old: serialize.CapellaWorkItem = ctx["POLARION_WI_MAP"][obj.uuid] + + if _type == "diagram" and svg_diff(old.description, new.description): + return + if new == old: return @@ -72,6 +80,39 @@ def patch_work_item( logger.error("Updating work item %r failed. %s", wi, error.args[0]) +def pixel_diff(old: str, new: str) -> bool: + """Return True if the pixels of the diagrams differ.""" + encoded_old = old.replace("data:image/", "").split(";base64,", 1)[1] + encoded_new = new.replace("data:image/", "").split(";base64,", 1)[1] + + decoded_old = base64.b64decode(encoded_old) + decoded_new = base64.b64decode(encoded_new) + + image_old = Image.open(io.BytesIO(decoded_old)) + image_new = Image.open(io.BytesIO(decoded_new)) + + diff = ImageChops.difference(image_old, image_new) + + return bool(diff.getbbox()) + + +def svg_diff(old: str, new: str) -> bool: + """Return True if the visible elements of the diagram SVGs differ.""" + encoded_old = old.replace("data:image/svg+xml;base64,", "") + encoded_new = new.replace("data:image/svg+xml;base64,", "") + + decoded_old = base64.b64decode(encoded_old).decode("utf-8").splitlines() + decoded_new = base64.b64decode(encoded_new).decode("utf-8").splitlines() + + for i, d_old in enumerate(decoded_old): + if re.sub(r'id=["\'][^"\']*["\']', "", d_old) != re.sub( + r'id=["\'][^"\']*["\']', "", decoded_new[i] + ): + return True + + return False + + def handle_links( left: cabc.Iterable[polarion_api.WorkItemLink], right: cabc.Iterable[polarion_api.WorkItemLink],