Blame libnmstate/prettystate.py

Packit Service 0535c1
#
Packit Service 0535c1
# Copyright (c) 2018-2020 Red Hat, Inc.
Packit Service 0535c1
#
Packit Service 0535c1
# This file is part of nmstate
Packit Service 0535c1
#
Packit Service 0535c1
# This program is free software: you can redistribute it and/or modify
Packit Service 0535c1
# it under the terms of the GNU Lesser General Public License as published by
Packit Service 0535c1
# the Free Software Foundation, either version 2.1 of the License, or
Packit Service 0535c1
# (at your option) any later version.
Packit Service 0535c1
#
Packit Service 0535c1
# This program is distributed in the hope that it will be useful,
Packit Service 0535c1
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0535c1
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 0535c1
# GNU Lesser General Public License for more details.
Packit Service 0535c1
#
Packit Service 0535c1
# You should have received a copy of the GNU Lesser General Public License
Packit Service 0535c1
# along with this program. If not, see <https://www.gnu.org/licenses/>.
Packit Service 0535c1
#
Packit Service 0535c1
Packit Service 0535c1
from collections.abc import Mapping
Packit Service 0535c1
from collections.abc import Sequence
Packit Service 0535c1
from copy import deepcopy
Packit Service 0535c1
import difflib
Packit Service 0535c1
import json
Packit Service 0535c1
Packit Service 0535c1
import yaml
Packit Service 0535c1
Packit Service 0535c1
from .schema import DNS
Packit Service 0535c1
from .schema import Route
Packit Service 0535c1
from .schema import RouteRule
Packit Service 0535c1
from .schema import Interface
Packit Service 0535c1
Packit Service 0535c1
PRIORITY_LIST = (
Packit Service 0535c1
    "name",
Packit Service 0535c1
    "type",
Packit Service 0535c1
    "state",
Packit Service 0535c1
    "enabled",
Packit Service 0535c1
    DNS.KEY,
Packit Service 0535c1
    RouteRule.KEY,
Packit Service 0535c1
    Route.KEY,
Packit Service 0535c1
    Interface.KEY,
Packit Service 0535c1
)
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def format_desired_current_state_diff(desired_state, current_state):
Packit Service 0535c1
    pretty_desired_state = PrettyState(desired_state).yaml
Packit Service 0535c1
    pretty_current_state = PrettyState(current_state).yaml
Packit Service 0535c1
Packit Service 0535c1
    diff = "".join(
Packit Service 0535c1
        difflib.unified_diff(
Packit Service 0535c1
            pretty_desired_state.splitlines(True),
Packit Service 0535c1
            pretty_current_state.splitlines(True),
Packit Service 0535c1
            fromfile="desired",
Packit Service 0535c1
            tofile="current",
Packit Service 0535c1
            n=3,
Packit Service 0535c1
        )
Packit Service 0535c1
    )
Packit Service 0535c1
    return (
Packit Service 0535c1
        "\n"
Packit Service 0535c1
        "desired\n"
Packit Service 0535c1
        "=======\n"
Packit Service 0535c1
        "{}\n"
Packit Service 0535c1
        "current\n"
Packit Service 0535c1
        "=======\n"
Packit Service 0535c1
        "{}\n"
Packit Service 0535c1
        "difference\n"
Packit Service 0535c1
        "==========\n"
Packit Service 0535c1
        "{}\n".format(pretty_desired_state, pretty_current_state, diff)
Packit Service 0535c1
    )
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
class PrettyState:
Packit Service 0535c1
    def __init__(self, state):
Packit Service 0535c1
        yaml.add_representer(dict, represent_dict)
Packit Service 0535c1
        self.state = _sort_with_priority(state)
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def yaml(self):
Packit Service 0535c1
        return yaml.dump(
Packit Service 0535c1
            self.state, default_flow_style=False, explicit_start=True
Packit Service 0535c1
        )
Packit Service 0535c1
Packit Service 0535c1
    @property
Packit Service 0535c1
    def json(self):
Packit Service 0535c1
        return json.dumps(self.state, indent=4, separators=(",", ": "))
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def represent_dict(dumper, data):
Packit Service 0535c1
    """
Packit Service 0535c1
    Represent dictionary with insert order
Packit Service 0535c1
    """
Packit Service 0535c1
    value = []
Packit Service 0535c1
Packit Service 0535c1
    for item_key, item_value in data.items():
Packit Service 0535c1
        node_key = dumper.represent_data(item_key)
Packit Service 0535c1
        node_value = dumper.represent_data(item_value)
Packit Service 0535c1
        value.append((node_key, node_value))
Packit Service 0535c1
Packit Service 0535c1
    return yaml.nodes.MappingNode("tag:yaml.org,2002:map", value)
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def represent_unicode(_, data):
Packit Service 0535c1
    """
Packit Service 0535c1
    Represent unicode as regular string
Packit Service 0535c1
Packit Service 0535c1
    Source:
Packit Service 0535c1
        https://stackoverflow.com/questions/1950306/pyyaml-dumping-without-tags
Packit Service 0535c1
Packit Service 0535c1
    """
Packit Service 0535c1
Packit Service 0535c1
    return yaml.ScalarNode(
Packit Service 0535c1
        tag="tag:yaml.org,2002:str", value=data.encode("utf-8")
Packit Service 0535c1
    )
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _sort_with_priority(data):
Packit Service 0535c1
    if isinstance(data, Sequence) and not isinstance(data, str):
Packit Service 0535c1
        return [_sort_with_priority(item) for item in data]
Packit Service 0535c1
    elif isinstance(data, Mapping):
Packit Service 0535c1
        new_data = {}
Packit Service 0535c1
        for key in sorted(data.keys(), key=_sort_with_priority_key_func):
Packit Service 0535c1
            new_data[key] = _sort_with_priority(data[key])
Packit Service 0535c1
        return new_data
Packit Service 0535c1
    else:
Packit Service 0535c1
        return deepcopy(data)
Packit Service 0535c1
Packit Service 0535c1
Packit Service 0535c1
def _sort_with_priority_key_func(key):
Packit Service 0535c1
    try:
Packit Service 0535c1
        priority = PRIORITY_LIST.index(key)
Packit Service 0535c1
    except ValueError:
Packit Service 0535c1
        priority = len(PRIORITY_LIST)
Packit Service 0535c1
    return (priority, key)