[diffoscope] 01/02: Revert "diffoscope.diff: Improve FIFO writing robustness. (Closes: #852013)"

Chris Lamb chris at chris-lamb.co.uk
Sat Jan 28 21:10:50 CET 2017


This is an automated email from the git hooks/post-receive script.

lamby pushed a commit to branch master
in repository diffoscope.

commit d9b7da285baf13f884b5ca857d696186c45d871f
Author: Chris Lamb <lamby at debian.org>
Date:   Sun Jan 29 09:10:27 2017 +1300

    Revert "diffoscope.diff: Improve FIFO writing robustness. (Closes: #852013)"
    
    This reverts commit fa4cab2ab453d5d9b076ec5f3b362c534f065f6d.
---
 diffoscope/diff.py | 103 ++++++++++++++++++++++++++---------------------------
 1 file changed, 51 insertions(+), 52 deletions(-)

diff --git a/diffoscope/diff.py b/diffoscope/diff.py
index 8914712..9ff2c74 100644
--- a/diffoscope/diff.py
+++ b/diffoscope/diff.py
@@ -19,9 +19,6 @@
 
 import re
 import io
-import os
-import errno
-import fcntl
 import hashlib
 import logging
 import threading
@@ -192,55 +189,54 @@ def run_diff(fifo1, fifo2, end_nl_q1, end_nl_q2):
 
     return parser.diff
 
-class FIFOFeeder(threading.Thread):
-    def __init__(self, feeder, fifo_path, end_nl_q=None, *, daemon=True):
-        os.mkfifo(fifo_path)
-        super().__init__(daemon=daemon)
-        self.feeder = feeder
-        self.fifo_path = fifo_path
-        self.end_nl_q = Queue() if end_nl_q is None else end_nl_q
-        self._exception = None
-        self._want_join = threading.Event()
-
-    def __enter__(self):
-        self.start()
-        return self
+def feed(feeder, f, end_nl_q):
+    # work-around unified diff limitation: if there's no newlines in both
+    # don't make it a difference
+    try:
+        end_nl = feeder(f)
+        end_nl_q.put(end_nl)
+    finally:
+        f.close()
+
+class ExThread(threading.Thread):
+    """
+    Inspired by https://stackoverflow.com/a/6874161
+    """
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.__status_queue = Queue()
+
+    def run(self, *args, **kwargs):
+        try:
+            super().run(*args, **kwargs)
+        except Exception as ex:
+            #except_type, except_class, tb = sys.exc_info()
+            self.__status_queue.put(ex)
 
-    def __exit__(self, exc_type, exc_value, exc_tb):
-        self.join()
+        self.__status_queue.put(None)
 
-    def run(self):
-        try:
-            # Try to open the FIFO nonblocking, so we can periodically check
-            # if the main thread wants us to wind down.  If it does, there's no
-            # more need for the FIFO, so stop the thread.
-            while True:
-                try:
-                    fifo_fd = os.open(self.fifo_path, os.O_WRONLY | os.O_NONBLOCK)
-                except OSError as error:
-                    if error.errno != errno.ENXIO:
-                        raise
-                    elif self._want_join.is_set():
-                        return
-                else:
-                    break
-
-            # Now clear the fd's nonblocking flag to let writes block normally.
-            fcntl.fcntl(fifo_fd, fcntl.F_SETFL, 0)
-            with open(fifo_fd, 'wb') as fifo:
-                # The queue works around a unified diff limitation: if there's
-                # no newlines in both don't make it a difference
-                end_nl = self.feeder(fifo)
-                self.end_nl_q.put(end_nl)
-        except Exception as error:
-            self._exception = error
+    def wait_for_exc_info(self):
+        return self.__status_queue.get()
 
     def join(self):
-        self._want_join.set()
-        super().join()
-        if self._exception is not None:
-            raise self._exception
+        ex = self.wait_for_exc_info()
+        if ex is None:
+            return
+        raise ex
 
+ at contextlib.contextmanager
+def fd_from_feeder(feeder, end_nl_q, fifo):
+    f = open(fifo, 'wb')
+    t = ExThread(target=feed, args=(feeder, f, end_nl_q))
+
+    t.daemon = True
+    t.start()
+
+    try:
+        t.join()
+    finally:
+        f.close()
 
 def empty_file_feeder():
     def feeder(f):
@@ -276,12 +272,15 @@ def make_feeder_from_raw_reader(in_file, filter=lambda buf: buf):
     return feeder
 
 def diff(feeder1, feeder2):
+    end_nl_q1 = Queue()
+    end_nl_q2 = Queue()
+
     with tempfile.TemporaryDirectory() as tmpdir:
-        fifo1_path = os.path.join(tmpdir, 'fifo1')
-        fifo2_path = os.path.join(tmpdir, 'fifo2')
-        with FIFOFeeder(feeder1, fifo1_path) as fifo1, \
-             FIFOFeeder(feeder2, fifo2_path) as fifo2:
-            return run_diff(fifo1_path, fifo2_path, fifo1.end_nl_q, fifo2.end_nl_q)
+        fifo1 = '{}/f1'.format(tmpdir)
+        fifo2 = '{}/f2'.format(tmpdir)
+        fd_from_feeder(feeder1, end_nl_q1, fifo1)
+        fd_from_feeder(feeder2, end_nl_q2, fifo2)
+        return run_diff(fifo1, fifo2, end_nl_q1, end_nl_q2)
 
 def reverse_unified_diff(diff):
     res = []

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/diffoscope.git


More information about the diffoscope mailing list