Merge pull request #1747 from centricular/run-command-configure-file

Some fixes to run_command()
pull/1760/head
Jussi Pakkanen 8 years ago committed by GitHub
commit e0cf45edf0
  1. 20
      mesonbuild/dependencies.py
  2. 64
      mesonbuild/interpreter.py
  3. 9
      test cases/common/105 find program path/meson.build
  4. 0
      test cases/common/105 find program path/program.py

@ -465,8 +465,9 @@ class ExternalProgram:
@staticmethod
def _shebang_to_cmd(script):
"""
Windows does not understand shebangs, so we check if the file has a
shebang and manually parse it to figure out the interpreter to use
Check if the file has a shebang and manually parse it to figure out
the interpreter to use. This is useful if the script is not executable
or if we're on Windows (which does not understand shebangs).
"""
try:
with open(script) as f:
@ -504,15 +505,17 @@ class ExternalProgram:
if os.path.exists(trial):
if self._is_executable(trial):
return [trial]
# Now getting desperate. Maybe it is a script file that is
# a) not chmodded executable, or
# b) we are on windows so they can't be directly executed.
return self._shebang_to_cmd(trial)
else:
if mesonlib.is_windows():
for ext in self.windows_exts:
trial_ext = '{}.{}'.format(trial, ext)
if os.path.exists(trial_ext):
return [trial_ext]
return False
# Now getting desperate. Maybe it is a script file that is a) not chmodded
# executable or b) we are on windows so they can't be directly executed.
return self._shebang_to_cmd(trial)
def _search(self, name, search_dir):
'''
@ -525,7 +528,8 @@ class ExternalProgram:
# Do a standard search in PATH
command = shutil.which(name)
if not mesonlib.is_windows():
# On UNIX-like platforms, the standard PATH search is enough
# On UNIX-like platforms, shutil.which() is enough to find
# all executables whether in PATH or with an absolute path
return [command]
# HERE BEGINS THE TERROR OF WINDOWS
if command:
@ -567,9 +571,9 @@ class ExternalProgram:
return self.command[:]
def get_path(self):
# Assume that the last element is the full path to the script
# If it's not a script, this will be an array of length 1
if self.found():
# Assume that the last element is the full path to the script or
# binary being run
return self.command[-1]
return None

@ -23,7 +23,7 @@ from . import compilers
from .wrap import wrap, WrapMode
from . import mesonlib
from .mesonlib import FileMode, Popen_safe, get_meson_script
from .dependencies import InternalDependency, Dependency
from .dependencies import InternalDependency, Dependency, ExternalProgram
from .interpreterbase import InterpreterBase
from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs
from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode
@ -72,17 +72,19 @@ class TryRunResultHolder(InterpreterObject):
class RunProcess(InterpreterObject):
def __init__(self, command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False):
def __init__(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False):
super().__init__()
pc, self.stdout, self.stderr = self.run_command(command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir)
if not isinstance(cmd, ExternalProgram):
raise AssertionError('BUG: RunProcess must be passed an ExternalProgram')
pc, self.stdout, self.stderr = self.run_command(cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir)
self.returncode = pc.returncode
self.methods.update({'returncode': self.returncode_method,
'stdout': self.stdout_method,
'stderr': self.stderr_method,
})
def run_command(self, command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir):
cmd_name = command_array[0]
def run_command(self, cmd, args, source_dir, build_dir, subdir, mesonintrospect, in_builddir):
command_array = cmd.get_command() + args
env = {'MESON_SOURCE_ROOT': source_dir,
'MESON_BUILD_ROOT': build_dir,
'MESON_SUBDIR': subdir,
@ -94,18 +96,6 @@ class RunProcess(InterpreterObject):
child_env = os.environ.copy()
child_env.update(env)
mlog.debug('Running command:', ' '.join(command_array))
try:
return Popen_safe(command_array, env=child_env, cwd=cwd)
except FileNotFoundError:
pass
# Was not a command, is a program in path?
exe = shutil.which(cmd_name)
if exe is not None:
command_array = [exe] + command_array[1:]
return Popen_safe(command_array, env=child_env, cwd=cwd)
# No? Maybe it is a script in the source tree.
fullpath = os.path.join(source_dir, subdir, cmd_name)
command_array = [fullpath] + command_array[1:]
try:
return Popen_safe(command_array, env=child_env, cwd=cwd)
except FileNotFoundError:
@ -250,7 +240,6 @@ class DependencyHolder(InterpreterObject):
def found_method(self, args, kwargs):
if self.held_object.type_name == 'internal':
return True
return self.held_object.found()
def version_method(self, args, kwargs):
@ -1105,7 +1094,8 @@ class MesonMain(InterpreterObject):
if found.found():
self._found_source_scripts[key] = found
else:
raise InterpreterException('Script {!r} not found'.format(name))
m = 'Script or command {!r} not found or not executable'
raise InterpreterException(m.format(name))
return build.RunScript(found.get_command(), args)
def add_install_script_method(self, args, kwargs):
@ -1469,28 +1459,38 @@ class Interpreter(InterpreterBase):
raise InterpreterException('Not enough arguments')
cmd = args[0]
cargs = args[1:]
srcdir = self.environment.get_source_dir()
builddir = self.environment.get_build_dir()
m = 'must be a string, or the output of find_program(), files(), or ' \
'configure_file(); not {!r}'
if isinstance(cmd, ExternalProgramHolder):
cmd = cmd.get_command()
elif isinstance(cmd, str):
cmd = [cmd]
cmd = cmd.held_object
else:
raise InterpreterException('First argument should be find_program() '
'or string, not {!r}'.format(cmd))
if isinstance(cmd, mesonlib.File):
cmd = cmd.absolute_path(srcdir, builddir)
elif not isinstance(cmd, str):
raise InterpreterException('First argument ' + m.format(cmd))
# Prefer scripts in the current source directory
search_dir = os.path.join(srcdir, self.subdir)
prog = ExternalProgram(cmd, silent=True, search_dir=search_dir)
if not prog.found():
raise InterpreterException('Program or command {!r} not found'
'or not executable'.format(cmd))
cmd = prog
expanded_args = []
for a in mesonlib.flatten(cargs):
if isinstance(a, str):
expanded_args.append(a)
elif isinstance(a, mesonlib.File):
if a.is_built:
raise InterpreterException('Can not use generated files in run_command.')
expanded_args.append(os.path.join(self.environment.get_source_dir(), str(a)))
expanded_args.append(a.absolute_path(srcdir, builddir))
elif isinstance(a, ExternalProgramHolder):
expanded_args.append(a.held_object.get_path())
else:
raise InterpreterException('Run_command arguments must be strings or the output of files().')
args = cmd + expanded_args
raise InterpreterException('Arguments ' + m.format(a))
in_builddir = kwargs.get('in_builddir', False)
if not isinstance(in_builddir, bool):
raise InterpreterException('in_builddir must be boolean.')
return RunProcess(args, self.environment.source_dir, self.environment.build_dir, self.subdir,
return RunProcess(cmd, expanded_args, srcdir, builddir, self.subdir,
get_meson_script(self.environment, 'mesonintrospect'), in_builddir)
@stringArgs
@ -1846,7 +1846,7 @@ class Interpreter(InterpreterBase):
if progobj.found():
return progobj
if required and not progobj.found():
raise InvalidArguments('Program "%s" not found.' % exename)
raise InvalidArguments('Program "%s" not found or not executable' % exename)
return progobj
def func_find_library(self, node, args, kwargs):
@ -2426,7 +2426,7 @@ different subdirectory.
exe_wrapper.append(i)
elif isinstance(i, dependencies.ExternalProgram):
if not i.found():
raise InterpreterException('Tried to use non-found external executable.')
raise InterpreterException('Tried to use non-found executable.')
exe_wrapper += i.get_command()
else:
raise InterpreterException('Exe wrapper can only contain strings or external binaries.')

@ -1,9 +1,6 @@
project('find program', 'c')
python = find_program('python3', required : false)
if not python.found()
python = find_program('python')
endif
python = import('python3').find_python()
# Source file via string
prog = find_program('program.py')
@ -14,8 +11,8 @@ py = configure_file(input : 'program.py',
output : 'builtprogram.py',
configuration : configuration_data())
foreach f : [prog, find_program(py), find_program(progf)]
ret = run_command(python, f.path())
foreach f : [prog, progf, py, find_program(py), find_program(progf)]
ret = run_command(python, f)
assert(ret.returncode() == 0, 'can\'t manually run @0@'.format(prog.path()))
assert(ret.stdout().strip() == 'Found', 'wrong output from manually-run @0@'.format(prog.path()))

Loading…
Cancel
Save