From 3c0de471228420c333bb98be35a28705d0ec063d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 31 Jul 2024 17:18:42 +1000 Subject: [PATCH] Allow external programs in test()'s 'args' parameter Although it's not especially common, there are certainly cases where it's useful to pass the path to an external program to a test program. Fixes: https://github.com/mesonbuild/meson/issues/3552 Signed-off-by: David Gibson --- .../snippets/test_args_accepts_external_program.md | 10 ++++++++++ docs/yaml/functions/benchmark.yaml | 2 +- mesonbuild/backend/backends.py | 2 ++ mesonbuild/interpreter/interpreter.py | 2 ++ mesonbuild/interpreter/interpreterobjects.py | 2 +- mesonbuild/interpreter/kwargs.py | 2 +- mesonbuild/interpreter/type_checking.py | 2 +- test cases/common/41 test args/meson.build | 4 ++++ test cases/common/41 test args/wrap.py | 6 ++++++ test cases/failing/112 run_target in test/test.json | 2 +- 10 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 docs/markdown/snippets/test_args_accepts_external_program.md create mode 100755 test cases/common/41 test args/wrap.py diff --git a/docs/markdown/snippets/test_args_accepts_external_program.md b/docs/markdown/snippets/test_args_accepts_external_program.md new file mode 100644 index 000000000..d730ad5f3 --- /dev/null +++ b/docs/markdown/snippets/test_args_accepts_external_program.md @@ -0,0 +1,10 @@ +## test() and benchmark() functions accept new types + +`test` and `benchmark` now accept ExternalPrograms (as returned by +`find_program`) in the `args` list. This can be useful where the test +executable is a wrapper which invokes another program given as an +argument. + +```meson +test('some_test', find_program('sudo'), args : [ find_program('sh'), 'script.sh' ]) +``` diff --git a/docs/yaml/functions/benchmark.yaml b/docs/yaml/functions/benchmark.yaml index 0323b26e4..7a555a42d 100644 --- a/docs/yaml/functions/benchmark.yaml +++ b/docs/yaml/functions/benchmark.yaml @@ -28,7 +28,7 @@ posargs: kwargs: args: - type: list[str | file | tgt] + type: list[str | file | tgt | external_program] description: Arguments to pass to the executable env: diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 9b26d9e6c..e35660b69 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -1261,6 +1261,8 @@ class Backend: cmd_args.append(a) elif isinstance(a, (build.Target, build.CustomTargetIndex)): cmd_args.extend(self.construct_target_rel_paths(a, t.workdir)) + elif isinstance(a, programs.ExternalProgram): + cmd_args.extend(a.get_command()) else: raise MesonException('Bad object in test command.') diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 9a524037a..92315ff0f 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -2268,6 +2268,8 @@ class Interpreter(InterpreterBase, HoldableObject): kwargs: T.Dict[str, T.Any], is_base_test: bool): if isinstance(args[1], (build.CustomTarget, build.CustomTargetIndex)): FeatureNew.single_use('test with CustomTarget as command', '1.4.0', self.subproject) + if any(isinstance(i, ExternalProgram) for i in kwargs['args']): + FeatureNew.single_use('test with external_program in args', '1.6.0', self.subproject) t = self.make_test(node, args, kwargs) if is_base_test: diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index d5c1efaa8..bbc5b8608 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -753,7 +753,7 @@ class Test(MesonInterpreterObject): exe: T.Union[ExternalProgram, build.Executable, build.CustomTarget, build.CustomTargetIndex], depends: T.List[T.Union[build.CustomTarget, build.BuildTarget]], is_parallel: bool, - cmd_args: T.List[T.Union[str, mesonlib.File, build.Target]], + cmd_args: T.List[T.Union[str, mesonlib.File, build.Target, ExternalProgram]], env: mesonlib.EnvironmentVariables, should_fail: bool, timeout: int, workdir: T.Optional[str], protocol: str, priority: int, verbose: bool): diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 461ddc9bf..eee53c5ff 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -38,7 +38,7 @@ class BaseTest(TypedDict): """Shared base for the Rust module.""" - args: T.List[T.Union[str, File, build.Target]] + args: T.List[T.Union[str, File, build.Target, ExternalProgram]] should_fail: bool timeout: int workdir: T.Optional[str] diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 0d92a3dbf..ed34be950 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -485,7 +485,7 @@ VARIABLES_KW: KwargInfo[T.Dict[str, str]] = KwargInfo( PRESERVE_PATH_KW: KwargInfo[bool] = KwargInfo('preserve_path', bool, default=False, since='0.63.0') TEST_KWS: T.List[KwargInfo] = [ - KwargInfo('args', ContainerTypeInfo(list, (str, File, BuildTarget, CustomTarget, CustomTargetIndex)), + KwargInfo('args', ContainerTypeInfo(list, (str, File, BuildTarget, CustomTarget, CustomTargetIndex, ExternalProgram)), listify=True, default=[]), KwargInfo('should_fail', bool, default=False), KwargInfo('timeout', int, default=30), diff --git a/test cases/common/41 test args/meson.build b/test cases/common/41 test args/meson.build index 7efd8d5da..ddd369e7f 100644 --- a/test cases/common/41 test args/meson.build +++ b/test cases/common/41 test args/meson.build @@ -45,3 +45,7 @@ custompathtgt = custom_target('testpathappend', build_always : true, command : [pathtester], env : env) + +# https://github.com/mesonbuild/meson/issues/3552 +wrap = find_program('wrap.py') +test('external program arg', wrap, args : [testerpy, testfile]) diff --git a/test cases/common/41 test args/wrap.py b/test cases/common/41 test args/wrap.py new file mode 100755 index 000000000..87508e008 --- /dev/null +++ b/test cases/common/41 test args/wrap.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +import subprocess +import sys + +subprocess.run(sys.argv[1:]) diff --git a/test cases/failing/112 run_target in test/test.json b/test cases/failing/112 run_target in test/test.json index 100db9482..515897899 100644 --- a/test cases/failing/112 run_target in test/test.json +++ b/test cases/failing/112 run_target in test/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/112 run_target in test/meson.build:7:0: ERROR: test keyword argument 'args' was of type array[RunTarget] but should have been array[str | File | BuildTarget | CustomTarget | CustomTargetIndex]" + "line": "test cases/failing/112 run_target in test/meson.build:7:0: ERROR: test keyword argument 'args' was of type array[RunTarget] but should have been array[str | File | BuildTarget | CustomTarget | CustomTargetIndex | ExternalProgram]" } ] }