Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
directory_compare.py918 linesDownload Raw Back to schema_diff
1##########################################################################2#3# pgAdmin 4 - PostgreSQL Tools4#5# Copyright (C) 2013 - 2024, The pgAdmin Development Team6# This software is released under the PostgreSQL Licence7#8##########################################################################9 10"""Directory comparison"""11 12import copy13import string14from flask import current_app15from flask_babel import gettext16from pgadmin.utils.constants import PGADMIN_STRING_SEPARATOR17 18count = 119 20list_keys_array = ['name', 'colname', 'argid', 'token', 'option', 'conname',21                   'member_name', 'label', 'attname', 'fdwoption',22                   'fsrvoption', 'umoption']23 24SPECIAL_NODES = ['table', 'view', 'mview']25VIEW_NODES = ['view', 'mview']26 27 28def _get_user_mapping_name(user_mapping_name):29    """30    This function is used to check the pgadmin string separator in the31    specific string and split that.32    """33    mapping_name = user_mapping_name34 35    if mapping_name.find(PGADMIN_STRING_SEPARATOR):36        mapping_name = mapping_name.split(PGADMIN_STRING_SEPARATOR)[0]37 38    return mapping_name39 40 41def _get_source_list(**kwargs):42    """43    Get only source list.44    :param kwargs45    :return: list of source dict.46    """47    added = kwargs.get('added')48    source_dict = kwargs.get('source_dict')49    node = kwargs.get('node')50    source_params = kwargs.get('source_params')51    view_object = kwargs.get('view_object')52    node_label = kwargs.get('node_label')53    group_name = kwargs.get('group_name')54    source_schema_name = kwargs.get('source_schema_name')55    target_schema = kwargs.get('target_schema')56 57    global count58    source_only = []59    for item in added:60        source_object_id = None61        if 'oid' in source_dict[item]:62            source_object_id = source_dict[item]['oid']63 64        if node in SPECIAL_NODES:65            temp_src_params = copy.deepcopy(source_params)66            temp_src_params['tid'] = source_object_id67            temp_src_params['json_resp'] = False68            temp_src_params['add_not_exists_clause'] = True69            if node in VIEW_NODES:70                source_ddl = \71                    view_object.get_sql_from_view_diff(**temp_src_params)72                temp_src_params.update({'target_schema': target_schema})73                diff_ddl = (74                    view_object.get_sql_from_view_diff(**temp_src_params))75                source_dependencies = \76                    view_object.get_view_submodules_dependencies(77                        **temp_src_params)78            else:79                source_ddl = \80                    view_object.get_sql_from_table_diff(**temp_src_params)81                temp_src_params.update({'target_schema': target_schema})82                diff_ddl = (83                    view_object.get_sql_from_table_diff(**temp_src_params))84                source_dependencies = \85                    view_object.get_table_submodules_dependencies(86                        **temp_src_params)87        else:88            temp_src_params = copy.deepcopy(source_params)89            temp_src_params['oid'] = source_object_id90            # Provide Foreign Data Wrapper ID91            if 'fdwid' in source_dict[item]:92                temp_src_params['fdwid'] = source_dict[item]['fdwid']93            # Provide Foreign Server ID94            if 'fsid' in source_dict[item]:95                temp_src_params['fsid'] = source_dict[item]['fsid']96 97            source_ddl = view_object.get_sql_from_diff(**temp_src_params)98            temp_src_params.update({'target_schema': target_schema})99            diff_ddl = view_object.get_sql_from_diff(**temp_src_params)100            source_dependencies = view_object.get_dependencies(101                view_object.conn, source_object_id, where=None,102                show_system_objects=None, is_schema_diff=True)103 104        title = item105        if node == 'user_mapping':106            title = _get_user_mapping_name(item)107 108        source_only.append({109            'id': count,110            'type': node,111            'label': node_label,112            'title': title,113            'oid': source_object_id,114            'status': gettext('Source Only'),115            'source_ddl': source_ddl,116            'target_ddl': '',117            'diff_ddl': diff_ddl,118            'group_name': group_name,119            'dependencies': source_dependencies,120            'source_schema_name': source_schema_name121        })122        count += 1123 124    return source_only125 126 127def _delete_keys(temp_tgt_params):128    """129    Delete keys from temp target parameters.130    :param temp_tgt_params:131    :type temp_tgt_params:132    :return:133    """134    if 'gid' in temp_tgt_params:135        del temp_tgt_params['gid']136    if 'json_resp' in temp_tgt_params:137        del temp_tgt_params['json_resp']138    if 'add_not_exists_clause' in temp_tgt_params:139        del temp_tgt_params['add_not_exists_clause']140 141 142def _get_target_list(removed, target_dict, node, target_params, view_object,143                     node_label, group_name):144    """145    Get only target list.146    :param removed: removed list.147    :param target_dict: target dict.148    :param node: node type.149    :param target_params: target parameters.150    :param view_object: view object for get sql.151    :param node_label: node label.152    :param group_name: group name.153    :return: list of target dict.154    """155    global count156    target_only = []157    for item in removed:158        target_object_id = None159        if 'oid' in target_dict[item]:160            target_object_id = target_dict[item]['oid']161 162        if node in SPECIAL_NODES:163            temp_tgt_params = copy.deepcopy(target_params)164            temp_tgt_params['tid'] = target_object_id165            temp_tgt_params['json_resp'] = False166            temp_tgt_params['add_not_exists_clause'] = True167            if node in VIEW_NODES:168                target_ddl = (169                    view_object.get_sql_from_view_diff(**temp_tgt_params))170                temp_tgt_params.update(171                    {'drop_sql': True})172                diff_ddl = (173                    view_object.get_sql_from_view_diff(**temp_tgt_params))174            else:175                target_ddl = (176                    view_object.get_sql_from_table_diff(**temp_tgt_params))177                _delete_keys(temp_tgt_params)178                diff_ddl = view_object.get_drop_sql(**temp_tgt_params)179        else:180            temp_tgt_params = copy.deepcopy(target_params)181            temp_tgt_params['oid'] = target_object_id182            # Provide Foreign Data Wrapper ID183            if 'fdwid' in target_dict[item]:184                temp_tgt_params['fdwid'] = target_dict[item]['fdwid']185            # Provide Foreign Server ID186            if 'fsid' in target_dict[item]:187                temp_tgt_params['fsid'] = target_dict[item]['fsid']188 189            target_ddl = view_object.get_sql_from_diff(**temp_tgt_params)190            temp_tgt_params.update(191                {'drop_sql': True})192            diff_ddl = view_object.get_sql_from_diff(**temp_tgt_params)193 194        title = item195        if node == 'user_mapping':196            title = _get_user_mapping_name(item)197 198        target_only.append({199            'id': count,200            'type': node,201            'label': node_label,202            'title': title,203            'oid': target_object_id,204            'status': gettext('Target Only'),205            'source_ddl': '',206            'target_ddl': target_ddl,207            'diff_ddl': diff_ddl,208            'group_name': group_name,209            'dependencies': []210        })211        count += 1212 213    return target_only214 215 216def _check_add_req_ids(source_dict, target_dict, key, temp_src_params,217                       temp_tgt_params):218    """219    Check for Foreign Data Wrapper ID and Foreign Server ID and update it220    in req parameters.221    :param source_dict: Source dict for compare schema.222    :param target_dict: Target dict for compare schema.223    :param key: Key for get obj.224    :param temp_src_params:225    :param temp_tgt_params:226    :return:227    """228    if 'fdwid' in source_dict[key]:229        temp_src_params['fdwid'] = source_dict[key]['fdwid']230        temp_tgt_params['fdwid'] = target_dict[key]['fdwid']231    # Provide Foreign Server ID232    if 'fsid' in source_dict[key]:233        temp_src_params['fsid'] = source_dict[key]['fsid']234        temp_tgt_params['fsid'] = target_dict[key]['fsid']235 236 237def get_source_target_oid(source_dict, target_dict, key):238    """239    Get source and target object ID.240    :param source_dict: Source schema diff data.241    :param target_dict: Target schema diff data.242    :param key: Key.243    :return: source and target object ID.244    """245    source_object_id = None246    target_object_id = None247    if 'oid' in source_dict[key]:248        source_object_id = source_dict[key]['oid']249        target_object_id = target_dict[key]['oid']250 251    return source_object_id, target_object_id252 253 254def _get_identical_and_different_list(intersect_keys, source_dict, target_dict,255                                      node, node_label, view_object,256                                      **kwargs):257    """258    get lists of identical and different keys list.259    :param intersect_keys:260    :param source_dict:261    :param target_dict:262    :param node:263    :param node_label:264    :param view_object:265    :param other_param:266    :return: return list of identical and different dict.267    """268    global count269    identical = []270    different = []271    dict1 = kwargs['dict1']272    dict2 = kwargs['dict2']273    ignore_keys = kwargs['ignore_keys']274    source_params = kwargs['source_params']275    target_params = kwargs['target_params']276    group_name = kwargs['group_name']277    target_schema = kwargs.get('target_schema')278    ignore_whitespaces = kwargs.get('ignore_whitespaces')279    ignore_grants = kwargs.get('ignore_grants', False)280 281    for key in intersect_keys:282        source_object_id, target_object_id = \283            get_source_target_oid(source_dict, target_dict, key)284 285        # Recursively Compare the two dictionary286        current_app.logger.debug(287            "Schema Diff: Source Dict: {0}".format(dict1[key]))288        current_app.logger.debug(289            "Schema Diff: Target Dict: {0}".format(dict2[key]))290 291        if are_dictionaries_identical(dict1[key], dict2[key], ignore_keys,292                                      ignore_whitespaces):293            title = key294            if node == 'user_mapping':295                title = _get_user_mapping_name(key)296 297            identical.append({298                'id': count,299                'type': node,300                'label': node_label,301                'title': title,302                'oid': source_object_id,303                'source_oid': source_object_id,304                'target_oid': target_object_id,305                'status': gettext('Identical'),306                'group_name': group_name,307                'dependencies': [],308                'source_scid': source_params['scid']309                if 'scid' in source_params else 0,310                'target_scid': target_params['scid']311                if 'scid' in target_params else 0,312            })313        else:314            if node in SPECIAL_NODES:315                temp_src_params = copy.deepcopy(source_params)316                temp_tgt_params = copy.deepcopy(target_params)317                # Add submodules into the ignore keys so that directory318                # difference won't include those in added, deleted and changed319                sub_module = ['index', 'rule', 'trigger', 'compound_trigger']320                temp_ignore_keys = ignore_keys + sub_module321 322                diff_dict = directory_diff(323                    dict1[key], dict2[key],324                    ignore_keys=temp_ignore_keys,325                    difference={}326                )327 328                # No need to parse acl if ignore_grants is set to True.329                if not ignore_grants:330                    parse_acl(dict1[key], dict2[key], diff_dict)331 332                temp_src_params['tid'] = source_object_id333                temp_tgt_params['tid'] = target_object_id334 335                if node in VIEW_NODES:336                    source_ddl = \337                        view_object.get_sql_from_view_diff(**temp_src_params)338                    diff_dependencies = \339                        view_object.get_view_submodules_dependencies(340                            **temp_src_params)341                    target_ddl = \342                        view_object.get_sql_from_view_diff(**temp_tgt_params)343                else:344                    temp_src_params['json_resp'] = \345                        temp_tgt_params['json_resp'] = False346 347                    source_ddl = \348                        view_object.get_sql_from_table_diff(**temp_src_params)349                    diff_dependencies = \350                        view_object.get_table_submodules_dependencies(351                            **temp_src_params)352                    target_ddl = \353                        view_object.get_sql_from_table_diff(**temp_tgt_params)354 355                diff_ddl = view_object.get_sql_from_submodule_diff(356                    source_params=temp_src_params,357                    target_params=temp_tgt_params,358                    source=dict1[key], target=dict2[key], diff_dict=diff_dict,359                    target_schema=target_schema,360                    ignore_whitespaces=ignore_whitespaces)361            else:362                temp_src_params = copy.deepcopy(source_params)363                temp_tgt_params = copy.deepcopy(target_params)364                diff_dict = directory_diff(365                    dict1[key], dict2[key],366                    ignore_keys=ignore_keys, difference={}367                )368 369                # No need to parse acl if ignore_grants is set to True.370                if not ignore_grants:371                    parse_acl(dict1[key], dict2[key], diff_dict)372 373                temp_src_params['oid'] = source_object_id374                temp_tgt_params['oid'] = target_object_id375                # Provide Foreign Data Wrapper ID376                _check_add_req_ids(source_dict, target_dict, key,377                                   temp_src_params, temp_tgt_params)378 379                source_ddl = view_object.get_sql_from_diff(**temp_src_params)380                diff_dependencies = view_object.get_dependencies(381                    view_object.conn, source_object_id, where=None,382                    show_system_objects=None, is_schema_diff=True)383                target_ddl = view_object.get_sql_from_diff(**temp_tgt_params)384                temp_tgt_params.update(385                    {'data': diff_dict, 'target_schema': target_schema})386                diff_ddl = view_object.get_sql_from_diff(**temp_tgt_params)387 388            title = key389            if node == 'user_mapping':390                title = _get_user_mapping_name(key)391 392            different.append({393                'id': count,394                'type': node,395                'label': node_label,396                'title': title,397                'oid': source_object_id,398                'source_oid': source_object_id,399                'target_oid': target_object_id,400                'status': gettext('Different'),401                'source_ddl': source_ddl,402                'target_ddl': target_ddl,403                'diff_ddl': diff_ddl,404                'group_name': group_name,405                'dependencies': diff_dependencies406            })407        count += 1408 409    return identical, different410 411 412def compare_dictionaries(**kwargs):413    """414    This function will compare the two dictionaries.415 416    :param kwargs:417    :return:418    """419    view_object = kwargs.get('view_object')420    source_params = kwargs.get('source_params')421    target_params = kwargs.get('target_params')422    target_schema = kwargs.get('target_schema')423    group_name = kwargs.get('group_name')424    source_dict = kwargs.get('source_dict')425    target_dict = kwargs.get('target_dict')426    node = kwargs.get('node')427    node_label = kwargs.get('node_label')428    ignore_keys = kwargs.get('ignore_keys', None)429    source_schema_name = kwargs.get('source_schema_name')430    ignore_owner = kwargs.get('ignore_owner')431    ignore_whitespaces = kwargs.get('ignore_whitespaces')432    ignore_tablespace = kwargs.get('ignore_tablespace')433    ignore_grants = kwargs.get('ignore_grants')434 435    dict1 = copy.deepcopy(source_dict)436    dict2 = copy.deepcopy(target_dict)437 438    # Find the duplicate keys in both the dictionaries439    dict1_keys = set(dict1.keys())440    dict2_keys = set(dict2.keys())441    intersect_keys = dict1_keys.intersection(dict2_keys)442 443    # Add gid to the params444    source_params['gid'] = target_params['gid'] = 1445 446    # Keys that are available in source and missing in target.447 448    added = dict1_keys - dict2_keys449 450    source_only = _get_source_list(added=added, source_dict=source_dict,451                                   node=node, source_params=source_params,452                                   view_object=view_object,453                                   node_label=node_label,454                                   group_name=group_name,455                                   source_schema_name=source_schema_name,456                                   target_schema=target_schema)457 458    target_only = []459    # Keys that are available in target and missing in source.460    removed = dict2_keys - dict1_keys461    target_only = _get_target_list(removed, target_dict, node, target_params,462                                   view_object, node_label, group_name)463 464    # if ignore_owner is True then add all the possible owner keys to the465    # ignore keys.466    if ignore_owner:467        owner_keys = ['owner', 'eventowner', 'funcowner', 'fdwowner',468                      'fsrvowner', 'lanowner', 'relowner', 'seqowner',469                      'typeowner']470        ignore_keys = ignore_keys + owner_keys471 472    # if ignore_tablespace is True then add all the possible tablespace keys473    # to the ignore keys.474    if ignore_tablespace:475        tablespace_keys = ['spcname', 'spcoid']476        ignore_keys = ignore_keys + tablespace_keys477 478    # if ignore_grants is True then add all the possible grants keys479    # to the ignore keys.480    if ignore_grants:481        grant_keys = ['relacl', 'acl', 'datacl', 'fdwacl', 'lanacl', 'fsrvacl']482        ignore_keys = ignore_keys + grant_keys483 484    # Compare the values of duplicates keys.485    other_param = {486        "dict1": dict1,487        "dict2": dict2,488        "ignore_keys": ignore_keys,489        "source_params": source_params,490        "target_params": target_params,491        "group_name": group_name,492        "target_schema": target_schema,493        "ignore_whitespaces": ignore_whitespaces,494        "ignore_grants": ignore_grants495    }496 497    identical, different = _get_identical_and_different_list(498        intersect_keys, source_dict, target_dict, node, node_label,499        view_object, **other_param)500 501    return source_only + target_only + different + identical502 503 504def are_lists_identical(source_list, target_list, ignore_keys,505                        ignore_whitespaces):506    """507    This function is used to compare two list.508    :param source_list:509    :param target_list:510    :param ignore_keys: ignore keys to compare511    :param ignore_whitespaces:512    :return:513    """514    if source_list is None or target_list is None or \515            len(source_list) != len(target_list):516        return False517 518    for index in range(len(source_list)):519        # Check the type of the value if it is an dictionary then520        # call are_dictionaries_identical() function.521        if isinstance(source_list[index], dict):522            if not are_dictionaries_identical(source_list[index],523                                              target_list[index],524                                              ignore_keys,525                                              ignore_whitespaces):526                return False527        else:528            if source_list[index] != target_list[index]:529                return False530    return True531 532 533def are_dictionaries_identical(source_dict, target_dict, ignore_keys,534                               ignore_whitespaces):535    """536    This function is used to recursively compare two dictionaries with537    same keys.538    :param source_dict: source dict539    :param target_dict: target dict540    :param ignore_keys: ignore keys to compare541    :param ignore_whitespaces: ignore whitespaces while comparing542    :return:543    """544    src_keys = set(source_dict.keys())545    tar_keys = set(target_dict.keys())546    igr_keys = set(ignore_keys)547 548    # Keys that are available in source and missing in target.549    src_only = (src_keys - igr_keys) - tar_keys550    # Keys that are available in target and missing in source.551    tar_only = (tar_keys - igr_keys) - src_keys552 553    # If number of keys are different in source and target then554    # return False555    if len(src_only) != len(tar_only):556        current_app.logger.debug("Schema Diff: Number of keys are different "557                                 "in source and target")558        return False559 560    # If number of keys are same but key is not present in target then561    # return False562    for key in src_only:563        if key not in tar_only:564            current_app.logger.debug(565                "Schema Diff: Number of keys are same but key is not"566                " present in target")567            return False568 569    for key in source_dict.keys():570        # Continue if key is available in ignore_keys571        if key in ignore_keys:572            continue573 574        if isinstance(source_dict[key], dict):575            if not are_dictionaries_identical(source_dict[key],576                                              target_dict[key],577                                              ignore_keys,578                                              ignore_whitespaces):579                return False580        elif isinstance(source_dict[key], list):581            # Sort the source and target list on the basis of582            # list key array.583            source_dict[key], target_dict[key] = sort_list(source_dict[key],584                                                           target_dict[key])585            # Compare the source and target lists586            if not are_lists_identical(source_dict[key], target_dict[key],587                                       ignore_keys, ignore_whitespaces):588                return False589        else:590            source_value = source_dict[key]591            target_value = target_dict[key]592            # Check if ignore whitespaces or not.593            source_value, target_value = check_for_ignore_whitespaces(594                ignore_whitespaces, source_value, target_value)595 596            # We need a proper solution as sometimes we observe that597            # source_value is '' and target_value is None or vice versa598            # in such situation we shown the comparison as different599            # which is wrong.600            if (source_value == '' and target_value is None) or \601                    (source_value is None and target_value == ''):602                continue603 604            if source_value != target_value:605                current_app.logger.debug(606                    "Schema Diff: Object name: '{0}', Source Value: '{1}', "607                    "Target Value: '{2}', Key: '{3}'".format(608                        source_dict['name'] if 'name' in source_dict else '',609                        source_value, target_value, key))610                return False611 612    return True613 614 615def check_for_ignore_whitespaces(ignore_whitespaces, source_value,616                                 target_value):617    """618    If ignore_whitespaces is True then check the source_value and619    target_value if of type string. If the values is of type string620    then using translate function ignore all the whitespaces.621    :param ignore_whitespaces: flag to check ignore whitespace.622    :param source_value: source schema diff value623    :param target_value: target schema diff value624    :return: return source and target values.625    """626    if ignore_whitespaces:627        if isinstance(source_value, str):628            source_value = source_value.translate(629                str.maketrans('', '', string.whitespace))630        if isinstance(target_value, str):631            target_value = target_value.translate(632                str.maketrans('', '', string.whitespace))633 634    return source_value, target_value635 636 637def directory_diff(source_dict, target_dict, ignore_keys=[], difference=None):638    """639    This function is used to recursively compare two dictionaries and640    return the difference.641    The difference is from source to target642    :param source_dict: source dict643    :param target_dict: target dict644    :param ignore_keys: ignore keys to compare645    :param difference:646    """647 648    difference = {} if difference is None else difference649    src_keys = set(source_dict.keys())650    tar_keys = set(target_dict.keys())651    igr_keys = set(ignore_keys)652 653    # Keys that are available in source and missing in target.654    src_only = (src_keys - igr_keys) - tar_keys655    # Keys that are available in target and missing in source.656    tar_only = (tar_keys - igr_keys) - src_keys657 658    for key in source_dict.keys():659        added = []660        deleted = []661        updated = []662        source = None663 664        # ignore the keys if available.665        if key in ignore_keys:666            continue667        elif key in tar_only:668            if isinstance(target_dict[key], list):669                difference[key] = {}670                difference[key]['deleted'] = target_dict[key]671        elif key in src_only:672            # Source only values in the newly added list673            if isinstance(source_dict[key], list):674                difference[key] = {}675                difference[key]['added'] = source_dict[key]676        elif isinstance(source_dict[key], dict):677            directory_diff(source_dict[key], target_dict[key],678                           ignore_keys, difference)679        elif isinstance(source_dict[key], list):680            tmp_target = None681            tmp_list = [x for x in source_dict[key]682                        if isinstance(x, (list, dict))]683 684            if tmp_list:685                tmp_target = copy.deepcopy(target_dict[key])686                for index in range(len(source_dict[key])):687                    source = copy.deepcopy(source_dict[key][index])688                    if isinstance(source, list):689                        # This block is empty will figure out some scenario690                        pass691                    elif isinstance(source, dict):692                        # Check the above keys are exist in the dictionary693                        tmp_key = is_key_exists(list_keys_array, source)694                        if tmp_key is not None:695                            # Compare the two list by ignoring the keys.696                            compare_list_by_ignoring_keys(source, tmp_target,697                                                          added, updated,698                                                          tmp_key, ignore_keys)699 700                        difference[key] = {}701                        if len(added) > 0:702                            difference[key]['added'] = added703                        if len(updated) > 0:704                            difference[key]['changed'] = updated705                    elif target_dict[key] is None or \706                            (isinstance(target_dict[key], list) and707                             len(target_dict[key]) < index and708                             source != target_dict[key][index]):709                        difference[key] = source710                    elif isinstance(target_dict[key], list) and\711                            len(target_dict[key]) > index:712                        difference[key] = source713            elif len(source_dict[key]) > 0:714                difference[key] = source_dict[key]715            elif key in target_dict and isinstance(target_dict[key], list):716                # If no element in source dict then check for the element717                # is available in target and the type is of list.718                # Added such elements as a deleted.719                tmp_tar_list = [x for x in target_dict[key]720                                if isinstance(x, (list, dict))]721                if tmp_tar_list:722                    difference[key] = {'deleted': target_dict[key]}723 724            if isinstance(source, dict) and tmp_target and key in tmp_target \725                    and tmp_target[key] and len(tmp_target[key]) > 0:726                if isinstance(tmp_target[key], list) and \727                        isinstance(tmp_target[key][0], dict):728                    deleted = deleted + tmp_target[key]729                else:730                    deleted.append({key: tmp_target[key]})731                difference[key]['deleted'] = deleted732            elif tmp_target and isinstance(tmp_target, list):733                difference[key]['deleted'] = tmp_target734 735            # No point adding empty list into difference.736            if key in difference and len(difference[key]) == 0:737                difference.pop(key)738        else:739            if source_dict[key] != target_dict[key]:740                if (key == 'comment' or key == 'description') and \741                        source_dict[key] is None:742                    difference[key] = ''743                else:744                    difference[key] = source_dict[key]745 746    if len(src_only) == 0 and len(tar_only) > 0:747        for key in tar_only:748            if isinstance(target_dict[key], list):749                difference[key] = {}750                difference[key]['deleted'] = target_dict[key]751 752    return difference753 754 755def is_key_exists(key_list, target_dict):756    """757    This function is used to iterate the key list and check that key is758    present in the given dictionary759    :param key_list:760    :param target_dict:761    :return:762    """763    for key in key_list:764        if key in target_dict:765            return key766 767    return None768 769 770def _check_key_in_source_target(key, acl_keys, target, source):771    """772    Check if key is present in source if not then check it's present in target.773    :param key: key to be checked.774    :param acl_keys:  acl keys775    :param target: target object.776    :param source: source object.777    :return: return key.778    """779    if key is None:780        key = is_key_exists(acl_keys, target)781        if key is None:782            key = 'acl'783    elif key is not None and not isinstance(source[key], list):784        key = 'acl'785 786    return key787 788 789def parse_acl(source, target, diff_dict):790    """791    This function is used to parse acl.792 793    :param source: Source Dict794    :param target: Target Dict795    :param diff_dict: Difference Dict796    """797    acl_keys = ['datacl', 'relacl', 'typacl', 'pkgacl', 'fsrvacl']798    key = is_key_exists(acl_keys, source)799 800    # If key is not found in source then check the key is available801    # in target.802    key = _check_key_in_source_target(key, acl_keys, target, source)803 804    tmp_source = source[key] if\805        key in source and source[key] is not None else []806    tmp_target = copy.deepcopy(target[key]) if\807        key in target and target[key] is not None else []808 809    diff = {'added': [], 'deleted': []}810    for acl in tmp_source:811        if acl in tmp_target:812            tmp_target.remove(acl)813        elif acl not in tmp_target:814            diff['added'].append(acl)815    diff['deleted'] = tmp_target816 817    # Update the key if there are some element in added or deleted818    # else remove that key from diff dict819    if len(diff['added']) > 0 or len(diff['deleted']) > 0:820        diff_dict.update({key: diff})821    elif key in diff_dict:822        diff_dict.pop(key)823 824 825def sort_list(source, target):826    """827    This function is used to sort the source and target list on the828    basis of key found in the source and target list.829    :param source:830    :param target:831    :return:832    """833    # Check the above keys are exist in the dictionary834    if source is not None and source and isinstance(source[0], dict):835        tmp_key = is_key_exists(list_keys_array, source[0])836        if tmp_key is not None:837            source = sorted(source, key=lambda k: k[tmp_key])838 839    # Check the above keys are exist in the dictionary840    if target is not None and target and isinstance(target[0], dict):841        tmp_key = is_key_exists(list_keys_array, target[0])842        if tmp_key is not None:843            target = sorted(target, key=lambda k: k[tmp_key])844 845    return source, target846 847 848def compare_list_by_ignoring_keys(source_list, target_list, added, updated,849                                  key, ignore_keys):850    """851    This function is used to compare the two list by ignoring the keys852    specified in ignore_keys.853    :param source_list:854    :param target_list:855    :param added:856    :param updated:857    :param key:858    :param ignore_keys:859    :return:860    """861    if isinstance(target_list, list) and target_list:862        tmp_target = None863        for item in target_list:864            if key in item and item[key] == source_list[key]:865                tmp_target = copy.deepcopy(item)866 867        if tmp_target is None:868            added.append(source_list)869        else:870            source_with_ignored_keys = copy.deepcopy(source_list)871            target_with_ignored_keys = copy.deepcopy(tmp_target)872 873            # Remove ignore keys from source and target before comparison874            _remove_keys(ignore_keys, source_with_ignored_keys,875                         target_with_ignored_keys)876 877            _compare_source_and_target(source_with_ignored_keys,878                                       target_with_ignored_keys, source_list,879                                       target_list, updated, tmp_target)880    else:881        added.append(source_list)882 883 884def _remove_keys(ignore_keys, source_with_ignored_keys,885                 target_with_ignored_keys):886    """887    Remove non required keys form both source and target object.888    :param ignore_keys: ignore keys list.889    :param source_with_ignored_keys: source keys list.890    :param target_with_ignored_keys: target keys list.891    :return: None892    """893    for ig_key in ignore_keys:894        if ig_key in source_with_ignored_keys:895            del source_with_ignored_keys[ig_key]896        if ig_key in target_with_ignored_keys:897            del target_with_ignored_keys[ig_key]898 899 900def _compare_source_and_target(source_with_ignored_keys,901                               target_with_ignored_keys, source_list,902                               target_list, updated, tmp_target):903    """904    Compare source and target keys905    :param source_with_ignored_keys:906    :param target_with_ignored_keys:907    :param source_list:908    :param target_list:909    :param updated:910    :param tmp_target:911    :return:912    """913    if source_with_ignored_keys != target_with_ignored_keys:914        updated.append(source_list)915        target_list.remove(tmp_target)916    elif source_with_ignored_keys == target_with_ignored_keys:917        target_list.remove(tmp_target)918 
codekingpro/portable-devtools · Team Ai