diff options
author | Thibault Saunier <tsaunier@igalia.com> | 2018-07-13 13:29:41 -0400 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2018-08-27 21:37:18 +0300 |
commit | 731906504efb57aa9ae86685501f1d3a0aa22121 (patch) | |
tree | f85fe896a96cee352dae1d887f690eaabf8c761b /mesonbuild | |
parent | 899b0aae9f9afacccfd5963e84df6634e9835b5c (diff) | |
download | meson-731906504efb57aa9ae86685501f1d3a0aa22121.zip meson-731906504efb57aa9ae86685501f1d3a0aa22121.tar.gz meson-731906504efb57aa9ae86685501f1d3a0aa22121.tar.bz2 |
Add a `required` argument to `subproject`
Allowing to use the new "feature" option type and allowing not to fail
on subproject if it is not necessary to fail.
By default subprojects are "required" so previous behaviour is not
changed.
Fixes #3880
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/interpreter.py | 85 |
1 files changed, 70 insertions, 15 deletions
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 4fbb837..358dd8f 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -383,6 +383,9 @@ class DependencyHolder(InterpreterObject, ObjectHolder): 'partial_dependency': self.partial_dependency_method, }) + def found(self): + return self.found_method([], {}) + @noPosargs @permittedKwargs({}) def type_name_method(self, args, kwargs): @@ -916,16 +919,30 @@ class Test(InterpreterObject): class SubprojectHolder(InterpreterObject, ObjectHolder): - def __init__(self, subinterpreter): + def __init__(self, subinterpreter, subproject_dir, name): InterpreterObject.__init__(self) ObjectHolder.__init__(self, subinterpreter) + self.name = name + self.subproject_dir = subproject_dir self.methods.update({'get_variable': self.get_variable_method, + 'found': self.found_method, }) + @noPosargs + @permittedKwargs({}) + def found_method(self, args, kwargs): + return self.found() + + def found(self): + return self.held_object is not None + @permittedKwargs({}) def get_variable_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Get_variable takes one argument.') + if not self.found(): + raise InterpreterException('Subproject "%s/%s" disabled can\'t get_variable on it.' % ( + self.subproject_dir, self.name)) varname = args[0] if not isinstance(varname, str): raise InterpreterException('Get_variable takes a string argument.') @@ -1838,7 +1855,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, 'both_libraries': known_library_kwargs, 'library': known_library_kwargs, 'subdir': {'if_found'}, - 'subproject': {'version', 'default_options'}, + 'subproject': {'version', 'default_options', 'required'}, 'test': {'args', 'depends', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite'}, 'vcs_tag': {'input', 'output', 'fallback', 'command', 'replace_string'}, } @@ -2219,7 +2236,16 @@ external dependencies (including libraries) must go to "dependencies".''') dirname = args[0] return self.do_subproject(dirname, kwargs) + def disabled_subproject(self, dirname): + self.subprojects[dirname] = SubprojectHolder(None, self.subproject_dir, dirname) + return self.subprojects[dirname] + def do_subproject(self, dirname, kwargs): + disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) + if disabled: + mlog.log('\nSubproject', mlog.bold(dirname), ':', 'skipped: feature', mlog.bold(feature), 'disabled') + return self.disabled_subproject(dirname) + default_options = mesonlib.stringlistify(kwargs.get('default_options', [])) default_options = coredata.create_options_dict(default_options) if dirname == '': @@ -2237,7 +2263,13 @@ external dependencies (including libraries) must go to "dependencies".''') incpath = ' => '.join(fullstack) raise InvalidCode('Recursive include of subprojects: %s.' % incpath) if dirname in self.subprojects: - return self.subprojects[dirname] + subproject = self.subprojects[dirname] + + if required and not subproject.found(): + raise InterpreterException('Subproject "%s/%s" required but not found.' % ( + self.subproject_dir, dirname)) + + return subproject subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir) r = wrap.Resolver(subproject_dir_abs, self.coredata.wrap_mode) try: @@ -2249,22 +2281,35 @@ external dependencies (including libraries) must go to "dependencies".''') # promotion... self.print_nested_info(dirname) - msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}' - raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e)) + if required: + msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}' + raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e)) + + mlog.log('\nSubproject ', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)\n') + return self.disabled_subproject(dirname) + subdir = os.path.join(self.subproject_dir, resolved) os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True) self.global_args_frozen = True mlog.log() with mlog.nested(): - mlog.log('\nExecuting subproject', mlog.bold(dirname), '\n') - subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir, - self.modules, default_options) - subi.subprojects = self.subprojects - - subi.subproject_stack = self.subproject_stack + [dirname] - current_active = self.active_projectname - subi.run() - mlog.log('\nSubproject', mlog.bold(dirname), 'finished.') + try: + mlog.log('\nExecuting subproject', mlog.bold(dirname), '\n') + subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir, + self.modules, default_options) + subi.subprojects = self.subprojects + + subi.subproject_stack = self.subproject_stack + [dirname] + current_active = self.active_projectname + subi.run() + mlog.log('\nSubproject', mlog.bold(dirname), 'finished.') + except Exception as e: + if not required: + mlog.log(e) + mlog.log('\nSubproject', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)') + return self.disabled_subproject(dirname) + else: + raise e if 'version' in kwargs: pv = subi.project_version @@ -2274,7 +2319,7 @@ external dependencies (including libraries) must go to "dependencies".''') self.active_projectname = current_active self.build.subprojects[dirname] = subi.project_version self.subprojects.update(subi.subprojects) - self.subprojects[dirname] = SubprojectHolder(subi) + self.subprojects[dirname] = SubprojectHolder(subi, self.subproject_dir, dirname) self.build_def_files += subi.build_def_files return self.subprojects[dirname] @@ -2799,6 +2844,13 @@ external dependencies (including libraries) must go to "dependencies".''') def get_subproject_dep(self, name, dirname, varname, required): try: + subproject = self.subprojects[dirname] + if not subproject.found(): + if not required: + return DependencyHolder(NotFoundDependency(self.environment), self.subproject) + + raise DependencyException('Subproject %s was not found.' % (name)) + dep = self.subprojects[dirname].get_variable_method([varname], {}) except InvalidArguments as e: if required: @@ -2820,6 +2872,9 @@ external dependencies (including libraries) must go to "dependencies".''') dep = self.get_subproject_dep(name, dirname, varname, required) if not dep: return False + if not dep.found(): + return dep + found = dep.version_method([], {}) # Don't do a version check if the dependency is not found and not required if not dep.found_method([], {}) and not required: |