Esempio n. 1
0
def show_text_diff(stream, a, b):
    _show_diff_header(stream, (a, b), "--text")
    differ = difflib.Differ()
    lines_a = open(a, "r", encoding=default_encoding).readlines()
    lines_b = open(b, "r", encoding=default_encoding).readlines()
    with TermColor(stream) as tc:
        for d in differ.compare(lines_a, lines_b):
            # Someday add "?" highlighting.  Trick is this should change color mid-line on the
            # previous (one or two) lines.  (Google and see if somebody else solved this one already)
            # https://stackoverflow.com/questions/774316/python-difflib-highlighting-differences-inline
            tc.color(_diff_color_mapping.get(d[0], 0))
            stream.write(d)
            tc.reset()
Esempio n. 2
0
def _show_diff_header(stream, files, diff_line=None):
    headers = []

    for f in files:
        if isinstance(f, DiffHeader):
            headers.append(f)
        else:
            headers.append(DiffHeader(f))

    with TermColor(stream) as tc:
        tc.color(ANSI_YELLOW, ANSI_BOLD)
        if diff_line:
            stream.write("diff {} {} {}\n".format(diff_line, headers[0].name, headers[1].name))
        tc.reset()
        stream.write("--- {0}\n".format(headers[0]))
        stream.write("+++ {0}\n".format(headers[1]))
Esempio n. 3
0
def show_diff(stream, diffs, headers=None):
    tc = TermColor(stream)

    def is_multiline(v):
        if v and "\n" in v:
            return True
        else:
            return False

    def write_key(key, value, prefix_=" "):
        if is_multiline(value):
            write_multiline_key(key, value, prefix_)
        else:
            if key.startswith("#-"):
                template = "{0}{2}\n"
            else:
                template = "{0}{1} = {2}\n"
            stream.write(template.format(prefix_, key, value))

    def write_multiline_key(key, value, prefix_=" "):
        with tc:
            lines = value.replace("\n", "\\\n").split("\n")
            tc.color(_diff_color_mapping.get(prefix_))
            stream.write("{0}{1} = {2}\n".format(prefix_, key, lines.pop(0)))
            for line in lines:
                stream.write("{0}{1}\n".format(prefix_, line))

    def show_value(value, stanza_, key, prefix_=""):
        with tc:
            tc.color(_diff_color_mapping.get(prefix_))
            if isinstance(value, dict):
                if stanza_ is not GLOBAL_STANZA:
                    stream.write("{0}[{1}]\n".format(prefix_, stanza_))
                for x, y in sorted(six.iteritems(value)):
                    write_key(x, y, prefix_)
                stream.write("\n")
            else:
                write_key(key, value, prefix_)

    def show_multiline_diff(value_a, value_b, key):
        def f(v):
            r = "{0} = {1}".format(key, v)
            r = r.replace("\n", "\\\n")
            return r.splitlines()

        a = f(value_a)
        b = f(value_b)
        differ = difflib.Differ()
        with tc:
            for d in differ.compare(a, b):
                # Someday add "?" highlighting.  Trick is this should change color mid-line on the
                # previous (one or two) lines.  (Google and see if somebody else solved this one already)
                # https://stackoverflow.com/questions/774316/python-difflib-highlighting-differences-inline
                tc.color(_diff_color_mapping.get(d[0], 0))
                # Differences in how difflib returns bytes/unicode?
                if not isinstance(d, six.text_type):
                    d = d.decode(default_encoding)
                stream.write(d)
                tc.reset()
                stream.write("\n")

    # Global result:  no changes between files or no commonality between files
    if len(diffs) == 1 and isinstance(diffs[0].location, DiffGlobal):
        op = diffs[0]
        if op.tag == DIFF_OP_EQUAL:
            return EXIT_CODE_DIFF_EQUAL
        else:
            if headers:
                _show_diff_header(stream, headers, "--ksconf -global")
            # This is the only place where a gets '-' and b gets '+'
            for (prefix, data) in [("-", op.a), ("+", op.b)]:
                for (stanza, keys) in sorted(data.items()):
                    show_value(keys, stanza, None, prefix)
            stream.flush()
            return EXIT_CODE_DIFF_NO_COMMON

    if headers:
        _show_diff_header(stream, headers, "--ksconf")

    last_stanza = None
    for op in diffs:
        if isinstance(op.location, DiffStanza):
            if op.tag in (DIFF_OP_DELETE, DIFF_OP_REPLACE):
                show_value(op.b, op.location.stanza, None, "-")
            if op.tag in (DIFF_OP_INSERT, DIFF_OP_REPLACE):
                show_value(op.a, op.location.stanza, None, "+")
            continue  # pragma: no cover  (peephole optimization)

        if op.location.stanza != last_stanza:
            if last_stanza is not None:
                # Line break after last stanza
                stream.write("\n")
                stream.flush()
            if op.location.stanza is not GLOBAL_STANZA:
                stream.write(" [{0}]\n".format(op.location.stanza))
            last_stanza = op.location.stanza

        if op.tag == DIFF_OP_INSERT:
            show_value(op.a, op.location.stanza, op.location.key, "+")
        elif op.tag == DIFF_OP_DELETE:
            show_value(op.b, op.location.stanza, op.location.key, "-")
        elif op.tag == DIFF_OP_REPLACE:
            if is_multiline(op.a) or is_multiline(op.b):
                show_multiline_diff(op.a, op.b, op.location.key)
            else:
                show_value(op.b, op.location.stanza, op.location.key, "-")
                show_value(op.a, op.location.stanza, op.location.key, "+")
        elif op.tag == DIFF_OP_EQUAL:
            show_value(op.b, op.location.stanza, op.location.key, " ")
    stream.flush()
    return EXIT_CODE_DIFF_CHANGE