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.
pull/13086/merge
Mads Andreasen 8 months ago committed by Jussi Pakkanen
parent f01ae52bc2
commit 50704bced3
  1. 6
      mesonbuild/environment.py
  2. 4
      mesonbuild/scripts/coverage.py
  3. 11
      mesonbuild/utils/universal.py
  4. 5
      unittests/internaltests.py

@ -109,13 +109,13 @@ def detect_llvm_cov(suffix: T.Optional[str] = None):
tool = 'llvm-cov' tool = 'llvm-cov'
else: else:
tool = f'llvm-cov-{suffix}' tool = f'llvm-cov-{suffix}'
if mesonlib.exe_exists([tool, '--version']): if shutil.which(tool) is not None:
return tool return tool
else: else:
# Otherwise guess in the dark # Otherwise guess in the dark
tools = get_llvm_tool_names('llvm-cov') tools = get_llvm_tool_names('llvm-cov')
for tool in tools: for tool in tools:
if mesonlib.exe_exists([tool, '--version']): if shutil.which(tool):
return tool return tool
return None 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'): def detect_lcov_genhtml(lcov_exe: str = 'lcov', genhtml_exe: str = 'genhtml'):
lcov_exe, lcov_version = detect_lcov(lcov_exe) 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 genhtml_exe = None
return lcov_exe, lcov_version, genhtml_exe return lcov_exe, lcov_version, genhtml_exe

@ -5,7 +5,7 @@ from __future__ import annotations
from mesonbuild import environment, mesonlib 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 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, 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 gcovr_exe = None
else: else:
gcovr_exe, gcovr_version = environment.detect_gcovr(gcovr_exe) 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 llvm_cov_exe = None
lcov_exe, lcov_version, genhtml_exe = environment.detect_lcov_genhtml() lcov_exe, lcov_version, genhtml_exe = environment.detect_lcov_genhtml()

@ -98,7 +98,6 @@ __all__ = [
'do_conf_file', 'do_conf_file',
'do_conf_str', 'do_conf_str',
'do_replacement', 'do_replacement',
'exe_exists',
'expand_arguments', 'expand_arguments',
'extract_as_list', 'extract_as_list',
'first', 'first',
@ -683,14 +682,8 @@ def is_qnx() -> bool:
def is_aix() -> bool: def is_aix() -> bool:
return platform.system().lower() == 'aix' return platform.system().lower() == 'aix'
def exe_exists(arglist: T.List[str]) -> bool: def exe_exists(exe: str) -> bool:
try: return shutil.which(exe) is not None
if subprocess.run(arglist, timeout=10).returncode == 0:
return True
except (FileNotFoundError, subprocess.TimeoutExpired):
pass
return False
@lru_cache(maxsize=None) @lru_cache(maxsize=None)
def darwin_get_object_archs(objpath: str) -> 'ImmutableListProtocol[str]': def darwin_get_object_archs(objpath: str) -> 'ImmutableListProtocol[str]':

@ -39,6 +39,7 @@ from mesonbuild.interpreter.type_checking import in_set_validator, NoneType
from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface, PkgConfigCLI from mesonbuild.dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface, PkgConfigCLI
from mesonbuild.programs import ExternalProgram from mesonbuild.programs import ExternalProgram
import mesonbuild.modules.pkgconfig import mesonbuild.modules.pkgconfig
from mesonbuild import utils
from run_tests import ( from run_tests import (
@ -813,6 +814,10 @@ class InternalTests(unittest.TestCase):
self.assertTrue(vctools_ver.startswith(toolset_ver), self.assertTrue(vctools_ver.startswith(toolset_ver),
msg=f'{vctools_ver!r} does not start with {toolset_ver!r}') 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): def test_split_args(self):
split_args = mesonbuild.mesonlib.split_args split_args = mesonbuild.mesonlib.split_args
join_args = mesonbuild.mesonlib.join_args join_args = mesonbuild.mesonlib.join_args

Loading…
Cancel
Save