diff options
-rw-r--r-- | docs/markdown/Reference-manual.md | 3 | ||||
-rw-r--r-- | docs/markdown/snippets/summary.md | 8 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 61 | ||||
-rw-r--r-- | mesonbuild/mlog.py | 4 | ||||
-rwxr-xr-x | run_unittests.py | 5 | ||||
-rw-r--r-- | test cases/unit/72 summary/meson.build | 1 |
6 files changed, 59 insertions, 23 deletions
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 475b711..ff82164 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1239,9 +1239,10 @@ pair doesn't appear twice. All sections will be collected and printed at the end of the configuration in the same order as they have been called. Keyword arguments: +- `section` title to group a set of key/value pairs. - `bool_yn` if set to true, all boolean values will be replaced by green YES or red NO. -- `section` title to group a set of key/value pairs. +- `list_sep` *Since 0.54.0* string used to separate list values (e.g. `', '`). Example: ```meson diff --git a/docs/markdown/snippets/summary.md b/docs/markdown/snippets/summary.md new file mode 100644 index 0000000..67f29da --- /dev/null +++ b/docs/markdown/snippets/summary.md @@ -0,0 +1,8 @@ +## Summary improvements + +A new `list_sep` keyword argument has been added to `summary()` function. +If defined and the value is a list, elements will be separated by the provided +string instead of being aligned on a new line. + +The automatic `subprojects` section now also print the number of warnings encountered +during that subproject configuration, or the error message if the configuration failed. diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index a9e0a3b..2769c2d 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -963,10 +963,14 @@ class Test(InterpreterObject): class SubprojectHolder(InterpreterObject, ObjectHolder): - def __init__(self, subinterpreter, subproject_dir, name): + def __init__(self, subinterpreter, subproject_dir, name, warnings=0, disabled_feature=None, + exception=None): InterpreterObject.__init__(self) ObjectHolder.__init__(self, subinterpreter) self.name = name + self.warnings = warnings + self.disabled_feature = disabled_feature + self.exception = exception self.subproject_dir = subproject_dir self.methods.update({'get_variable': self.get_variable_method, 'found': self.found_method, @@ -1791,6 +1795,9 @@ class Summary: bool_yn = kwargs.get('bool_yn', False) if not isinstance(bool_yn, bool): raise InterpreterException('bool_yn keyword argument must be boolean') + list_sep = kwargs.get('list_sep') + if list_sep is not None and not isinstance(list_sep, str): + raise InterpreterException('list_sep keyword argument must be string') for k, v in values.items(): if k in self.sections[section]: raise InterpreterException('Summary section {!r} already have key {!r}'.format(section, k)) @@ -1803,9 +1810,7 @@ class Summary: formatted_values.append(mlog.green('YES') if i else mlog.red('NO')) else: formatted_values.append(i) - if not formatted_values: - formatted_values = [''] - self.sections[section][k] = formatted_values + self.sections[section][k] = (formatted_values, list_sep) self.max_key_len = max(self.max_key_len, len(k)) def dump(self): @@ -1815,11 +1820,14 @@ class Summary: if section: mlog.log(' ', mlog.bold(section)) for k, v in values.items(): + v, list_sep = v indent = self.max_key_len - len(k) + 3 - mlog.log(' ' * indent, k + ':', v[0]) - indent = self.max_key_len + 5 - for i in v[1:]: - mlog.log(' ' * indent, i) + end = ' ' if v else '' + mlog.log(' ' * indent, k + ':', end=end) + if list_sep is None: + indent = self.max_key_len + 6 + list_sep = '\n' + ' ' * indent + mlog.log(*v, sep=list_sep) mlog.log('') # newline @@ -2598,10 +2606,9 @@ external dependencies (including libraries) must go to "dependencies".''') dirname = args[0] return self.do_subproject(dirname, 'meson', kwargs) - def disabled_subproject(self, dirname, feature=None): - sub = SubprojectHolder(None, self.subproject_dir, dirname) - if feature: - sub.disabled_feature = feature + def disabled_subproject(self, dirname, disabled_feature=None, exception=None): + sub = SubprojectHolder(None, self.subproject_dir, dirname, + disabled_feature=disabled_feature, exception=exception) self.subprojects[dirname] = sub return sub @@ -2609,7 +2616,7 @@ external dependencies (including libraries) must go to "dependencies".''') disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) if disabled: mlog.log('Subproject', mlog.bold(dirname), ':', 'skipped: feature', mlog.bold(feature), 'disabled') - return self.disabled_subproject(dirname, feature) + return self.disabled_subproject(dirname, disabled_feature=feature) default_options = mesonlib.stringlistify(kwargs.get('default_options', [])) default_options = coredata.create_options_dict(default_options) @@ -2650,7 +2657,7 @@ external dependencies (including libraries) must go to "dependencies".''') if not required: mlog.log(e) mlog.log('Subproject ', mlog.bold(subprojdir), 'is buildable:', mlog.red('NO'), '(disabling)') - return self.disabled_subproject(dirname) + return self.disabled_subproject(dirname, exception=e) raise e subdir = os.path.join(self.subproject_dir, resolved) @@ -2678,7 +2685,7 @@ external dependencies (including libraries) must go to "dependencies".''') # fatal and VS CI treat any logs with "ERROR:" as fatal. mlog.exception(e, prefix=mlog.yellow('Exception:')) mlog.log('\nSubproject', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)') - return self.disabled_subproject(dirname) + return self.disabled_subproject(dirname, exception=e) raise e def _do_subproject_meson(self, dirname, subdir, default_options, kwargs, ast=None, build_def_files=None): @@ -2690,7 +2697,12 @@ external dependencies (including libraries) must go to "dependencies".''') subi.subproject_stack = self.subproject_stack + [dirname] current_active = self.active_projectname + current_warnings_counter = mlog.log_warnings_counter + mlog.log_warnings_counter = 0 subi.run() + subi_warnings = mlog.log_warnings_counter + mlog.log_warnings_counter = current_warnings_counter + mlog.log('Subproject', mlog.bold(dirname), 'finished.') mlog.log() @@ -2702,7 +2714,8 @@ external dependencies (including libraries) must go to "dependencies".''') raise InterpreterException('Subproject %s version is %s but %s required.' % (dirname, pv, wanted)) self.active_projectname = current_active self.subprojects.update(subi.subprojects) - self.subprojects[dirname] = SubprojectHolder(subi, self.subproject_dir, dirname) + self.subprojects[dirname] = SubprojectHolder(subi, self.subproject_dir, dirname, + warnings=subi_warnings) # Duplicates are possible when subproject uses files from project root if build_def_files: self.build_def_files = list(set(self.build_def_files + build_def_files)) @@ -2949,7 +2962,8 @@ external dependencies (including libraries) must go to "dependencies".''') mlog.log(mlog.bold('Message:'), *args) @noArgsFlattening - @permittedKwargs({'section', 'bool_yn'}) + @FeatureNewKwargs('summary', '0.54.0', ['list_sep']) + @permittedKwargs({'section', 'bool_yn', 'list_sep'}) @FeatureNew('summary', '0.53.0') def func_summary(self, node, args, kwargs): if len(args) == 1: @@ -2977,11 +2991,18 @@ external dependencies (including libraries) must go to "dependencies".''') all_subprojects = collections.OrderedDict() for name, subp in sorted(self.subprojects.items()): value = subp.found() - if not value and hasattr(subp, 'disabled_feature'): - value = 'Feature {!r} disabled'.format(subp.disabled_feature) + if subp.disabled_feature: + value = [value, 'Feature {!r} disabled'.format(subp.disabled_feature)] + elif subp.exception: + value = [value, str(subp.exception)] + elif subp.warnings > 0: + value = [value, '{} warnings'.format(subp.warnings)] all_subprojects[name] = value if all_subprojects: - self.summary_impl('Subprojects', all_subprojects, {'bool_yn': True}) + self.summary_impl('Subprojects', all_subprojects, + {'bool_yn': True, + 'list_sep': ' ', + }) # Print all summaries, main project last. mlog.log('') # newline main_summary = self.summary.pop('', None) diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index a1acfa3..ea75bd0 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -59,6 +59,7 @@ log_disable_stdout = False # type: bool log_errors_only = False # type: bool _in_ci = 'CI' in os.environ # type: bool _logged_once = set() # type: T.Set[T.Tuple[str, ...]] +log_warnings_counter = 0 # type: int def disable() -> None: global log_disable_stdout @@ -262,6 +263,9 @@ def _log_error(severity: str, *rargs: T.Union[str, AnsiDecorator], else: log(*args, **kwargs) + global log_warnings_counter + log_warnings_counter += 1 + if log_fatal_warnings: raise MesonException("Fatal warnings enabled, aborting") diff --git a/run_unittests.py b/run_unittests.py index d091cbc..5655165 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -4392,14 +4392,15 @@ recommended as it is not supported on some platforms''') A list: string 1 True - empty list: + empty list: A number: 1 yes: YES no: NO + coma list: a, b, c Subprojects sub: YES - sub2: NO + sub2: NO Problem encountered: This subproject failed ''') expected_lines = expected.split('\n')[1:] out_start = out.find(expected_lines[0]) diff --git a/test cases/unit/72 summary/meson.build b/test cases/unit/72 summary/meson.build index c155889..df4540d 100644 --- a/test cases/unit/72 summary/meson.build +++ b/test cases/unit/72 summary/meson.build @@ -12,3 +12,4 @@ summary({'Some boolean': false, summary('A number', 1, section: 'Configuration') summary('yes', true, bool_yn : true, section: 'Configuration') summary('no', false, bool_yn : true, section: 'Configuration') +summary('coma list', ['a', 'b', 'c'], list_sep: ', ', section: 'Configuration') |