From f9b3cd6d49bf5e9287e3fb3cd3267ab8333e4e72 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 17 Dec 2018 10:51:38 -0800 Subject: [PATCH] WIP: Add a summary() function for configuration summarization This has been requested multiple times in the mesa/xorg community, and apparently in the GStreamer community as well. This function can be called one per project (so subprojects can call it as well), and takes up to a single positional argument, and an unlimited number of free form keyword arguments, the values of which must be dictionaries. At the end of the configuration phase all of the information passed to the summary function is printed, separating the main project from each subproject, and printing the group information. For example: ```meson sec1 = {'driver' : 'foobar', 'OS' : 'Linux', 'API' : 1.7} ... sec2 = {'driver' : 'dive comp', 'OS' : 'Minix', 'API' : 1.1.2} ... sec3 = {'with' : {'mesa' : true, 'gbm' : false}} summary( {'Backend' : 'OpenGL'}, Server : sec1, Client : sec2, Misc : sec3, ) ``` Which would print something like: ```txt Configuration Summary: Backend = OpenGL Server: driver = foobar OS = Linux API = 1.7 Client: driver = dive comp OS = Minix API = 1.1.2 Misc: with = {'mesa : true, 'gbm' : false} ``` Fixes #757 --- mesonbuild/interpreter.py | 55 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 4d4445ed613e..345f2eed94dc 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1905,6 +1905,7 @@ def __init__(self, build, backend=None, subproject='', subdir='', subproject_dir self.coredata = self.environment.get_coredata() self.backend = backend self.subproject = subproject + self.summary = {} if modules is None: self.modules = {} else: @@ -2009,6 +2010,7 @@ def build_func_dict(self): 'subdir': self.func_subdir, 'subdir_done': self.func_subdir_done, 'subproject': self.func_subproject, + 'summary': self.func_summary, 'shared_library': self.func_shared_lib, 'shared_module': self.func_shared_module, 'static_library': self.func_static_lib, @@ -2268,7 +2270,7 @@ def func_option(self, nodes, args, kwargs): @stringArgs def func_subproject(self, nodes, args, kwargs): if len(args) != 1: - raise InterpreterException('Subproject takes exactly one argument') + raise InterpreterException('Subproject takes exactly one argument') dirname = args[0] return self.do_subproject(dirname, kwargs) @@ -2361,6 +2363,7 @@ def do_subproject(self, dirname, kwargs): self.build_def_files += subi.build_def_files self.build.merge(subi.build) self.build.subprojects[dirname] = subi.project_version + self.summary.update(subi.summary) return self.subprojects[dirname] def get_option_internal(self, optname): @@ -2603,6 +2606,54 @@ def func_message(self, node, args, kwargs): argstr = self.get_message_string_arg(node) mlog.log(mlog.bold('Message:'), argstr) + @FeatureNew('summary', '0.50.0') + def func_summary(self, node, args, kwargs): + if self.subproject in self.summary: + raise InterpreterException('Summary can only be called once per project.') + + if len(args) > 1: + raise InterpreterException('Summary accepts zero or one argument.') + try: + # To convert None to a dict + arg = args[0] or {} + except IndexError: + arg = {} + + if not isinstance(arg, dict): + raise InterpreterException('Summary argument must be a dictionary.') + if not all(isinstance(a, dict) for a in kwargs.values()): + raise InterpreterException('Summary kwargs must be dictionaries.') + + self.summary[self.subproject] = (arg, kwargs) + + def _print_summary(self): + """Print the configuration summary. + + Called after all projects and subprojects are configured and used to + print all of the configuration at once. + """ + mlog.log('') + mlog.log(mlog.bold('Configuration Summary:')) + + def printer(arg, kwargs): + for k, v in arg.items(): + mlog.log(' ', k, '=', v) + for s, t in kwargs.items(): + mlog.log(' ', mlog.bold(s + ':')) + for k, v in t.items(): + mlog.log(' ', k, '=', v) + mlog.log('') + + for project, (arg, kwargs) in sorted(self.summary.items()): + if project == '': + continue + mlog.log('', mlog.bold('Subproject : ' + project)) + printer(arg, kwargs) + + if self.summary.get(''): + mlog.log('', mlog.bold('Main Project')) + printer(*self.summary['']) + @FeatureNew('warning', '0.44.0') @noKwargs def func_warning(self, node, args, kwargs): @@ -3874,6 +3925,8 @@ def run(self): FeatureDeprecated.report(self.subproject) if not self.is_subproject(): self.print_extra_warnings() + if self.subproject == '': + self._print_summary() def print_extra_warnings(self): for c in self.build.compilers.values():