From 50704bced3775e9bc5b34f4295e282bfac7253f0 Mon Sep 17 00:00:00 2001 From: Mads Andreasen Date: Sun, 7 Apr 2024 16:12:50 +0200 Subject: [PATCH] Replace exe_exists function with shutil.which() The documentation for subprocess.run at https://docs.python.org/3/library/subprocess.html#popen-constructor has a warning, pointing to using shutil.which() instead of subprocess.run for detecting if exe files exists on the path. shutil.which() is used in many places already. --- mesonbuild/environment.py | 6 +++--- mesonbuild/scripts/coverage.py | 4 ++-- mesonbuild/utils/universal.py | 11 ++--------- unittests/internaltests.py | 5 +++++ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index be40dbcfd..63499676d 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -109,13 +109,13 @@ def detect_llvm_cov(suffix: T.Optional[str] = None): tool = 'llvm-cov' else: tool = f'llvm-cov-{suffix}' - if mesonlib.exe_exists([tool, '--version']): + if shutil.which(tool) is not None: return tool else: # Otherwise guess in the dark tools = get_llvm_tool_names('llvm-cov') for tool in tools: - if mesonlib.exe_exists([tool, '--version']): + if shutil.which(tool): return tool return None @@ -139,7 +139,7 @@ def compute_llvm_suffix(coredata: coredata.CoreData): def detect_lcov_genhtml(lcov_exe: str = 'lcov', genhtml_exe: str = 'genhtml'): lcov_exe, lcov_version = detect_lcov(lcov_exe) - if not mesonlib.exe_exists([genhtml_exe, '--version']): + if shutil.which(genhtml_exe) is None: genhtml_exe = None return lcov_exe, lcov_version, genhtml_exe diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py index 17a4a10ae..f01946944 100644 --- a/mesonbuild/scripts/coverage.py +++ b/mesonbuild/scripts/coverage.py @@ -5,7 +5,7 @@ from __future__ import annotations from mesonbuild import environment, mesonlib -import argparse, re, sys, os, subprocess, pathlib, stat +import argparse, re, sys, os, subprocess, pathlib, stat, shutil import typing as T def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build_root: str, log_dir: str, use_llvm_cov: bool, @@ -17,7 +17,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build gcovr_exe = None else: gcovr_exe, gcovr_version = environment.detect_gcovr(gcovr_exe) - if llvm_cov_exe == '' or not mesonlib.exe_exists([llvm_cov_exe, '--version']): + if llvm_cov_exe == '' or shutil.which(llvm_cov_exe) is None: llvm_cov_exe = None lcov_exe, lcov_version, genhtml_exe = environment.detect_lcov_genhtml() diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 4f18ec11b..21173f5df 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -98,7 +98,6 @@ __all__ = [ 'do_conf_file', 'do_conf_str', 'do_replacement', - 'exe_exists', 'expand_arguments', 'extract_as_list', 'first', @@ -683,14 +682,8 @@ def is_qnx() -> bool: def is_aix() -> bool: return platform.system().lower() == 'aix' -def exe_exists(arglist: T.List[str]) -> bool: - try: - if subprocess.run(arglist, timeout=10).returncode == 0: - return True - except (FileNotFoundError, subprocess.TimeoutExpired): - pass - return False - +def exe_exists(exe: str) -> bool: + return shutil.which(exe) is not None @lru_cache(maxsize=None) def darwin_get_object_archs(objpath: str) -> 'ImmutableListProtocol[str]': diff --git a/unittests/internaltests.py b/unittests/internaltests.py index fe9f0d4f5..2c3bcfda3 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -39,6 +39,7 @@ from mesonbuild.interpreter.type_checking import in_set_validator, NoneType from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface, PkgConfigCLI from mesonbuild.programs import ExternalProgram import mesonbuild.modules.pkgconfig +from mesonbuild import utils from run_tests import ( @@ -813,6 +814,10 @@ class InternalTests(unittest.TestCase): self.assertTrue(vctools_ver.startswith(toolset_ver), msg=f'{vctools_ver!r} does not start with {toolset_ver!r}') + def test_exe_exists(self): + self.assertTrue(utils.universal.exe_exists('python3')) + self.assertFalse(utils.universal.exe_exists('command_that_does_not_exist')) + def test_split_args(self): split_args = mesonbuild.mesonlib.split_args join_args = mesonbuild.mesonlib.join_args