--- /dev/null
+#!/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