[Git][reproducible-builds/diffoscope][master] 3 commits: Add --list-missing-tools

Mattia Rizzolo gitlab at salsa.debian.org
Tue Nov 6 12:38:00 CET 2018


Mattia Rizzolo pushed to branch master at Reproducible Builds / diffoscope


Commits:
339a4317 by Will Thompson at 2018-11-06T10:29:37Z
Add --list-missing-tools

While creating a Flatpak package for Diffoscope, I found myself wanting
to compare the list reported by --list-tools to what was available in
the sandbox (so that I could add interesting external tools). Since
Diffoscope already has all the machinery to find external tools –
including logic to prefix "g" for GNU tools on non-GNU systems – it is
best placed to report the list of missing tools.

- - - - -
f9c30e2b by Mattia Rizzolo at 2018-11-06T11:33:09Z
Merge branch 'list-missing-tools' of salsa.debian.org:wjt-guest/diffoscope

MR: https://salsa.debian.org/reproducible-builds/diffoscope/merge_requests/14
Signed-off-by: Mattia Rizzolo <mattia at debian.org>

- - - - -
5d6dc2a5 by Mattia Rizzolo at 2018-11-06T11:37:30Z
Wrap some long lines

Gbp-Dch: Ignore
Signed-off-by: Mattia Rizzolo <mattia at debian.org>

- - - - -


3 changed files:

- diffoscope/main.py
- diffoscope/tools.py
- tests/test_main.py


Changes:

=====================================
diffoscope/main.py
=====================================
@@ -30,7 +30,8 @@ import traceback
 
 from . import VERSION
 from .path import set_path
-from .tools import tool_prepend_prefix, tool_required, OS_NAMES, get_current_os
+from .tools import tool_check_installed, tool_prepend_prefix, tool_required, \
+        OS_NAMES, get_current_os
 from .config import Config
 from .locale import set_locale
 from .logging import line_eraser, setup_logging
@@ -166,8 +167,9 @@ def create_parser():
                         'spilling it into child pages (--html-dir) or skipping the '
                         'rest of the diff block. Child pages are limited instead by '
                         '--max-page-size-child. (default: %(default)s, remains in '
-                        'effect even with --no-default-limits)', default=Config().max_page_diff_block_lines).completer = RangeCompleter(
-        Config().max_page_diff_block_lines)
+                        'effect even with --no-default-limits)',
+                        default=Config().max_page_diff_block_lines).completer = RangeCompleter(
+                                Config().max_page_diff_block_lines)
     # TODO: old flag kept for backwards-compat, drop 6 months after v84
     group2.add_argument("--max-diff-block-lines-parent", metavar='LINES', type=int,
                         help=argparse.SUPPRESS, default=None)
@@ -182,8 +184,8 @@ def create_parser():
     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' can take a long "
-                        'time and differences here are likely secondary '
+                        "example '^readelf.*\\s--debug-dump=info' can take a "
+                        'long time and differences here are likely secondary '
                         'differences caused by something represented '
                         'elsewhere. Use this option to disable commands that '
                         'use a lot of resources.')
@@ -246,14 +248,27 @@ def create_parser():
                         'distribution that satisfy these dependencies.')
     group4.add_argument('--list-debian-substvars', action=ListDebianSubstvarsAction,
                         help="List packages needed for Debian in 'substvar' format.")
+    group4.add_argument('--list-missing-tools', nargs='?', type=str, action=ListMissingToolsAction,
+                        metavar='DISTRO', choices=OS_NAMES,
+                        help='Show missing external tools and exit. '
+                        'DISTRO can be one of {%(choices)s}. '
+                        'If specified, the output will list packages in that '
+                        'distribution that satisfy these dependencies.')
 
     if not tlsh:
-        parser.epilog = 'File renaming detection based on fuzzy-matching is currently disabled. It can be enabled by installing the "tlsh" module available at https://github.com/trendmicro/tlsh'
+        parser.epilog = (
+            'File renaming detection based on fuzzy-matching is currently '
+            'disabled. It can be enabled by installing the "tlsh" module '
+            'available at https://github.com/trendmicro/tlsh'
+        )
     if argcomplete:
         argcomplete.autocomplete(parser)
     elif '_ARGCOMPLETE' in os.environ:
         logger.error(
-            'Argument completion requested but the "argcomplete" module is not installed. It can be obtained at https://pypi.python.org/pypi/argcomplete')
+            'Argument completion requested but the "argcomplete" module is '
+            'not installed. It can be obtained at '
+            'https://pypi.python.org/pypi/argcomplete'
+        )
         sys.exit(1)
 
     def post_parse(parsed_args):
@@ -265,7 +280,9 @@ def create_parser():
                                  for f in x.option_strings]
             if ineffective_flags:
                 logger.warning(
-                    "Loading diff instead of calculating it, but diff-calculation flags were given; they will be ignored:")
+                    'Loading diff instead of calculating it, but '
+                    'diff-calculation flags were given; they will be ignored:'
+                )
                 logger.warning(ineffective_flags)
     return parser, post_parse
 
@@ -302,13 +319,24 @@ class RangeCompleter(object):
 
 
 class ListToolsAction(argparse.Action):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.only_missing = False
+
     def __call__(self, parser, namespace, os_override, option_string=None):
         # Ensure all comparators are imported so tool_required.all is
         # populated.
         ComparatorManager().reload()
 
+        external_tools = sorted(tool_required.all)
+        if self.only_missing:
+            external_tools = [
+                tool for tool in external_tools
+                if not tool_check_installed(tool)
+            ]
+
         print("External-Tools-Required: ", end='')
-        print(', '.join(sorted(tool_required.all)))
+        print(', '.join(external_tools))
 
         current_os = get_current_os()
         os_list = [current_os] if (current_os in OS_NAMES) else iter(OS_NAMES)
@@ -318,7 +346,7 @@ class ListToolsAction(argparse.Action):
         for os_ in os_list:
             tools = set()
             print("Available-in-{}-packages: ".format(OS_NAMES[os_]), end='')
-            for x in tool_required.all:
+            for x in external_tools:
                 try:
                     tools.add(EXTERNAL_TOOLS[x][os_])
                 except KeyError:
@@ -328,6 +356,12 @@ class ListToolsAction(argparse.Action):
         sys.exit(0)
 
 
+class ListMissingToolsAction(ListToolsAction):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.only_missing = True
+
+
 class ListDebianSubstvarsAction(argparse._StoreTrueAction):
     def __call__(self, *args, **kwargs):
         # Attempt to import all comparators so tool_required.all is as


=====================================
diffoscope/tools.py
=====================================
@@ -55,6 +55,15 @@ def tool_prepend_prefix(prefix, *tools):
         REMAPPED_TOOL_NAMES[tool] = prefix + tool
 
 
+def tool_check_installed(command):
+    if command == get_tool_name(command) and not os_is_gnu() and tool_is_gnu(command):
+        # try "g" + command for each tool, if we're on a non-GNU system
+        if find_executable("g" + command):
+            tool_prepend_prefix("g", command)
+
+    return find_executable(get_tool_name(command))
+
+
 def tool_required(command):
     """
     Decorator that checks if the specified tool is installed
@@ -77,12 +86,7 @@ def tool_required(command):
             This ensures that any os.environ['PATH'] modifications are
             performed prior to the `find_executable` tests.
             """
-            if command == get_tool_name(command) and not os_is_gnu() and tool_is_gnu(command):
-                # try "g" + command for each tool, if we're on a non-GNU system
-                if find_executable("g" + command):
-                    tool_prepend_prefix("g", command)
-
-            if not find_executable(get_tool_name(command)):
+            if not tool_check_installed(command):
                 raise RequiredToolNotFound(command)
 
             with profile('command', command):


=====================================
tests/test_main.py
=====================================
@@ -138,6 +138,16 @@ def test_list_tools(capsys):
     assert 'xxd,' in out
 
 
+def test_list_missing_tools(capsys):
+    ret, out, err = run(capsys, '--list-missing-tools')
+
+    assert ret == 0
+    assert err == ''
+    assert 'External-Tools-Required: ' in out
+    # No assertions about the contents of the output since we don't control
+    # what's installed in the test environment
+
+
 def test_profiling(capsys):
     ret, out, err = run(capsys, TEST_TAR1_PATH, TEST_TAR1_PATH, '--profile=-')
 



View it on GitLab: https://salsa.debian.org/reproducible-builds/diffoscope/compare/0dfb8182fed6491296e1c1014351e00b29e59d8e...5d6dc2a5d121cc09e5b66b15615dcc0a4340abcd

-- 
View it on GitLab: https://salsa.debian.org/reproducible-builds/diffoscope/compare/0dfb8182fed6491296e1c1014351e00b29e59d8e...5d6dc2a5d121cc09e5b66b15615dcc0a4340abcd
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.reproducible-builds.org/pipermail/rb-commits/attachments/20181106/8db3b068/attachment.html>


More information about the rb-commits mailing list