From 33566c719da0d565f864418cd5645f19dcbc3f75 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Tue, 4 Oct 2022 08:40:28 -0300 Subject: [PATCH] [Install Checker] Added Helvetica font detection - Seems to be a problem on Arch Linux and derivatives --- kibot/dep_downloader.py | 10 ++++- src/kibot-check | 86 +++++++++++++++++++++++++++++++++++++---- src/kibot-check.in | 58 +++++++++++++++++++++++---- 3 files changed, 138 insertions(+), 16 deletions(-) diff --git a/kibot/dep_downloader.py b/kibot/dep_downloader.py index 8119069a..81920f09 100644 --- a/kibot/dep_downloader.py +++ b/kibot/dep_downloader.py @@ -41,6 +41,10 @@ Dependencies: command: rsvg-convert downloader: rsvg id: RSVG + tests: + - command: [convert, -list, font] + search: Helvetica + error: Missing Helvetica font, try installing Ghostscript fonts - name: Ghostscript url: https://www.ghostscript.com/ url_down: https://github.com/ArtifexSoftware/ghostpdl-downloads/releases @@ -837,7 +841,7 @@ class ToolDependency(object): """ Class used to define tools needed for an output """ def __init__(self, output, name, url=None, url_down=None, is_python=False, deb=None, in_debian=True, extra_deb=None, roles=None, plugin_dirs=None, command=None, pypi_name=None, module_name=None, no_cmd_line_version=False, - help_option=None, no_cmd_line_version_old=False, downloader=None, arch=None, extra_arch=None): + help_option=None, no_cmd_line_version_old=False, downloader=None, arch=None, extra_arch=None, tests=None): # The associated output self.output = output # Name of the tool @@ -875,6 +879,7 @@ class ToolDependency(object): self.no_cmd_line_version = no_cmd_line_version self.no_cmd_line_version_old = no_cmd_line_version_old # An old version doesn't have version self.help_option = help_option if help_option is not None else '--version' + self.tests = tests # Roles if roles is None: roles = [ToolDependencyRole()] @@ -930,13 +935,14 @@ def register_dep(context, dep): if downloader: downloader = getattr(modules[__name__], downloader+'_downloader') name = dep['name'] + tests = dep.get('tests', []) # logger.error('{}:{} {} {}'.format(context, name, downloader, pypi_name)) # TODO: Make it *ARGS td = ToolDependency(context, name, roles=role, url=url, url_down=url_down, deb=deb, in_debian=in_debian, extra_deb=extra_deb, is_python=is_python, module_name=module_name, plugin_dirs=plugin_dirs, command=command, help_option=help_option, pypi_name=pypi_name, no_cmd_line_version_old=no_cmd_line_version_old, downloader=downloader, arch=arch, - extra_arch=extra_arch) + extra_arch=extra_arch, tests=tests) # Extra comments comments = dep.get('comments', []) if isinstance(comments, str): diff --git a/src/kibot-check b/src/kibot-check index 9f0f142a..64e049ae 100755 --- a/src/kibot-check +++ b/src/kibot-check @@ -48,6 +48,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": null,\ "url_down": null\ },\ @@ -85,6 +86,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": "https://www.ghostscript.com/",\ "url_down": "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases"\ },\ @@ -134,6 +136,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": "https://git-scm.com/",\ "url_down": null\ },\ @@ -179,6 +182,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": "https://imagemagick.org/",\ "url_down": "https://imagemagick.org/script/download.php"\ },\ @@ -220,6 +224,7 @@ deps = '{\ ]\ }\ ],\ + "tests": [],\ "url": "https://github.com/INTI-CMNB/InteractiveHtmlBom",\ "url_down": "https://github.com/INTI-CMNB/InteractiveHtmlBom/releases"\ },\ @@ -255,6 +260,7 @@ deps = '{\ ]\ }\ ],\ + "tests": [],\ "url": "https://github.com/INTI-CMNB/KiBoM",\ "url_down": "https://github.com/INTI-CMNB/KiBoM/releases"\ },\ @@ -420,6 +426,7 @@ deps = '{\ ]\ }\ ],\ + "tests": [],\ "url": "https://github.com/INTI-CMNB/KiAuto",\ "url_down": "https://github.com/INTI-CMNB/KiAuto/releases"\ },\ @@ -455,6 +462,7 @@ deps = '{\ ]\ }\ ],\ + "tests": [],\ "url": "https://github.com/INTI-CMNB/KiDiff",\ "url_down": "https://github.com/INTI-CMNB/KiDiff/releases"\ },\ @@ -500,6 +508,7 @@ deps = '{\ ]\ }\ ],\ + "tests": [],\ "url": "https://github.com/hildogjr/KiCost",\ "url_down": "https://github.com/hildogjr/KiCost/releases"\ },\ @@ -532,6 +541,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": null,\ "url_down": null\ },\ @@ -570,6 +580,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": "https://pandoc.org/",\ "url_down": "https://github.com/jgm/pandoc/releases"\ },\ @@ -619,6 +630,7 @@ deps = '{\ ]\ }\ ],\ + "tests": [],\ "url": "https://github.com/INTI-CMNB/pcbdraw",\ "url_down": "https://github.com/INTI-CMNB/pcbdraw/releases"\ },\ @@ -651,6 +663,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": null,\ "url_down": null\ },\ @@ -683,6 +696,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": null,\ "url_down": null\ },\ @@ -714,6 +728,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": "https://www.rarlab.com/",\ "url_down": "https://www.rarlab.com/download.htm"\ },\ @@ -763,6 +778,17 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [\ + {\ + "command": [\ + "convert",\ + "-list",\ + "font"\ + ],\ + "error": "Missing Helvetica font, try installing Ghostscript fonts",\ + "search": "Helvetica"\ + }\ + ],\ "url": "https://gitlab.gnome.org/GNOME/librsvg",\ "url_down": null\ },\ @@ -795,6 +821,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": null,\ "url_down": null\ },\ @@ -827,6 +854,7 @@ deps = '{\ "version": null\ }\ ],\ + "tests": [],\ "url": null,\ "url_down": null\ }\ @@ -849,6 +877,8 @@ else: RED = GREEN = YELLOW = YELLOW2 = RESET = BRIGHT = NORMAL = '' last_ok = False last_cmd = None +tests_ok = True +tests_msg = '' is_x86 = is_64 = is_linux = False ver_re = re.compile(r'(\d+)\.(\d+)(?:\.(\d+))?(?:[\.-](\d+))?') @@ -872,14 +902,19 @@ def check_tool_binary_local(name): return full_name +def look_for_command(command): + cmd_full = which(command) + if not cmd_full: + cmd_full = check_tool_binary_python(command) + if not cmd_full: + cmd_full = check_tool_binary_local(command) + return cmd_full + + def run_command(cmd, only_first_line=False, pre_ver_text=None, no_err_2=False): global last_ok global last_cmd - cmd_full = which(cmd[0]) - if not cmd_full: - cmd_full = check_tool_binary_python(cmd[0]) - if not cmd_full: - cmd_full = check_tool_binary_local(cmd[0]) + cmd_full = look_for_command(cmd[0]) if not cmd_full: last_ok = False return NOT_AVAIL @@ -944,13 +979,48 @@ def do_int(v): return int(v) if v is not None else 0 -def check_version(version, roles, no_ver=False): +def check_tests(tests): + global tests_ok + global tests_msg + for t in tests: + cmd = t['command'] + cmd_full = look_for_command(cmd[0]) + if cmd_full is None: + tests_ok = False + tests_msg = 'Missing test tool `{}`'.format(cmd[0]) + return True + cmd[0] = cmd_full + try: + cmd_output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except FileNotFoundError as e: + tests_ok = False + tests_msg = 'Missing test tool `{}`'.format(cmd[0]) + return True + except subprocess.CalledProcessError as e: + tests_ok = False + tests_msg = 'Failed to run %s, error %d' % (cmd[0], e.returncode) + if e.output: + tests_msg += '\nOutput from command: '+e.output.decode() + return True + res = cmd_output.decode().strip() + if not re.search(t['search'], res): + tests_ok = False + tests_msg = t['error'] + return True + return False + + +def check_version(version, roles, no_ver=False, tests=None): res = ver_re.search(version) if res: ver = list(map(do_int, res.groups())) else: ver = [0, 0, 0] not_avail = version == NOT_AVAIL or version == UNKNOWN + global tests_ok + tests_ok = True + if tests and res and not not_avail: + not_avail = check_tests(tests) severity = 0 for r in roles: mandatory = r['mandatory'] @@ -1246,13 +1316,15 @@ for name, d in dependencies.items(): # It will just confuse run_command thinking we need to check Python cmd.insert(0, 'python3') version = run_command(cmd, no_err_2=d['no_cmd_line_version_old']) - sev, ver = check_version(version, d['roles']) + sev, ver = check_version(version, d['roles'], tests=d['tests']) d['sev'] = sev version = version.split('\n')[0] pypi_name = d['pypi_name'] if pypi_name and pypi_name.lower() != name.lower(): name += ' ({})'.format(pypi_name) print(name+': '+do_color(version, sev, version=ver)) + if not tests_ok: + print('- '+do_color(tests_msg, sev)) if args.show_paths and last_cmd: print(' '+last_cmd) diff --git a/src/kibot-check.in b/src/kibot-check.in index 94948963..ea8cfa72 100755 --- a/src/kibot-check.in +++ b/src/kibot-check.in @@ -36,6 +36,8 @@ else: RED = GREEN = YELLOW = YELLOW2 = RESET = BRIGHT = NORMAL = '' last_ok = False last_cmd = None +tests_ok = True +tests_msg = '' is_x86 = is_64 = is_linux = False ver_re = re.compile(r'(\d+)\.(\d+)(?:\.(\d+))?(?:[\.-](\d+))?') @@ -59,14 +61,19 @@ def check_tool_binary_local(name): return full_name +def look_for_command(command): + cmd_full = which(command) + if not cmd_full: + cmd_full = check_tool_binary_python(command) + if not cmd_full: + cmd_full = check_tool_binary_local(command) + return cmd_full + + def run_command(cmd, only_first_line=False, pre_ver_text=None, no_err_2=False): global last_ok global last_cmd - cmd_full = which(cmd[0]) - if not cmd_full: - cmd_full = check_tool_binary_python(cmd[0]) - if not cmd_full: - cmd_full = check_tool_binary_local(cmd[0]) + cmd_full = look_for_command(cmd[0]) if not cmd_full: last_ok = False return NOT_AVAIL @@ -131,13 +138,48 @@ def do_int(v): return int(v) if v is not None else 0 -def check_version(version, roles, no_ver=False): +def check_tests(tests): + global tests_ok + global tests_msg + for t in tests: + cmd = t['command'] + cmd_full = look_for_command(cmd[0]) + if cmd_full is None: + tests_ok = False + tests_msg = 'Missing test tool `{}`'.format(cmd[0]) + return True + cmd[0] = cmd_full + try: + cmd_output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except FileNotFoundError as e: + tests_ok = False + tests_msg = 'Missing test tool `{}`'.format(cmd[0]) + return True + except subprocess.CalledProcessError as e: + tests_ok = False + tests_msg = 'Failed to run %s, error %d' % (cmd[0], e.returncode) + if e.output: + tests_msg += '\nOutput from command: '+e.output.decode() + return True + res = cmd_output.decode().strip() + if not re.search(t['search'], res): + tests_ok = False + tests_msg = t['error'] + return True + return False + + +def check_version(version, roles, no_ver=False, tests=None): res = ver_re.search(version) if res: ver = list(map(do_int, res.groups())) else: ver = [0, 0, 0] not_avail = version == NOT_AVAIL or version == UNKNOWN + global tests_ok + tests_ok = True + if tests and res and not not_avail: + not_avail = check_tests(tests) severity = 0 for r in roles: mandatory = r['mandatory'] @@ -433,13 +475,15 @@ for name, d in dependencies.items(): # It will just confuse run_command thinking we need to check Python cmd.insert(0, 'python3') version = run_command(cmd, no_err_2=d['no_cmd_line_version_old']) - sev, ver = check_version(version, d['roles']) + sev, ver = check_version(version, d['roles'], tests=d['tests']) d['sev'] = sev version = version.split('\n')[0] pypi_name = d['pypi_name'] if pypi_name and pypi_name.lower() != name.lower(): name += ' ({})'.format(pypi_name) print(name+': '+do_color(version, sev, version=ver)) + if not tests_ok: + print('- '+do_color(tests_msg, sev)) if args.show_paths and last_cmd: print(' '+last_cmd)