]> Frank Brehm's Git Trees - pixelpark/admin-tools.git/commitdiff
Adding pp_lib/differ.py
authorFrank Brehm <frank.brehm@pixelpark.com>
Wed, 5 Apr 2017 16:16:47 +0000 (18:16 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Wed, 5 Apr 2017 16:16:47 +0000 (18:16 +0200)
pp_lib/differ.py [new file with mode: 0644]

diff --git a/pp_lib/differ.py b/pp_lib/differ.py
new file mode 100644 (file)
index 0000000..8397758
--- /dev/null
@@ -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 = '<None>'
+
+        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 = '<None>'
+
+        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