aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2023-05-24 09:39:01 -0400
committerXavier Claessens <xclaesse@gmail.com>2023-08-24 18:51:13 -0400
commitf720105e242111f4b68c0cb2aa77a4301a2fd10f (patch)
treed02ac5a61ef8386aa1d2555cbcd36815fe694c28
parent6f87215f1f7c104de2f8720e3c0926bcffdc7232 (diff)
downloadmeson-f720105e242111f4b68c0cb2aa77a4301a2fd10f.zip
meson-f720105e242111f4b68c0cb2aa77a4301a2fd10f.tar.gz
meson-f720105e242111f4b68c0cb2aa77a4301a2fd10f.tar.bz2
find_program: Fallback if version mismatch
Fixes: #11797
-rw-r--r--mesonbuild/interpreter/interpreter.py70
-rw-r--r--mesonbuild/modules/__init__.py3
-rw-r--r--test cases/common/182 find override/meson.build6
-rwxr-xr-xtest cases/common/182 find override/prog-version.py3
-rw-r--r--test cases/common/182 find override/subprojects/sub2.wrap5
-rw-r--r--test cases/common/182 find override/subprojects/sub2/meson.build4
-rwxr-xr-xtest cases/common/182 find override/subprojects/sub2/prog-version.py3
7 files changed, 65 insertions, 29 deletions
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index 7bba4fa..4751af9 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -131,6 +131,8 @@ if T.TYPE_CHECKING:
BuildTargetSource = T.Union[mesonlib.FileOrString, build.GeneratedTypes, build.StructuredSources]
+ ProgramVersionFunc = T.Callable[[T.Union[ExternalProgram, build.Executable, OverrideProgram]], str]
+
def _project_version_validator(value: T.Union[T.List, str, mesonlib.File, None]) -> T.Optional[str]:
if isinstance(value, list):
@@ -1621,46 +1623,23 @@ class Interpreter(InterpreterBase, HoldableObject):
required: bool = True, silent: bool = True,
wanted: T.Union[str, T.List[str]] = '',
search_dirs: T.Optional[T.List[str]] = None,
- version_func: T.Optional[T.Callable[[T.Union['ExternalProgram', 'build.Executable', 'OverrideProgram']], str]] = None
+ version_func: T.Optional[ProgramVersionFunc] = None
) -> T.Union['ExternalProgram', 'build.Executable', 'OverrideProgram']:
args = mesonlib.listify(args)
extra_info: T.List[mlog.TV_Loggable] = []
- progobj = self.program_lookup(args, for_machine, default_options, required, search_dirs, extra_info)
- if progobj is None:
+ progobj = self.program_lookup(args, for_machine, default_options, required, search_dirs, wanted, version_func, extra_info)
+ if progobj is None or not self.check_program_version(progobj, wanted, version_func, extra_info):
progobj = self.notfound_program(args)
if isinstance(progobj, ExternalProgram) and not progobj.found():
if not silent:
- mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'))
+ mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'), *extra_info)
if required:
m = 'Program {!r} not found or not executable'
raise InterpreterException(m.format(progobj.get_name()))
return progobj
- if wanted:
- if version_func:
- version = version_func(progobj)
- elif isinstance(progobj, build.Executable):
- if progobj.subproject:
- interp = self.subprojects[progobj.subproject].held_object
- else:
- interp = self
- assert isinstance(interp, Interpreter)
- version = interp.project_version
- else:
- version = progobj.get_version(self)
- is_found, not_found, _ = mesonlib.version_compare_many(version, wanted)
- if not is_found:
- mlog.log('Program', mlog.bold(progobj.name), 'found:', mlog.red('NO'),
- 'found', mlog.normal_cyan(version), 'but need:',
- mlog.bold(', '.join([f"'{e}'" for e in not_found])), *extra_info)
- if required:
- m = 'Invalid version of program, need {!r} {!r} found {!r}.'
- raise InterpreterException(m.format(progobj.name, not_found, version))
- return self.notfound_program(args)
- extra_info.insert(0, mlog.normal_cyan(version))
-
# Only store successful lookups
self.store_name_lookups(args)
if not silent:
@@ -1671,7 +1650,11 @@ class Interpreter(InterpreterBase, HoldableObject):
def program_lookup(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice,
default_options: T.Optional[T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]]],
- required: bool, search_dirs: T.List[str], extra_info: T.List[mlog.TV_Loggable]
+ required: bool,
+ search_dirs: T.List[str],
+ wanted: T.Union[str, T.List[str]],
+ version_func: T.Optional[ProgramVersionFunc],
+ extra_info: T.List[mlog.TV_Loggable]
) -> T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]]:
progobj = self.program_from_overrides(args, extra_info)
if progobj:
@@ -1694,11 +1677,42 @@ class Interpreter(InterpreterBase, HoldableObject):
if progobj is None and args[0].endswith('python3'):
prog = ExternalProgram('python3', mesonlib.python_command, silent=True)
progobj = prog if prog.found() else None
+
+ if progobj and not self.check_program_version(progobj, wanted, version_func, extra_info):
+ progobj = None
+
if progobj is None and fallback and required:
+ progobj = self.notfound_program(args)
+ mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'), *extra_info)
+ extra_info.clear()
progobj = self.find_program_fallback(fallback, args, default_options, required, extra_info)
return progobj
+ def check_program_version(self, progobj: T.Union[ExternalProgram, build.Executable, OverrideProgram],
+ wanted: T.Union[str, T.List[str]],
+ version_func: T.Optional[ProgramVersionFunc],
+ extra_info: T.List[mlog.TV_Loggable]) -> bool:
+ if wanted:
+ if version_func:
+ version = version_func(progobj)
+ elif isinstance(progobj, build.Executable):
+ if progobj.subproject:
+ interp = self.subprojects[progobj.subproject].held_object
+ else:
+ interp = self
+ assert isinstance(interp, Interpreter)
+ version = interp.project_version
+ else:
+ version = progobj.get_version(self)
+ is_found, not_found, _ = mesonlib.version_compare_many(version, wanted)
+ if not is_found:
+ extra_info[:0] = ['found', mlog.normal_cyan(version), 'but need:',
+ mlog.bold(', '.join([f"'{e}'" for e in not_found]))]
+ return False
+ extra_info.insert(0, mlog.normal_cyan(version))
+ return True
+
def find_program_fallback(self, fallback: str, args: T.List[mesonlib.FileOrString],
default_options: T.Dict[OptionKey, T.Union[str, int, bool, T.List[str]]],
required: bool, extra_info: T.List[mlog.TV_Loggable]
diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py
index b46b300..57c169d 100644
--- a/mesonbuild/modules/__init__.py
+++ b/mesonbuild/modules/__init__.py
@@ -26,6 +26,7 @@ from ..programs import ExternalProgram
if T.TYPE_CHECKING:
from ..interpreter import Interpreter
+ from ..interpreter.interpreter import ProgramVersionFunc
from ..interpreter.interpreterobjects import MachineHolder
from ..interpreterbase import TYPE_var, TYPE_kwargs
from ..programs import OverrideProgram
@@ -86,7 +87,7 @@ class ModuleState:
def find_program(self, prog: T.Union[mesonlib.FileOrString, T.List[mesonlib.FileOrString]],
required: bool = True,
- version_func: T.Optional[T.Callable[[T.Union[ExternalProgram, build.Executable, OverrideProgram]], str]] = None,
+ version_func: T.Optional[ProgramVersionFunc] = None,
wanted: T.Optional[str] = None, silent: bool = False,
for_machine: MachineChoice = MachineChoice.HOST) -> T.Union[ExternalProgram, build.Executable, OverrideProgram]:
if not isinstance(prog, list):
diff --git a/test cases/common/182 find override/meson.build b/test cases/common/182 find override/meson.build
index f217001..edb1687 100644
--- a/test cases/common/182 find override/meson.build
+++ b/test cases/common/182 find override/meson.build
@@ -23,3 +23,9 @@ six_prog = find_program('six_meson_exe')
assert(six_prog.found())
assert(six_prog.full_path() != '')
assert(six_prog.full_path() == six_prog.path())
+
+# We have prog-version.py in current directory, but it's version 1.0.
+# This needs to use fallback for "prog-version" name which will be version 2.0.
+prog = find_program('prog-version.py', 'prog-version', version: '>= 2.0')
+assert(prog.found())
+assert(prog.version() == '2.0')
diff --git a/test cases/common/182 find override/prog-version.py b/test cases/common/182 find override/prog-version.py
new file mode 100755
index 0000000..c00dd99
--- /dev/null
+++ b/test cases/common/182 find override/prog-version.py
@@ -0,0 +1,3 @@
+#! /usr/bin/env python3
+
+print('1.0')
diff --git a/test cases/common/182 find override/subprojects/sub2.wrap b/test cases/common/182 find override/subprojects/sub2.wrap
new file mode 100644
index 0000000..035629f
--- /dev/null
+++ b/test cases/common/182 find override/subprojects/sub2.wrap
@@ -0,0 +1,5 @@
+[wrap-file]
+directory = sub2
+
+[provide]
+program_names = prog-version
diff --git a/test cases/common/182 find override/subprojects/sub2/meson.build b/test cases/common/182 find override/subprojects/sub2/meson.build
new file mode 100644
index 0000000..f542073
--- /dev/null
+++ b/test cases/common/182 find override/subprojects/sub2/meson.build
@@ -0,0 +1,4 @@
+project('sub2')
+
+prog = find_program('prog-version.py')
+meson.override_find_program('prog-version', prog)
diff --git a/test cases/common/182 find override/subprojects/sub2/prog-version.py b/test cases/common/182 find override/subprojects/sub2/prog-version.py
new file mode 100755
index 0000000..78401bb
--- /dev/null
+++ b/test cases/common/182 find override/subprojects/sub2/prog-version.py
@@ -0,0 +1,3 @@
+#! /usr/bin/env python3
+
+print('2.0')