From: Frank Brehm Date: Wed, 5 Apr 2017 16:16:47 +0000 (+0200) Subject: Adding pp_lib/differ.py X-Git-Tag: 0.1.2~213 X-Git-Url: https://git.uhu-banane.de/?a=commitdiff_plain;h=5b2494bb6cb3b419fe591ae773fbf59fc19af842;p=pixelpark%2Fadmin-tools.git Adding pp_lib/differ.py --- diff --git a/pp_lib/differ.py b/pp_lib/differ.py new file mode 100644 index 0000000..8397758 --- /dev/null +++ b/pp_lib/differ.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@author: Frank Brehm +@contact: frank.brehm@pixelpark.com +@summary: The module for the MailAddress object. +""" + +# Standard modules +import sys +import os +import logging +import re +from datetime import datetime, timezone +import difflib + +from difflib import Differ, SequenceMatcher, IS_LINE_JUNK, IS_CHARACTER_JUNK + +import six + +__version__ = '0.1.1' +LOG = logging.getLogger(__name__) + + +# ============================================================================= +class ConfigDiffer(Differ): + """ + A class for comparing the contents of two contents of configuration files + without consideration of comments and whitespaces. + """ + + pat_linejunk = r'^\s*(?:\#.*)?$' + re_linejunk = re.compile(pat_linejunk) + + # ------------------------------------------------------------------------- + @classmethod + def is_line_junk(cls, line): + return cls.re_linejunk.search(line) is not None + + # ------------------------------------------------------------------------- + def __init__(self): + + super(ConfigDiffer, self).__init__( + linejunk=IS_LINE_JUNK, charjunk=IS_CHARACTER_JUNK) + + # ------------------------------------------------------------------------- + def is_equal(self, a, b): + + equal = True + for line in self.compare(a, b): + if line.startswith('+') or line.startswith('-'): + subline = line[1:] + if self.is_line_junk(subline): + LOG.debug("Line {!r} is junk.".format(subline)) + else: + equal = False + + return equal + + +# ============================================================================= +class ConfigFileDiffer(ConfigDiffer): + """ + A class for comparing the contents of two configuration files + without consideration of comments and whitespaces. + """ + + # ------------------------------------------------------------------------- + @classmethod + def file_mtime(cls, path): + + mtime = 0 + if os.path.exists(path): + mtime = os.stat(path).st_mtime + t = datetime.fromtimestamp(mtime, timezone.utc) + return t.astimezone().isoformat(" ") + + # ------------------------------------------------------------------------- + def __init__(self): + + super(ConfigFileDiffer, self).__init__() + + # ------------------------------------------------------------------------- + def compare(self, from_file, to_file): + + from_content = [] + to_content = [] + + open_args = {} + if six.PY3: + open_args = { + 'encoding': 'utf-8', + 'errors': 'surrogateescape', + } + + if from_file: + if os.path.isfile(from_file): + LOG.debug("Reading {!r} ...".format(from_file)) + with open(from_file, 'r', **open_args) as fh: + from_content = fh.readlines() + + if to_file: + if os.path.isfile(to_file): + LOG.debug("Reading {!r} ...".format(to_file)) + with open(to_file, 'r', **open_args) as fh: + to_content = fh.readlines() + + return super(ConfigFileDiffer, self).compare(from_content, to_content) + + # ------------------------------------------------------------------------- + def is_equal(self, from_file, to_file): + + equal = True + for line in self.compare(from_file, to_file): + if line.startswith('+') or line.startswith('-'): + subline = line[1:].rstrip() + if self.is_line_junk(subline): + LOG.debug("Line {!r} is junk.".format(subline)) + else: + LOG.debug(line.rstrip()) + equal = False + + return equal + + # ------------------------------------------------------------------------- + def unified_diff(self, from_file, to_file, n=3, lineterm='\n'): + + from_content = [] + to_content = [] + null_time = datetime.fromtimestamp(0, timezone.utc).astimezone().isoformat(" ") + from_mtime = null_time + to_mtime = null_time + + open_args = {} + if six.PY3: + open_args = { + 'encoding': 'utf-8', + 'errors': 'surrogateescape', + } + + if from_file: + if os.path.isfile(from_file): + from_mtime = self.file_mtime(from_file) + with open(from_file, 'r', **open_args) as fh: + from_content = fh.readlines() + else: + from_file = '' + + if to_file: + if os.path.isfile(to_file): + to_mtime = self.file_mtime(to_file) + with open(to_file, 'r', **open_args) as fh: + to_content = fh.readlines() + else: + to_file = '' + + return difflib.unified_diff( + from_content, to_content, + fromfile=from_file, tofile=to_file, + fromfiledate=from_mtime, tofiledate=to_mtime, + n=n, lineterm=lineterm) + + +# ============================================================================= + +if __name__ == "__main__": + + pass + +# ============================================================================= + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list