run_command: add env kwarg

pull/4838/head
Jan Tojnar 6 years ago committed by Jussi Pakkanen
parent c07e5124bc
commit 33d82201bd
  1. 8
      docs/markdown/External-commands.md
  2. 6
      docs/markdown/Reference-manual.md
  3. 9
      docs/markdown/snippets/run_command_env.md
  4. 26
      mesonbuild/interpreter.py
  5. 6
      test cases/common/36 run program/meson.build

@ -16,6 +16,14 @@ output = r.stdout().strip()
errortxt = r.stderr().strip() errortxt = r.stderr().strip()
``` ```
Additionally, since 0.50.0, you can pass the command [`environment`](Reference-manual.html#environment-object) object:
```meson
env = environment()
env.set('FOO', 'bar')
run_command('command', 'arg1', 'arg2', env: env)
```
The `run_command` function returns an object that can be queried for The `run_command` function returns an object that can be queried for
return value and text written to stdout and stderr. The `strip` method return value and text written to stdout and stderr. The `strip` method
call is used to strip trailing and leading whitespace from call is used to strip trailing and leading whitespace from

@ -1183,12 +1183,14 @@ and Meson will set three environment variables `MESON_SOURCE_ROOT`,
directory, build directory and subdirectory the target was defined in, directory, build directory and subdirectory the target was defined in,
respectively. respectively.
This function has one keyword argument. This function supports the following keyword arguments:
- `check` takes a boolean. If `true`, the exit status code of the command will - `check` takes a boolean. If `true`, the exit status code of the command will
be checked, and the configuration will fail if it is non-zero. The default is be checked, and the configuration will fail if it is non-zero. The default is
`false`. `false`.
Since 0.47.0 Since 0.47.0
- `env` an [environment object](#environment-object) to use a custom environment
Since 0.50.0
See also [External commands](External-commands.md). See also [External commands](External-commands.md).
@ -2175,7 +2177,7 @@ and has the following methods:
This object is returned by [`environment()`](#environment) and stores This object is returned by [`environment()`](#environment) and stores
detailed information about how environment variables should be set detailed information about how environment variables should be set
during tests. It should be passed as the `env` keyword argument to during tests. It should be passed as the `env` keyword argument to
tests. It has the following methods. tests and other functions. It has the following methods.
- `append(varname, value1, value2, ...)` appends the given values to - `append(varname, value1, value2, ...)` appends the given values to
the old value of the environment variable, e.g. `env.append('FOO', the old value of the environment variable, e.g. `env.append('FOO',

@ -0,0 +1,9 @@
## `run_command` accepts `env` kwarg
You can pass [`environment`](Reference-manual.html#environment-object) object to [`run_command`](Reference-manual.html#run-command), just like to `test`:
```meson
env = environment()
env.set('FOO', 'bar')
run_command('command', 'arg1', 'arg2', env: env)
```

@ -143,31 +143,32 @@ class TryRunResultHolder(InterpreterObject):
class RunProcess(InterpreterObject): class RunProcess(InterpreterObject):
def __init__(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False, check=False, capture=True): def __init__(self, cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False, check=False, capture=True):
super().__init__() super().__init__()
if not isinstance(cmd, ExternalProgram): if not isinstance(cmd, ExternalProgram):
raise AssertionError('BUG: RunProcess must be passed an ExternalProgram') raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
self.capture = capture self.capture = capture
pc, self.stdout, self.stderr = self.run_command(cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check) pc, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check)
self.returncode = pc.returncode self.returncode = pc.returncode
self.methods.update({'returncode': self.returncode_method, self.methods.update({'returncode': self.returncode_method,
'stdout': self.stdout_method, 'stdout': self.stdout_method,
'stderr': self.stderr_method, 'stderr': self.stderr_method,
}) })
def run_command(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check=False): def run_command(self, cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check=False):
command_array = cmd.get_command() + args command_array = cmd.get_command() + args
env = {'MESON_SOURCE_ROOT': source_dir, menv = {'MESON_SOURCE_ROOT': source_dir,
'MESON_BUILD_ROOT': build_dir, 'MESON_BUILD_ROOT': build_dir,
'MESON_SUBDIR': subdir, 'MESON_SUBDIR': subdir,
'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]), 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in mesonintrospect]),
} }
if in_builddir: if in_builddir:
cwd = os.path.join(build_dir, subdir) cwd = os.path.join(build_dir, subdir)
else: else:
cwd = os.path.join(source_dir, subdir) cwd = os.path.join(source_dir, subdir)
child_env = os.environ.copy() child_env = os.environ.copy()
child_env.update(env) child_env.update(menv)
child_env = env.get_env(child_env)
stdout = subprocess.PIPE if self.capture else subprocess.DEVNULL stdout = subprocess.PIPE if self.capture else subprocess.DEVNULL
mlog.debug('Running command:', ' '.join(command_array)) mlog.debug('Running command:', ' '.join(command_array))
try: try:
@ -1954,7 +1955,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'},
'install_subdir': {'exclude_files', 'exclude_directories', 'install_dir', 'install_mode', 'strip_directory'}, 'install_subdir': {'exclude_files', 'exclude_directories', 'install_dir', 'install_mode', 'strip_directory'},
'jar': build.known_jar_kwargs, 'jar': build.known_jar_kwargs,
'project': {'version', 'meson_version', 'default_options', 'license', 'subproject_dir'}, 'project': {'version', 'meson_version', 'default_options', 'license', 'subproject_dir'},
'run_command': {'check', 'capture'}, 'run_command': {'check', 'capture', 'env'},
'run_target': {'command', 'depends'}, 'run_target': {'command', 'depends'},
'shared_library': build.known_shlib_kwargs, 'shared_library': build.known_shlib_kwargs,
'shared_module': build.known_shmod_kwargs, 'shared_module': build.known_shmod_kwargs,
@ -2259,6 +2260,7 @@ external dependencies (including libraries) must go to "dependencies".''')
if not isinstance(actual, wanted): if not isinstance(actual, wanted):
raise InvalidArguments('Incorrect argument type.') raise InvalidArguments('Incorrect argument type.')
@FeatureNewKwargs('run_command', '0.50.0', ['env'])
@FeatureNewKwargs('run_command', '0.47.0', ['check', 'capture']) @FeatureNewKwargs('run_command', '0.47.0', ['check', 'capture'])
@permittedKwargs(permitted_kwargs['run_command']) @permittedKwargs(permitted_kwargs['run_command'])
def func_run_command(self, node, args, kwargs): def func_run_command(self, node, args, kwargs):
@ -2277,6 +2279,8 @@ external dependencies (including libraries) must go to "dependencies".''')
if not isinstance(check, bool): if not isinstance(check, bool):
raise InterpreterException('Check must be boolean.') raise InterpreterException('Check must be boolean.')
env = self.unpack_env_kwarg(kwargs)
m = 'must be a string, or the output of find_program(), files() '\ m = 'must be a string, or the output of find_program(), files() '\
'or configure_file(), or a compiler object; not {!r}' 'or configure_file(), or a compiler object; not {!r}'
if isinstance(cmd, ExternalProgramHolder): if isinstance(cmd, ExternalProgramHolder):
@ -2326,7 +2330,7 @@ external dependencies (including libraries) must go to "dependencies".''')
if not a.startswith('..'): if not a.startswith('..'):
if a not in self.build_def_files: if a not in self.build_def_files:
self.build_def_files.append(a) self.build_def_files.append(a)
return RunProcess(cmd, expanded_args, srcdir, builddir, self.subdir, return RunProcess(cmd, expanded_args, env, srcdir, builddir, self.subdir,
self.environment.get_build_command() + ['introspect'], self.environment.get_build_command() + ['introspect'],
in_builddir=in_builddir, check=check, capture=capture) in_builddir=in_builddir, check=check, capture=capture)

@ -65,6 +65,12 @@ ret = run_command(py3, '-c', 'print("some output")', capture : false)
assert(ret.returncode() == 0, 'failed to run python3: ' + ret.stderr()) assert(ret.returncode() == 0, 'failed to run python3: ' + ret.stderr())
assert(ret.stdout() == '', 'stdout is "@0@" instead of empty'.format(ret.stdout())) assert(ret.stdout() == '', 'stdout is "@0@" instead of empty'.format(ret.stdout()))
c_env = environment()
c_env.append('CUSTOM_ENV_VAR', 'FOOBAR')
ret = run_command(py3, '-c', 'import os; print(os.environ.get("CUSTOM_ENV_VAR"))', env : c_env)
assert(ret.returncode() == 0, 'failed to run python3: ' + ret.stderr())
assert(ret.stdout() == 'FOOBAR\n', 'stdout is "@0@" instead of FOOBAR'.format(ret.stdout()))
dd = find_program('dd', required : false) dd = find_program('dd', required : false)
if dd.found() if dd.found()
ret = run_command(dd, 'if=/dev/urandom', 'bs=10', 'count=1', capture: false) ret = run_command(dd, 'if=/dev/urandom', 'bs=10', 'count=1', capture: false)

Loading…
Cancel
Save