Add a new 'environment' object to be used to build test environment (#781)

Allowing user to fine tune tests environment variables
pull/783/head
Thibault Saunier 8 years ago committed by Jussi Pakkanen
parent 8fd8c16a87
commit a2e7ebc575
  1. 35
      mesonbuild/build.py
  2. 63
      mesonbuild/interpreter.py
  3. 4
      mesonbuild/scripts/meson_test.py
  4. 10
      test cases/common/48 test args/envvars.c
  5. 8
      test cases/common/48 test args/meson.build

@ -193,6 +193,41 @@ class ExtractedObjects():
self.target = target self.target = target
self.srclist = srclist self.srclist = srclist
class EnvironmentVariables():
def __init__(self):
self.envvars = []
def get_value(self, name, values, kwargs):
separator = kwargs.get('separator', os.pathsep)
value = ''
for var in values:
value += separator + var
return separator, value.strip(separator)
def set(self, env, name, values, kwargs):
return self.get_value(name, values, kwargs)[1]
def append(self, env, name, values, kwargs):
sep, value = self.get_value(name, values, kwargs)
if name in env:
return env[name] + sep + value
return value
def prepend(self, env, name, values, kwargs):
sep, value = self.get_value(name, values, kwargs)
if name in env:
return value + sep + env[name]
return value
def get_env(self, full_env):
env = {}
for method, name, values, kwargs in self.envvars:
env[name] = method(full_env, name, values, kwargs)
return env
class BuildTarget(): class BuildTarget():
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
self.name = name self.name = name

@ -180,6 +180,37 @@ class ConfigureFileHolder(InterpreterObject):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data) self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data)
class EnvironmentVariablesHolder(InterpreterObject):
def __init__(self):
super().__init__()
self.held_object = build.EnvironmentVariables()
self.methods.update({'set': self.set_method,
'append': self.append_method,
'prepend' : self.prepend_method,
})
@stringArgs
def add_var(self, method, args, kwargs):
if not isinstance(kwargs.get("separator", ""), str):
raise InterpreterException("EnvironmentVariablesHolder methods 'separator'"
" argument needs to be a string.")
if len(args) < 2:
raise InterpreterException("EnvironmentVariablesHolder methods require at least"
"2 arguments, first is the name of the variable and"
" following one are values")
self.held_object.envvars.append((method, args[0], args[1:], kwargs))
def set_method(self, args, kwargs):
self.add_var(self.held_object.set, args, kwargs)
def append_method(self, args, kwargs):
self.add_var(self.held_object.append, args, kwargs)
def prepend_method(self, args, kwargs):
self.add_var(self.held_object.prepend, args, kwargs)
class ConfigurationDataHolder(InterpreterObject): class ConfigurationDataHolder(InterpreterObject):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -1124,6 +1155,7 @@ class Interpreter():
'files' : self.func_files, 'files' : self.func_files,
'declare_dependency': self.func_declare_dependency, 'declare_dependency': self.func_declare_dependency,
'assert': self.func_assert, 'assert': self.func_assert,
'environment' : self.func_environment,
} }
def module_method_callback(self, invalues): def module_method_callback(self, invalues):
@ -1949,18 +1981,21 @@ class Interpreter():
if not isinstance(i, (str, mesonlib.File)): if not isinstance(i, (str, mesonlib.File)):
raise InterpreterException('Command line arguments must be strings') raise InterpreterException('Command line arguments must be strings')
envlist = kwargs.get('env', []) envlist = kwargs.get('env', [])
if not isinstance(envlist, list): if isinstance(envlist, EnvironmentVariablesHolder):
envlist = [envlist] env = envlist.held_object
env = {} else:
for e in envlist: if not isinstance(envlist, list):
if '=' not in e: envlist = [envlist]
raise InterpreterException('Env var definition must be of type key=val.') env = {}
(k, val) = e.split('=', 1) for e in envlist:
k = k.strip() if '=' not in e:
val = val.strip() raise InterpreterException('Env var definition must be of type key=val.')
if ' ' in k: (k, val) = e.split('=', 1)
raise InterpreterException('Env var key must not have spaces in it.') k = k.strip()
env[k] = val val = val.strip()
if ' ' in k:
raise InterpreterException('Env var key must not have spaces in it.')
env[k] = val
valgrind_args = kwargs.get('valgrind_args', []) valgrind_args = kwargs.get('valgrind_args', [])
if not isinstance(valgrind_args, list): if not isinstance(valgrind_args, list):
valgrind_args = [valgrind_args] valgrind_args = [valgrind_args]
@ -2147,6 +2182,10 @@ class Interpreter():
else: else:
self.build.global_link_args[lang] = args self.build.global_link_args[lang] = args
def func_environment(self, node, args, kwargs):
return EnvironmentVariablesHolder()
def flatten(self, args): def flatten(self, args):
if isinstance(args, mparser.StringNode): if isinstance(args, mparser.StringNode):
return args.value return args.value

@ -15,6 +15,7 @@
# limitations under the License. # limitations under the License.
import mesonbuild import mesonbuild
from .. import build
import sys, os, subprocess, time, datetime, pickle, multiprocessing, json import sys, os, subprocess, time, datetime, pickle, multiprocessing, json
import concurrent.futures as conc import concurrent.futures as conc
import argparse import argparse
@ -128,6 +129,9 @@ def run_single_test(wrap, test):
cmd = wrap + cmd + test.cmd_args cmd = wrap + cmd + test.cmd_args
starttime = time.time() starttime = time.time()
child_env = os.environ.copy() child_env = os.environ.copy()
if isinstance(test.env, build.EnvironmentVariables):
test.env = test.env.get_env(child_env)
child_env.update(test.env) child_env.update(test.env)
if len(test.extra_paths) > 0: if len(test.extra_paths) > 0:
child_env['PATH'] = child_env['PATH'] + ';'.join([''] + test.extra_paths) child_env['PATH'] = child_env['PATH'] + ';'.join([''] + test.extra_paths)

@ -4,12 +4,20 @@
int main(int argc, char **argv) { int main(int argc, char **argv) {
if(strcmp(getenv("first"), "val1") != 0) { if(strcmp(getenv("first"), "val1") != 0) {
fprintf(stderr, "First envvar is wrong.\n"); fprintf(stderr, "First envvar is wrong. %s\n", getenv("first"));
return 1; return 1;
} }
if(strcmp(getenv("second"), "val2") != 0) { if(strcmp(getenv("second"), "val2") != 0) {
fprintf(stderr, "Second envvar is wrong.\n"); fprintf(stderr, "Second envvar is wrong.\n");
return 1; return 1;
} }
if(strcmp(getenv("third"), "val3:and_more") != 0) {
fprintf(stderr, "Third envvar is wrong.\n");
return 1;
}
if(strstr(getenv("PATH"), "fakepath:") != NULL) {
fprintf(stderr, "Third envvar is wrong.\n");
return 1;
}
return 0; return 0;
} }

@ -3,6 +3,12 @@ project('test features', 'c')
e1 = executable('cmd_args', 'cmd_args.c') e1 = executable('cmd_args', 'cmd_args.c')
e2 = executable('envvars', 'envvars.c') e2 = executable('envvars', 'envvars.c')
env = environment()
env.set('first', 'val1')
env.set('second', 'val2')
env.set('third', 'val3', 'and_more', separator: ':')
env.append('PATH', 'fakepath', separator: ':')
test('command line arguments', e1, args : ['first', 'second']) test('command line arguments', e1, args : ['first', 'second'])
test('environment variables', e2, env : ['first=val1', 'second=val2']) test('environment variables', e2, env : env)
test('file arg', find_program('tester.py'), args : files('testfile.txt')) test('file arg', find_program('tester.py'), args : files('testfile.txt'))

Loading…
Cancel
Save