Your message dated Mon, 31 Jul 2017 21:05:11 +0000
with message-id <[email protected]>
and subject line Bug#866120: fixed in diffoscope 85
has caused the Debian Bug report #866120,
regarding [PATCH] comparators.xml: added new XML comparator
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
866120: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=866120
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Source: diffoscope
Version: 84
Severity: wishlist

Added XML Comparator as requested in our wishlist.
This patch closes #866120 and shows XML some love.

Signed-off-by: Juliana Rodrigues <[email protected]>
---
 diffoscope/comparators/__init__.py |   1 +
 diffoscope/comparators/xml.py      | 101 +++++++++++++++++++++++++++++++++++++
 tests/comparators/test_xml.py      |  49 ++++++++++++++++++
 tests/data/test1.xml               |   9 ++++
 tests/data/test2.xml               |   9 ++++
 tests/data/test_invalid.xml        |   8 +++
 tests/data/test_xml_expected_diff  |  14 +++++
 7 files changed, 191 insertions(+)
 create mode 100644 diffoscope/comparators/xml.py
 create mode 100644 tests/comparators/test_xml.py
 create mode 100644 tests/data/test1.xml
 create mode 100644 tests/data/test2.xml
 create mode 100644 tests/data/test_invalid.xml
 create mode 100644 tests/data/test_xml_expected_diff

diff --git a/diffoscope/comparators/__init__.py 
b/diffoscope/comparators/__init__.py
index d22aa79..7653741 100644
--- a/diffoscope/comparators/__init__.py
+++ b/diffoscope/comparators/__init__.py
@@ -40,6 +40,7 @@ class ComparatorManager(object):
         ('ps.PsFile',),
         ('javascript.JavaScriptFile',),
         ('json.JSONFile',),
+        ('xml.XMLFile',),
         ('text.TextFile',),
         ('bzip2.Bzip2File',),
         ('cpio.CpioFile',),
diff --git a/diffoscope/comparators/xml.py b/diffoscope/comparators/xml.py
new file mode 100644
index 0000000..d46f1bc
--- /dev/null
+++ b/diffoscope/comparators/xml.py
@@ -0,0 +1,101 @@
+import re
+
+from xml.dom import minidom
+from diffoscope.difference import Difference
+from diffoscope.comparators.utils.file import File
+from xml.parsers.expat import ExpatError
+
+def _format(node):
+  """
+  Removes *inplace* spaces from minidom.Document
+
+  Args:
+    node -- A xml.dom.minidom.Document object
+
+  Returns:
+    void
+  """
+  for n in node.childNodes:
+    if n.nodeType == minidom.Node.TEXT_NODE:
+      if n.nodeValue: n.nodeValue = n.nodeValue.strip()
+    elif n.nodeType == minidom.Node.ELEMENT_NODE:
+      _format(n)
+
+def _parse(file):
+  """
+  Formats a minidom.Document file and returns XML as string.
+
+  Args:
+    file -- An io.TextIOWrapper object
+
+  Returns:
+    str: formated string object
+  """
+  xml = minidom.parse(file)
+  _format(xml)
+  xml.normalize()
+  return xml.toprettyxml(indent=2*' ')
+
+
+class XMLFile(File):
+  """
+  XML Files Comparison class
+
+  Attributes:
+    RE_FILE_EXTENSION (SRE_Pattern): xml file extension pattern
+  """
+  RE_FILE_EXTENSION = re.compile(r'\.xml$')
+
+  @staticmethod
+  def recognizes(file):
+    """
+    Identifies if a given file has XML extension
+
+    Args:
+      file - a diffoscope.comparators.utils.file.File object
+
+    Returns:
+      False if file is not a XML File, True otherwise
+    """
+    if XMLFile.RE_FILE_EXTENSION.search(file.name) is None:
+      return False
+
+    with open(file.path) as f:
+      try:
+        file.parsed = _parse(f)
+      except ExpatError:
+        return False
+
+    return True
+
+  def compare_details(self, other, source=None):
+    """
+    Compares self.object with another, returning a Difference object
+
+    Args:
+      other  -- A XMLFile object
+      source
+
+    Returns:
+      A diffoscope.difference.Difference object
+    """
+    return [ Difference.from_text(self.dumps(self), self.dumps(other),
+      self.path, other.path)]
+
+  def dumps(self, file):
+    """
+    Opens a XMLFile and returns its parsed content
+
+    Args:
+      file -- XMLFile object
+
+    Returns:
+      str -- Formatted XML content from file
+    """
+    if file.parsed:
+      return file.parsed
+
+    with open(file.path) as f:
+      return _parse(f)
+
+
diff --git a/tests/comparators/test_xml.py b/tests/comparators/test_xml.py
new file mode 100644
index 0000000..e8e0aed
--- /dev/null
+++ b/tests/comparators/test_xml.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+#
+# diffoscope: in-depth comparison of files, archives, and directories
+#
+# Copyright © 2016 Chris Lamb <[email protected]>
+#
+# diffoscope is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# diffoscope is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with diffoscope.  If not, see <https://www.gnu.org/licenses/>.
+
+import pytest
+
+from diffoscope.comparators.xml import XMLFile
+
+from ..utils.data import load_fixture, get_data
+from ..utils.nonexisting import assert_non_existing
+
+
+xml_a = load_fixture('test1.xml')
+xml_b = load_fixture('test2.xml')
+invalid_xml = load_fixture('test_invalid.xml')
+
+def test_identification(xml_a):
+    assert isinstance(xml_a, XMLFile)
+
+def test_invalid(invalid_xml):
+    assert not isinstance(invalid_xml, XMLFile)
+
+def test_no_differences(xml_a):
+    assert xml_a.compare(xml_a) is None
+
[email protected]
+def differences(xml_a, xml_b):
+    return xml_a.compare(xml_b).details
+
+def test_diff(differences):
+    expected_diff = get_data('test_xml_expected_diff')
+    assert differences[0].unified_diff == expected_diff
+
+
diff --git a/tests/data/test1.xml b/tests/data/test1.xml
new file mode 100644
index 0000000..b02bf09
--- /dev/null
+++ b/tests/data/test1.xml
@@ -0,0 +1,9 @@
+<note>
+        <style type="text/css" id="night-mode-pro-style" />
+        <link type="text/css" rel="stylesheet"
+        id="night-mode-pro-link" />
+        <to>Tove</to>
+        <from>Jani</from>
+        <heading>Reminder</heading>
+        <body>Don't forget me this weekend!</body>
+</note>
diff --git a/tests/data/test2.xml b/tests/data/test2.xml
new file mode 100644
index 0000000..7e892f8
--- /dev/null
+++ b/tests/data/test2.xml
@@ -0,0 +1,9 @@
+<note>
+        <style type="text/css" id="night-mode-pro-style" />
+        <link type="text/css" rel="stylesheet"
+        id="night-mode-pro-link" />
+        <to>Jani</to>
+        <from>Toni</from>
+        <heading>Re: Reminder</heading>
+        <body>Pick me up on 5!</body>
+</note>
diff --git a/tests/data/test_invalid.xml b/tests/data/test_invalid.xml
new file mode 100644
index 0000000..2a4cd51
--- /dev/null
+++ b/tests/data/test_invalid.xml
@@ -0,0 +1,8 @@
+<note>
+        style type="text/css" id="night-mode-pro-style" />
+        <link type="text/css" rel="stylesheet"
+        id="night-mode-pro-link" />
+        <to>Tove</to>
+        from>Jani</from>
+        <heading>Reminder</heading>
+        <body>Don't forget me this weekend!</body>
diff --git a/tests/data/test_xml_expected_diff 
b/tests/data/test_xml_expected_diff
new file mode 100644
index 0000000..0b450cb
--- /dev/null
+++ b/tests/data/test_xml_expected_diff
@@ -0,0 +1,14 @@
+@@ -1,9 +1,9 @@
+ <?xml version="1.0" ?>
+ <note>
+   <style id="night-mode-pro-style" type="text/css"/>
+   <link id="night-mode-pro-link" rel="stylesheet" type="text/css"/>
+-  <to>Tove</to>
+-  <from>Jani</from>
+-  <heading>Reminder</heading>
+-  <body>Don't forget me this weekend!</body>
++  <to>Jani</to>
++  <from>Toni</from>
++  <heading>Re: Reminder</heading>
++  <body>Pick me up on 5!</body>
+ </note>
-- 
2.13.2

--- End Message ---
--- Begin Message ---
Source: diffoscope
Source-Version: 85

We believe that the bug you reported is fixed in the latest version of
diffoscope, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to [email protected],
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Mattia Rizzolo <[email protected]> (supplier of updated diffoscope package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing [email protected])


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 1.8
Date: Mon, 31 Jul 2017 22:27:45 +0200
Source: diffoscope
Binary: diffoscope
Architecture: source
Version: 85
Distribution: unstable
Urgency: medium
Maintainer: Reproducible builds folks 
<[email protected]>
Changed-By: Mattia Rizzolo <[email protected]>
Description:
 diffoscope - in-depth comparison of files, archives, and directories
Closes: 866120 868486 868534 870049
Changes:
 diffoscope (85) unstable; urgency=medium
 .
   [ Mattia Rizzolo ]
   * tools:
     + move from the deprecated platform.linux_distribution() to the external
       python package "distro".  Add it as an optioanl dependency, as without it
       distribution detection (i.e. `diffoscope --list-tools`) won't work.
       Also add it as a Debian (hard) dependency, as it's a very lightway
       package, and the usefulness it brings are great.
     + add a get_package_provider() function, returning the package name
       that best matches the system.
   * exc:
     + in RequiredToolNotFound.get_package(), just call the new
       get_package_provider()
   * debian/rules:
     + recommends the defusedxml python package, to avoid using the python3's
       standard xml library and its security holes.
 .
   [ Chris Lamb ]
   * comparators:
     + sqlite:
       - Simplify file detection by rewriting manual `recognizes` call
         with a `Sqlite3Database.RE_FILE_TYPE` definition.
     + xml:
       - Fix EPUB "missing file" tests; they ship a META-INF/container.xml file.
 .
   [ Ximin Luo ]
   * comparators:
     + factor common logic from various comparators into File.recognizes.
     + more tidying up and making names consistent.
     + directory:
       - make stat(1) warning textually like the other warnings.
       - bump stat(1) warning into an error.
       - use getfacl(1) before lsattr(1) as it's more general.
     + apk:
       - less kludgy way of detecting APKs.  Closes: #868486
   * main, logging:
     + restore old logger settings to avoid pytest fail in certain situations.
   * debian/rules:
     + add a check to prevent additions of "DOS/MBR" file type.
   * feeder:
     + force a flush when writing output to diff.  Closes: #870049
   * tests/comparators:
     + directory:
       - be less strict about the expected test output, to cope with a missing
         `getfacl`.  Closes: #868534
 .
   [ Juliana Oliveira Rodrigues ]
   * comparators:
     + Add new XML comparator.  Closes: #866120
       The comparator will use defusedxml if this is installed, to avoid
       falling in known security holes coming from the XML specification.
   * tests/comparators:
     + apk:
       - fix the tests after the addition of the XML comparator.
     + image:
       - fix test_ico_image for identify >= 6.9.8.
 .
   [ Guangyuan Yang ]
   * tests/comparators:
     + device:
       - fix 2 cases for FreeBSD.
Checksums-Sha1:
 fbf4fc1689b2b1241a3567aa972e5a4891c31c01 3228 diffoscope_85.dsc
 a781bde07e4705a0a3e1b2eb675905bd9a74f911 653004 diffoscope_85.tar.xz
 98181b38cc107175c30e083a31d6ab6441bbde06 18385 diffoscope_85_amd64.buildinfo
Checksums-Sha256:
 3af990a704ba3a33ce5e3cc8ec477c1e940fa6068e8523f9c337c87206c32588 3228 
diffoscope_85.dsc
 2a71703db5199a6de56e21f8d1c50eea668c147e05ee06fdeda1bfd1bba27016 653004 
diffoscope_85.tar.xz
 7cf18e23618d2fe4efbd4995ff4803f0af51a4e45ad0051fe5381c3f1b221b28 18385 
diffoscope_85_amd64.buildinfo
Files:
 8c6156508c5386d5f6d03621212d23dd 3228 devel optional diffoscope_85.dsc
 0a6ae3525f191bff4b30b32cfc5e9b7f 653004 devel optional diffoscope_85.tar.xz
 e31ff3dcfd2b84502b318a43c55d263f 18385 devel optional 
diffoscope_85_amd64.buildinfo

-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEi3hoeGwz5cZMTQpICBa54Yx2K60FAll/lV8ACgkQCBa54Yx2
K63H/w/+JwR4jI33AcYD1jxsgRho34BQ20t/F/0Eh2Y05q8sK0nh/8YxyvsmxhS4
/80ZJkNEm0bFqx378bLe18vC+wYoOTZDb4rPTQOWoxJ8NU6l4fASoXplgwYVCYo8
KDHFqWjbUH5eGYZtiT6KvIp7jHkvi5gjc29kyywZv7EC75kxqddCkQ8lzeHg5zls
XrwyOpKTRMRPmxP9uZS8Z6HiYVCmYjCuCN5uvnePldtxx+Ogde4E3z8SYZWgvnRY
SGyj2LnKsxvi5KIpCA6jIDwiDTiv99cdYg6G/F8nGcCBo2iHK96iyoGFmbg2t3ps
9Ru3EfFo7uou+N1G+nHUoDXoPxeB/1Y0ifrLCzrou3JFKPBFSxjiaXyhv0FAqxUF
QCsvzmo4pl9RRYJ7VSfb++s4ttMwBn8Hp+LI8mhAEOkeIxLnEGUrEsF02eF6ewC5
c2v0v5OoXW2nsCfSxEVGsYZ7IKMFwH5kia3zLUvY+A/n42h+R7MiBQ3aMucs5QoM
z9zxIY2LPRGP5D0VoEJ/tY45uA3Nz0hJDaKO1OTC/LyZ0AP5Qs+twVHMtqgcNmwS
ijnV+DlNUI1/TLP0sfYPK1U8J4JLbxgsSv2yjiK86H7QWaXWezsDAlY/krNyU4p3
ObyZx9AAxZOiQyALNbjzcc/x7LzczVYCRkDybTtMBclSulyVubA=
=pkPO
-----END PGP SIGNATURE-----

--- End Message ---

Reply via email to