From 06481666f4e74ecef01e59351fc345ab0962d998 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 12 May 2020 10:36:55 -0700 Subject: [PATCH 1/8] interpreter: Replace some uses of mlog.deprecation with FeatureDeprecated This gives the version that the feature was deprecated in, and doesn't print the warning if the project supports versions of meson in which the project wasn't deprecated. --- mesonbuild/build.py | 1 - mesonbuild/interpreter.py | 7 +++++-- mesonbuild/modules/gnome.py | 9 +++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index fdfca7357..7c065c8b5 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -2172,7 +2172,6 @@ class CustomTarget(Target): if 'build_always' in kwargs and 'build_always_stale' in kwargs: raise InvalidArguments('build_always and build_always_stale are mutually exclusive. Combine build_by_default and build_always_stale.') elif 'build_always' in kwargs: - mlog.deprecation('build_always is deprecated. Combine build_by_default and build_always_stale instead.') if 'build_by_default' not in kwargs: self.build_by_default = kwargs['build_always'] self.build_always_stale = kwargs['build_always'] diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 8c7a82c88..f80faa8aa 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -29,7 +29,7 @@ from .interpreterbase import InterpreterBase from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, stringArgs, permittedKwargs, noArgsFlattening from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler, disablerIfNotFound -from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs +from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs from .interpreterbase import ObjectHolder from .modules import ModuleReturnValue from .cmake import CMakeInterpreter @@ -527,8 +527,9 @@ class ExternalProgramHolder(InterpreterObject, ObjectHolder): @noPosargs @permittedKwargs({}) + @FeatureDeprecated('ExternalProgram.path', '0.55.0', + 'use ExternalProgram.full_path() instead') def path_method(self, args, kwargs): - mlog.deprecation('path() method is deprecated and replaced by full_path()') return self._full_path() @noPosargs @@ -3686,6 +3687,8 @@ external dependencies (including libraries) must go to "dependencies".''') raise InterpreterException('Unknown target_type.') @permittedKwargs(permitted_kwargs['vcs_tag']) + @FeatureDeprecatedKwargs('custom_target', '0.47.0', ['build_always'], + 'combine build_by_default and build_always_stale instead.') def func_vcs_tag(self, node, args, kwargs): if 'input' not in kwargs or 'output' not in kwargs: raise InterpreterException('Keyword arguments input and output must exist') diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 01acb37f1..ea1b32548 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -33,7 +33,7 @@ from ..mesonlib import ( join_args, unholder, ) from ..dependencies import Dependency, PkgConfigDependency, InternalDependency, ExternalProgram -from ..interpreterbase import noKwargs, permittedKwargs, FeatureNew, FeatureNewKwargs +from ..interpreterbase import noKwargs, permittedKwargs, FeatureNew, FeatureNewKwargs, FeatureDeprecatedKwargs # gresource compilation is broken due to the way # the resource compiler and Ninja clash about it @@ -834,6 +834,8 @@ class GnomeModule(ExtensionModule): return ModuleReturnValue(target_g, [target_g]) @permittedKwargs({'sources', 'media', 'symlink_media', 'languages'}) + @FeatureDeprecatedKwargs('gnome.yelp', '0.43.0', ['languages'], + 'Use a LINGUAS file in the source directory instead') def yelp(self, state, args, kwargs): if len(args) < 1: raise MesonException('Yelp requires a project id') @@ -848,11 +850,6 @@ class GnomeModule(ExtensionModule): source_str = '@@'.join(sources) langs = mesonlib.stringlistify(kwargs.pop('languages', [])) - if langs: - mlog.deprecation('''The "languages" argument of gnome.yelp() is deprecated. -Use a LINGUAS file in the sources directory instead. -This will become a hard error in the future.''') - media = mesonlib.stringlistify(kwargs.pop('media', [])) symlinks = kwargs.pop('symlink_media', True) From e3b2f1b82f2987a233b8a386457958b533acce04 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 12 May 2020 10:39:50 -0700 Subject: [PATCH 2/8] interpreterbase: Add a oneline helper method for Feature(New|Deprecated) This allows us to replace FeatureNew(..).use() with just FeatureNew.single_use(...). It's a lttle cleaner and hides some of the smell. --- mesonbuild/interpreterbase.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index af9018b08..6c2e73f43 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -286,6 +286,13 @@ class FeatureCheckBase(metaclass=abc.ABCMeta): return f(*wrapped_args, **wrapped_kwargs) return wrapped + @classmethod + def single_use(cls, feature_name: str, version: str, subproject: str, + extra_message: T.Optional[str] = None) -> None: + """Oneline version that instantiates and calls use().""" + cls(feature_name, version, extra_message).use(subproject) + + class FeatureNew(FeatureCheckBase): """Checks for new features""" @@ -342,7 +349,13 @@ class FeatureDeprecated(FeatureCheckBase): mlog.warning(*args) -class FeatureCheckKwargsBase: +class FeatureCheckKwargsBase(metaclass=abc.ABCMeta): + + @property + @abc.abstractmethod + def feature_check_class(self) -> T.Type[FeatureCheckBase]: + pass + def __init__(self, feature_name: str, feature_version: str, kwargs: T.List[str]): self.feature_name = feature_name self.feature_version = feature_version @@ -351,8 +364,6 @@ class FeatureCheckKwargsBase: def __call__(self, f): @wraps(f) def wrapped(*wrapped_args, **wrapped_kwargs): - # Which FeatureCheck class to invoke - FeatureCheckClass = self.feature_check_class kwargs, subproject = _get_callee_args(wrapped_args, want_subproject=True)[3:5] if subproject is None: raise AssertionError('{!r}'.format(wrapped_args)) @@ -360,7 +371,7 @@ class FeatureCheckKwargsBase: if arg not in kwargs: continue name = arg + ' arg in ' + self.feature_name - FeatureCheckClass(name, self.feature_version).use(subproject) + self.feature_check_class.single_use(name, self.feature_version, subproject) return f(*wrapped_args, **wrapped_kwargs) return wrapped From 21c8582d150942f299bbd66ae8f93e7479cae909 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 14 May 2020 11:18:17 -0700 Subject: [PATCH 3/8] interpreterbase: Proxy extra_message through to feature_check_class --- mesonbuild/interpreterbase.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 6c2e73f43..bb88e2c08 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -356,10 +356,12 @@ class FeatureCheckKwargsBase(metaclass=abc.ABCMeta): def feature_check_class(self) -> T.Type[FeatureCheckBase]: pass - def __init__(self, feature_name: str, feature_version: str, kwargs: T.List[str]): + def __init__(self, feature_name: str, feature_version: str, + kwargs: T.List[str], extra_message: T.Optional[str] = None): self.feature_name = feature_name self.feature_version = feature_version self.kwargs = kwargs + self.extra_message = extra_message def __call__(self, f): @wraps(f) @@ -371,7 +373,8 @@ class FeatureCheckKwargsBase(metaclass=abc.ABCMeta): if arg not in kwargs: continue name = arg + ' arg in ' + self.feature_name - self.feature_check_class.single_use(name, self.feature_version, subproject) + self.feature_check_class.single_use( + name, self.feature_version, subproject, self.extra_message) return f(*wrapped_args, **wrapped_kwargs) return wrapped From a313f46be7f146314e10760db016862f9516939b Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 12 May 2020 10:53:24 -0700 Subject: [PATCH 4/8] modules/pkgconfig: Remove duplicate FeatureNew --- mesonbuild/modules/pkgconfig.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 666a93d60..ac6c9b17d 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -394,8 +394,6 @@ class PkgConfigModule(ExtensionModule): 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions', 'dataonly', 'conflicts'}) def generate(self, state, args, kwargs): - if 'variables' in kwargs: - FeatureNew('custom pkgconfig variables', '0.41.0').use(state.subproject) default_version = state.project_version['version'] default_install_dir = None default_description = None From d51551231ffa19c48ec5a5c36da11e7f03921262 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 12 May 2020 10:53:37 -0700 Subject: [PATCH 5/8] use FeatureNew.single_use This is just slightly cleaner looking --- mesonbuild/build.py | 4 +-- mesonbuild/interpreter.py | 43 ++++++++++++++++++--------------- mesonbuild/interpreterbase.py | 2 +- mesonbuild/modules/pkgconfig.py | 6 ++--- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 7c065c8b5..67b92a527 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -776,7 +776,7 @@ class BuildTarget(Target): if isinstance(src, str): src = File(False, self.subdir, src) elif isinstance(src, File): - FeatureNew('File argument for extract_objects', '0.50.0').use(self.subproject) + FeatureNew.single_use('File argument for extract_objects', '0.50.0', self.subproject) else: raise MesonException('Object extraction arguments must be strings or Files.') # FIXME: It could be a generated source @@ -2160,7 +2160,7 @@ class CustomTarget(Target): 'when installing a target') if isinstance(kwargs['install_dir'], list): - FeatureNew('multiple install_dir for custom_target', '0.40.0').use(self.subproject) + FeatureNew.single_use('multiple install_dir for custom_target', '0.40.0', self.subproject) # If an item in this list is False, the output corresponding to # the list index of that item will not be installed self.install_dir = typeslistify(kwargs['install_dir'], (str, bool)) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index f80faa8aa..f199774b9 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1958,8 +1958,10 @@ class MesonMain(InterpreterObject): 'Arguments to {} must be strings, Files, CustomTargets, ' 'Indexes of CustomTargets, or ConfigureFiles'.format(name)) if new: - FeatureNew('Calling "{}" with File, CustomTaget, Index of CustomTarget, ConfigureFile, Executable, or ExternalProgram'.format(name), '0.55.0').use( - self.interpreter.subproject) + FeatureNew.single_use( + 'Calling "{}" with File, CustomTaget, Index of CustomTarget, ' + 'ConfigureFile, Executable, or ExternalProgram'.format(name), + '0.55.0', self.interpreter.subproject) return script_args @permittedKwargs(set()) @@ -1983,7 +1985,8 @@ class MesonMain(InterpreterObject): if len(args) < 1: raise InterpreterException('add_dist_script takes one or more arguments') if len(args) > 1: - FeatureNew('Calling "add_dist_script" with multiple arguments', '0.49.0').use(self.interpreter.subproject) + FeatureNew.single_use('Calling "add_dist_script" with multiple arguments', + '0.49.0', self.interpreter.subproject) if self.interpreter.subproject != '': raise InterpreterException('add_dist_script may not be used in a subproject.') script_args = self._process_script_args('add_dist_script', args[1:], allow_built=True) @@ -2606,7 +2609,7 @@ external dependencies (including libraries) must go to "dependencies".''') @noKwargs def func_assert(self, node, args, kwargs): if len(args) == 1: - FeatureNew('assert function without message argument', '0.53.0').use(self.subproject) + FeatureNew.single_use('assert function without message argument', '0.53.0', self.subproject) value = args[0] message = None elif len(args) == 2: @@ -2942,7 +2945,7 @@ external dependencies (including libraries) must go to "dependencies".''') if len(args) > 1: raise InterpreterException('configuration_data takes only one optional positional arguments') elif len(args) == 1: - FeatureNew('configuration_data dictionary', '0.49.0').use(self.subproject) + FeatureNew.single_use('configuration_data dictionary', '0.49.0', self.subproject) initial_values = args[0] if not isinstance(initial_values, dict): raise InterpreterException('configuration_data first argument must be a dictionary') @@ -3083,7 +3086,7 @@ external dependencies (including libraries) must go to "dependencies".''') @noKwargs def func_message(self, node, args, kwargs): if len(args) > 1: - FeatureNew('message with more than one argument', '0.54.0').use(self.subproject) + FeatureNew.single_use('message with more than one argument', '0.54.0', self.subproject) args_str = [self.get_message_string_arg(i) for i in args] self.message_impl(args_str) @@ -3145,7 +3148,7 @@ external dependencies (including libraries) must go to "dependencies".''') @noKwargs def func_warning(self, node, args, kwargs): if len(args) > 1: - FeatureNew('warning with more than one argument', '0.54.0').use(self.subproject) + FeatureNew.single_use('warning with more than one argument', '0.54.0', self.subproject) args_str = [self.get_message_string_arg(i) for i in args] mlog.warning(*args_str, location=node) @@ -3469,15 +3472,15 @@ external dependencies (including libraries) must go to "dependencies".''') def _handle_featurenew_dependencies(self, name): 'Do a feature check on dependencies used by this subproject' if name == 'mpi': - FeatureNew('MPI Dependency', '0.42.0').use(self.subproject) + FeatureNew.single_use('MPI Dependency', '0.42.0', self.subproject) elif name == 'pcap': - FeatureNew('Pcap Dependency', '0.42.0').use(self.subproject) + FeatureNew.single_use('Pcap Dependency', '0.42.0', self.subproject) elif name == 'vulkan': - FeatureNew('Vulkan Dependency', '0.42.0').use(self.subproject) + FeatureNew.single_use('Vulkan Dependency', '0.42.0', self.subproject) elif name == 'libwmf': - FeatureNew('LibWMF Dependency', '0.44.0').use(self.subproject) + FeatureNew.single_use('LibWMF Dependency', '0.44.0', self.subproject) elif name == 'openmp': - FeatureNew('OpenMP Dependency', '0.46.0').use(self.subproject) + FeatureNew.single_use('OpenMP Dependency', '0.46.0', self.subproject) @FeatureNewKwargs('dependency', '0.54.0', ['components']) @FeatureNewKwargs('dependency', '0.52.0', ['include_type']) @@ -3599,7 +3602,7 @@ external dependencies (including libraries) must go to "dependencies".''') def get_subproject_infos(self, kwargs): fbinfo = mesonlib.stringlistify(kwargs['fallback']) if len(fbinfo) == 1: - FeatureNew('Fallback without variable name', '0.53.0').use(self.subproject) + FeatureNew.single_use('Fallback without variable name', '0.53.0', self.subproject) return fbinfo[0], None elif len(fbinfo) != 2: raise InterpreterException('Fallback info must have one or two items.') @@ -3693,7 +3696,7 @@ external dependencies (including libraries) must go to "dependencies".''') if 'input' not in kwargs or 'output' not in kwargs: raise InterpreterException('Keyword arguments input and output must exist') if 'fallback' not in kwargs: - FeatureNew('Optional fallback in vcs_tag', '0.41.0').use(self.subproject) + FeatureNew.single_use('Optional fallback in vcs_tag', '0.41.0', self.subproject) fallback = kwargs.pop('fallback', self.project_version) if not isinstance(fallback, str): raise InterpreterException('Keyword argument fallback must be a string.') @@ -3746,7 +3749,7 @@ external dependencies (including libraries) must go to "dependencies".''') if len(args) != 1: raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name') if 'depfile' in kwargs and ('@BASENAME@' in kwargs['depfile'] or '@PLAINNAME@' in kwargs['depfile']): - FeatureNew('substitutions in custom_target depfile', '0.47.0').use(self.subproject) + FeatureNew.single_use('substitutions in custom_target depfile', '0.47.0', self.subproject) return self._func_custom_target_impl(node, args, kwargs) def _func_custom_target_impl(self, node, args, kwargs): @@ -3835,7 +3838,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self @permittedKwargs(permitted_kwargs['test']) def func_test(self, node, args, kwargs): if kwargs.get('protocol') == 'gtest': - FeatureNew('"gtest" protocol for tests', '0.55.0').use(self.subproject) + FeatureNew.single_use('"gtest" protocol for tests', '0.55.0', self.subproject) self.add_test(node, args, kwargs, True) def unpack_env_kwarg(self, kwargs) -> build.EnvironmentVariables: @@ -3843,7 +3846,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self if isinstance(envlist, EnvironmentVariablesHolder): env = envlist.held_object elif isinstance(envlist, dict): - FeatureNew('environment dictionary', '0.52.0').use(self.subproject) + FeatureNew.single_use('environment dictionary', '0.52.0', self.subproject) env = EnvironmentVariablesHolder(envlist) env = env.held_object else: @@ -4159,7 +4162,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self if 'configuration' in kwargs: conf = kwargs['configuration'] if isinstance(conf, dict): - FeatureNew('configure_file.configuration dictionary', '0.49.0').use(self.subproject) + FeatureNew.single_use('configure_file.configuration dictionary', '0.49.0', self.subproject) conf = ConfigurationDataHolder(self.subproject, conf) elif not isinstance(conf, ConfigurationDataHolder): raise InterpreterException('Argument "configuration" is not of type configuration_data') @@ -4189,7 +4192,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self conf.mark_used() elif 'command' in kwargs: if len(inputs) > 1: - FeatureNew('multiple inputs in configure_file()', '0.52.0').use(self.subproject) + FeatureNew.single_use('multiple inputs in configure_file()', '0.52.0', self.subproject) # We use absolute paths for input and output here because the cwd # that the command is run from is 'unspecified', so it could change. # Currently it's builddir/subdir for in_builddir else srcdir/subdir. @@ -4437,7 +4440,7 @@ different subdirectory. if len(args) > 1: raise InterpreterException('environment takes only one optional positional arguments') elif len(args) == 1: - FeatureNew('environment positional arguments', '0.52.0').use(self.subproject) + FeatureNew.single_use('environment positional arguments', '0.52.0', self.subproject) initial_values = args[0] if not isinstance(initial_values, dict) and not isinstance(initial_values, list): raise InterpreterException('environment first argument must be a dictionary or a list') diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index bb88e2c08..634f4f278 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -584,7 +584,7 @@ class InterpreterBase: self.argument_depth += 1 for key, value in kwargs.items(): if not isinstance(key, mparser.StringNode): - FeatureNew('Dictionary entry using non literal key', '0.53.0').use(self.subproject) + FeatureNew.single_use('Dictionary entry using non literal key', '0.53.0', self.subproject) assert isinstance(key, mparser.BaseNode) # All keys must be nodes due to resolve_key_nodes=False str_key = self.evaluate_statement(key) if not isinstance(str_key, str): diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index ac6c9b17d..7597eeba1 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -76,7 +76,7 @@ class DependenciesHelper: processed_reqs = [] for obj in mesonlib.unholder(mesonlib.listify(reqs)): if not isinstance(obj, str): - FeatureNew('pkgconfig.generate requirement from non-string object', '0.46.0').use(self.state.subproject) + FeatureNew.single_use('pkgconfig.generate requirement from non-string object', '0.46.0', self.state.subproject) if hasattr(obj, 'generated_pc'): self._check_generated_pc_deprecation(obj) processed_reqs.append(obj.generated_pc) @@ -401,9 +401,9 @@ class PkgConfigModule(ExtensionModule): mainlib = None default_subdirs = ['.'] if not args and 'version' not in kwargs: - FeatureNew('pkgconfig.generate implicit version keyword', '0.46.0').use(state.subproject) + FeatureNew.single_use('pkgconfig.generate implicit version keyword', '0.46.0', state.subproject) elif len(args) == 1: - FeatureNew('pkgconfig.generate optional positional argument', '0.46.0').use(state.subproject) + FeatureNew.single_use('pkgconfig.generate optional positional argument', '0.46.0', state.subproject) mainlib = getattr(args[0], 'held_object', args[0]) if not isinstance(mainlib, (build.StaticLibrary, build.SharedLibrary)): raise mesonlib.MesonException('Pkgconfig_gen first positional argument must be a library object') From e35584e9ff33a2cba8128487b14b0a3dcfe9fbc5 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 12 May 2020 10:55:31 -0700 Subject: [PATCH 6/8] interpreter: Add always set default value for version and set it ASAP Ideally we wouldn't need to have the default dict here and could just rely on it being set as soon as project is called. There is a corner case exercised by test case common/35 run program, which is that if a FeatureNew or FeatureDeprecated is called to generate the meson version it will be unset, to work around this I've changed the type from a dict to a default dict with '' as the default value. A better fix would probably be to store all of the FeatureNew/FeatureDeprecated checks until the end, then evaluate them, but for now this results in no loss of functionality, only more functionality, even if it isn't prefect. --- mesonbuild/interpreter.py | 7 +++---- mesonbuild/mesonlib.py | 4 +++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index f199774b9..07ab4f0e9 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2985,11 +2985,14 @@ external dependencies (including libraries) must go to "dependencies".''') if ':' in proj_name: raise InvalidArguments("Project name {!r} must not contain ':'".format(proj_name)) + # This needs to be evaluated as early as possible, as meson uses this + # for things like deprecation testing. if 'meson_version' in kwargs: cv = coredata.version pv = kwargs['meson_version'] if not mesonlib.version_compare(cv, pv): raise InterpreterException('Meson version is %s but project requires %s' % (cv, pv)) + mesonlib.project_meson_versions[self.subproject] = kwargs['meson_version'] if os.path.exists(self.option_file): oi = optinterpreter.OptionInterpreter(self.subproject) @@ -3036,10 +3039,6 @@ external dependencies (including libraries) must go to "dependencies".''') self.build.subproject_dir = self.subproject_dir - mesonlib.project_meson_versions[self.subproject] = '' - if 'meson_version' in kwargs: - mesonlib.project_meson_versions[self.subproject] = kwargs['meson_version'] - self.build.projects[self.subproject] = proj_name mlog.log('Project name:', mlog.bold(proj_name)) mlog.log('Project version:', mlog.bold(self.project_version)) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index b901ec98b..26fe6ebd7 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -39,8 +39,10 @@ _U = T.TypeVar('_U') have_fcntl = False have_msvcrt = False +# TODO: this is such a hack, this really should be either in coredata or in the +# interpreter # {subproject: project_meson_version} -project_meson_versions = {} # type: T.Dict[str, str] +project_meson_versions = collections.defaultdict(str) # type: T.DefaultDict[str, str] try: import fcntl From c64715b99a310e031fd145c64b111891861e4ddc Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 12 May 2020 10:57:43 -0700 Subject: [PATCH 7/8] optinterpreter: Enable and update FeatureNew to use_single With the version information fixed we can use a FeatureNew inside the optinterpreter, so let's do it. --- mesonbuild/optinterpreter.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index c13cc5da3..dfbe6d7a7 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -16,10 +16,11 @@ import re import functools import typing as T -from . import mparser +from . import compilers from . import coredata from . import mesonlib -from . import compilers +from . import mparser +from .interpreterbase import FeatureNew forbidden_option_names = set(coredata.builtin_options.keys()) forbidden_prefixes = [lang + '_' for lang in compilers.all_languages] + ['b_', 'backend_'] @@ -200,11 +201,8 @@ class OptionInterpreter: raise OptionException('Only calls to option() are allowed in option files.') (posargs, kwargs) = self.reduce_arguments(node.args) - # FIXME: Cannot use FeatureNew while parsing options because we parse - # it before reading options in project(). See func_project() in - # interpreter.py - #if 'yield' in kwargs: - # FeatureNew('option yield', '0.45.0').use(self.subproject) + if 'yield' in kwargs: + FeatureNew.single_use('option yield', '0.45.0', self.subproject) if 'type' not in kwargs: raise OptionException('Option call missing mandatory "type" keyword argument') From cb4e4f625f8f191eb5ed1bd435a263b0c7bd11cf Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 13 May 2020 14:33:40 -0700 Subject: [PATCH 8/8] run_unittests: Use unittest.mock instead of a handrolled mock --- run_unittests.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/run_unittests.py b/run_unittests.py index 8dde4e59d..e08846780 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -717,25 +717,22 @@ class InternalTests(unittest.TestCase): self.assertEqual([1, 2, 3], extract(kwargs, 'sources')) def test_pkgconfig_module(self): - - class Mock: - pass - - dummystate = Mock() + dummystate = mock.Mock() dummystate.subproject = 'dummy' - mock = Mock() - mock.pcdep = Mock() - mock.pcdep.name = "some_name" - mock.version_reqs = [] + _mock = mock.Mock(spec=mesonbuild.dependencies.ExternalDependency) + _mock.pcdep = mock.Mock() + _mock.pcdep.name = "some_name" + _mock.version_reqs = [] + _mock = mock.Mock(held_object=_mock) # pkgconfig dependency as lib deps = mesonbuild.modules.pkgconfig.DependenciesHelper(dummystate, "thislib") - deps.add_pub_libs([mock]) + deps.add_pub_libs([_mock]) self.assertEqual(deps.format_reqs(deps.pub_reqs), "some_name") # pkgconfig dependency as requires deps = mesonbuild.modules.pkgconfig.DependenciesHelper(dummystate, "thislib") - deps.add_pub_reqs([mock]) + deps.add_pub_reqs([_mock]) self.assertEqual(deps.format_reqs(deps.pub_reqs), "some_name") def _test_all_naming(self, cc, env, patterns, platform):