[diffoscope] 02/02: Add a --exclude-command CLI for filtering out long-running commands like "readelf --debug-dump=info"

Ximin Luo infinity0 at debian.org
Mon May 29 23:31:50 CEST 2017


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

infinity0 pushed a commit to branch experimental
in repository diffoscope.

commit fe2d5dec866ca68e1086be8aadd4fb38f87d5e37
Author: Ximin Luo <infinity0 at debian.org>
Date:   Mon May 29 23:29:11 2017 +0200

    Add a --exclude-command CLI for filtering out long-running commands like "readelf --debug-dump=info"
---
 diffoscope/comparators/utils/command.py |  5 +++++
 diffoscope/config.py                    |  1 +
 diffoscope/difference.py                | 34 ++++++++++++++++++++-------------
 diffoscope/excludes.py                  |  8 ++++++++
 diffoscope/main.py                      | 12 ++++++++++--
 5 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/diffoscope/comparators/utils/command.py b/diffoscope/comparators/utils/command.py
index 2d6fd4f..5014140 100644
--- a/diffoscope/comparators/utils/command.py
+++ b/diffoscope/comparators/utils/command.py
@@ -30,6 +30,8 @@ logger = logging.getLogger(__name__)
 class Command(object, metaclass=abc.ABCMeta):
     def __init__(self, path):
         self._path = path
+
+    def start(self):
         logger.debug("Executing %s", ' '.join([shlex.quote(x) for x in self.cmdline()]))
         self._process = subprocess.Popen(self.cmdline(),
                                          shell=False, close_fds=True,
@@ -58,6 +60,9 @@ class Command(object, metaclass=abc.ABCMeta):
     def cmdline(self):
         raise NotImplementedError()
 
+    def shell_cmdline(self):
+        return ' '.join(map(lambda x: '{}' if x == self.path else shlex.quote(x), self.cmdline()))
+
     def env(self):
         return None # inherit parent environment by default
 
diff --git a/diffoscope/config.py b/diffoscope/config.py
index 8f6a229..ccc744c 100644
--- a/diffoscope/config.py
+++ b/diffoscope/config.py
@@ -34,6 +34,7 @@ class Config(object):
     fuzzy_threshold = 60
     enforce_constraints = True
     excludes = ()
+    exclude_commands = ()
     compute_visual_diffs = False
     max_container_depth = 50
 
diff --git a/diffoscope/difference.py b/diffoscope/difference.py
index 38853f1..cef38f3 100644
--- a/diffoscope/difference.py
+++ b/diffoscope/difference.py
@@ -23,6 +23,7 @@ import logging
 import subprocess
 
 from .exc import RequiredToolNotFound
+from .excludes import command_excluded
 from .diff import diff, reverse_unified_diff
 from .config import Config
 from .profiling import profile
@@ -131,21 +132,28 @@ class Difference(object):
         if 'command_args' in kwargs:
             command_args = kwargs['command_args']
             del kwargs['command_args']
-        command1 = None
-        if path1 == '/dev/null':
-            feeder1 = empty_file_feeder()
-        else:
-            command1 = klass(path1, *command_args)
-            feeder1 = make_feeder_from_command(command1)
-        command2 = None
-        if path2 == '/dev/null':
-            feeder2 = empty_file_feeder()
-        else:
-            command2 = klass(path2, *command_args)
-            feeder2 = make_feeder_from_command(command2)
+
+        def command_and_feeder(path):
+            command = None
+            if path == '/dev/null':
+                feeder = empty_file_feeder()
+            else:
+                command = klass(path, *command_args)
+                feeder = make_feeder_from_command(command)
+                if command_excluded(command.shell_cmdline()):
+                    return None, None
+                command.start()
+            return feeder, command
+
+        feeder1, command1 = command_and_feeder(path1)
+        feeder2, command2 = command_and_feeder(path2)
+        if not feeder1 or not feeder2:
+            return None
+
         if 'source' not in kwargs:
             source_cmd = command1 or command2
-            kwargs['source'] = ' '.join(map(lambda x: '{}' if x == source_cmd.path else x, source_cmd.cmdline()))
+            kwargs['source'] = source_cmd.shell_cmdline()
+
         difference = Difference.from_feeder(feeder1, feeder2, path1, path2, *args, **kwargs)
         if not difference:
             return None
diff --git a/diffoscope/excludes.py b/diffoscope/excludes.py
index 2ce60ee..b95b71f 100644
--- a/diffoscope/excludes.py
+++ b/diffoscope/excludes.py
@@ -19,12 +19,20 @@
 
 import fnmatch
 import logging
+import re
 
 from diffoscope.config import Config
 
 logger = logging.getLogger(__name__)
 
 
+def command_excluded(command):
+    for y in Config().exclude_commands:
+        if re.search(y, command):
+            logger.debug("Excluding command '%s' as it matches pattern '%s'", command, y)
+            return True
+    return False
+
 def filter_excludes(filenames):
     for x in filenames:
         for y in Config().excludes:
diff --git a/diffoscope/main.py b/diffoscope/main.py
index 74e26ba..8ce6e1c 100644
--- a/diffoscope/main.py
+++ b/diffoscope/main.py
@@ -159,9 +159,16 @@ def create_parser():
     group3 = parser.add_argument_group('diff calculation')
     group3.add_argument('--new-file', action='store_true',
                         help='Treat absent files as empty')
-    group3.add_argument('--exclude', dest='excludes', nargs='?',
-                        metavar='PATTERN', action='append', default=[],
+    group3.add_argument('--exclude', dest='excludes',
+                        metavar='GLOB_PATTERN', action='append', default=[],
                         help='Exclude files that match %(metavar)s')
+    group3.add_argument('--exclude-command', dest='exclude_commands',
+                        metavar='REGEX_PATTERN', action='append', default=[],
+                        help='Exclude commands that match %(metavar)s. For '
+                        "example, '^readelf.*\s--debug-dump=info' takes by far "
+                        'the longest time, and differences here are probably '
+                        'only secondary differences caused by something that '
+                        'is already represented elsewhere in the diff.')
     group3.add_argument('--fuzzy-threshold', type=int,
                         help='Threshold for fuzzy-matching '
                         '(0 to disable, %(default)s is default, 400 is high fuzziness)',
@@ -291,6 +298,7 @@ def run_diffoscope(parsed_args):
     Config().fuzzy_threshold = parsed_args.fuzzy_threshold
     Config().new_file = parsed_args.new_file
     Config().excludes = parsed_args.excludes
+    Config().exclude_commands = parsed_args.exclude_commands
     Config().compute_visual_diffs = PresenterManager().compute_visual_diffs()
     set_path()
     set_locale()

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


More information about the diffoscope mailing list