interpreter: accept external programs and dependencies for summary

pull/8240/head
Paolo Bonzini 4 years ago committed by Xavier Claessens
parent 021068a8b7
commit adb1b2f3f6
  1. 6
      docs/markdown/Reference-manual.md
  2. 4
      docs/markdown/snippets/summary_prog_dep.md
  3. 17
      mesonbuild/dependencies/base.py
  4. 18
      mesonbuild/interpreter.py
  5. 12
      mesonbuild/mlog.py
  6. 6
      run_unittests.py
  7. 5
      test cases/unit/73 summary/meson.build

@ -1313,7 +1313,11 @@ The content is a series of key/value pairs grouped into sections. If the section
keyword argument is omitted, those key/value pairs are implicitly grouped into a section
with no title. key/value pairs can optionally be grouped into a dictionary,
but keep in mind that dictionaries does not guarantee ordering. `key` must be string,
`value` can only be integer, boolean, string, or a list of those.
`value` can be:
- an integer, boolean or string
- *since 0.57.0* an external program or a dependency
- a list of those.
`summary()` can be called multiple times as long as the same section/key
pair doesn't appear twice. All sections will be collected and printed at

@ -0,0 +1,4 @@
## `summary()` accepts external programs or dependencies
External program objects and dependency objects can be passed to
`summary()` as the value to be printed.

@ -134,6 +134,13 @@ class Dependency:
def is_built(self) -> bool:
return False
def summary_value(self) -> T.Union[str, mlog.AnsiDecorator, mlog.AnsiText]:
if not self.found():
return mlog.red('NO')
if not self.version:
return mlog.green('YES')
return mlog.AnsiText(mlog.green('YES'), ' ', mlog.cyan(self.version))
def get_compile_args(self) -> T.List[str]:
if self.include_type == 'system':
converted = []
@ -263,6 +270,11 @@ class InternalDependency(Dependency):
setattr(result, k, copy.deepcopy(v, memo))
return result
def summary_value(self) -> mlog.AnsiDecorator:
# Omit the version. Most of the time it will be just the project
# version, which is uninteresting in the summary.
return mlog.green('YES')
def is_built(self) -> bool:
if self.sources or self.libraries or self.whole_libraries:
return True
@ -1888,6 +1900,11 @@ class ExternalProgram:
else:
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
def summary_value(self) -> T.Union[str, mlog.AnsiDecorator]:
if not self.found():
return mlog.red('NO')
return self.path
def __repr__(self) -> str:
r = '<{} {!r} -> {!r}>'
return r.format(self.__class__.__name__, self.name, self.command)

@ -1854,7 +1854,7 @@ class Summary:
self.sections = collections.defaultdict(dict)
self.max_key_len = 0
def add_section(self, section, values, kwargs):
def add_section(self, section, values, kwargs, subproject):
bool_yn = kwargs.get('bool_yn', False)
if not isinstance(bool_yn, bool):
raise InterpreterException('bool_yn keyword argument must be boolean')
@ -1866,13 +1866,17 @@ class Summary:
raise InterpreterException('Summary section {!r} already have key {!r}'.format(section, k))
formatted_values = []
for i in listify(v):
if not isinstance(i, (str, int)):
m = 'Summary value in section {!r}, key {!r}, must be string, integer or boolean'
raise InterpreterException(m.format(section, k))
if bool_yn and isinstance(i, bool):
i = unholder(i)
if isinstance(i, bool) and bool_yn:
formatted_values.append(mlog.green('YES') if i else mlog.red('NO'))
else:
elif isinstance(i, (str, int, bool)):
formatted_values.append(str(i))
elif isinstance(i, (ExternalProgram, Dependency)):
FeatureNew.single_use('dependency or external program in summary', '0.57.0', subproject)
formatted_values.append(i.summary_value())
else:
m = 'Summary value in section {!r}, key {!r}, must be string, integer, boolean, dependency or external program'
raise InterpreterException(m.format(section, k))
self.sections[section][k] = (formatted_values, list_sep)
self.max_key_len = max(self.max_key_len, len(k))
@ -3284,7 +3288,7 @@ external dependencies (including libraries) must go to "dependencies".''')
def summary_impl(self, section, values, kwargs):
if self.subproject not in self.summary:
self.summary[self.subproject] = Summary(self.active_projectname, self.project_version)
self.summary[self.subproject].add_section(section, values, kwargs)
self.summary[self.subproject].add_section(section, values, kwargs, self.subproject)
def _print_summary(self):
# Add automatic 'Supbrojects' section in main project.

@ -136,6 +136,18 @@ class AnsiDecorator:
def __str__(self) -> str:
return self.get_text(colorize_console())
class AnsiText:
def __init__(self, *args: T.List[T.Union[str, AnsiDecorator]]):
self.args = args
def __len__(self) -> int:
return sum((len(x) for x in self.args))
def __str__(self) -> str:
return ''.join((str(x) for x in self.args))
def bold(text: str, quoted: bool = False) -> AnsiDecorator:
return AnsiDecorator(text, "\033[1m", quoted=quoted)

@ -4707,6 +4707,12 @@ class AllPlatformTests(BasePlatformTests):
no : NO
coma list : a, b, c
Stuff
missing prog : NO
existing prog : ''' + sys.executable + '''
missing dep : NO
internal dep : YES
Plugins
long coma list : alpha, alphacolor, apetag, audiofx, audioparsers, auparse,
autodetect, avi

@ -9,6 +9,11 @@ summary({'Some boolean': false,
'A list': ['string', 1, true],
'empty list': [],
}, section: 'Configuration')
summary({'missing prog': find_program('xyzzy', required: false),
'existing prog': import('python').find_installation(),
'missing dep': dependency('', required: false),
'internal dep': declare_dependency(),
}, section: 'Stuff')
summary('A number', 1, section: 'Configuration')
summary('yes', true, bool_yn : true, section: 'Configuration')
summary('no', false, bool_yn : true, section: 'Configuration')

Loading…
Cancel
Save