Merge pull request #6692 from xclaesse/summary-warnings

Summary improvements
pull/6718/head
Jussi Pakkanen 5 years ago committed by GitHub
commit 200738a3e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      docs/markdown/Reference-manual.md
  2. 8
      docs/markdown/snippets/summary.md
  3. 61
      mesonbuild/interpreter.py
  4. 4
      mesonbuild/mlog.py
  5. 5
      run_unittests.py
  6. 1
      test cases/unit/72 summary/meson.build

@ -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

@ -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.

@ -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)

@ -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")

@ -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])

@ -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')

Loading…
Cancel
Save