binman: Support help messages for missing blobs

When an external blob is missing it can be quite confusing for the user.
Add a way to provide a help message that is shown.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
This commit is contained in:
Simon Glass 2020-09-06 10:39:09 -06:00
parent c0f1ebe9c1
commit b238143db9
6 changed files with 119 additions and 3 deletions

View File

@ -343,6 +343,12 @@ compress:
Sets the compression algortihm to use (for blobs only). See the entry
documentation for details.
missing-msg:
Sets the tag of the message to show if this entry is missing. This is
used for external blobs. When they are missing it is helpful to show
information about what needs to be fixed. See missing-blob-help for the
message for each tag.
The attributes supported for images and sections are described below. Several
are similar to those for entries.

View File

@ -9,6 +9,7 @@ from collections import OrderedDict
import glob
import os
import pkg_resources
import re
import sys
from patman import tools
@ -22,6 +23,11 @@ from patman import tout
# Make this global so that it can be referenced from tests
images = OrderedDict()
# Help text for each type of missing blob, dict:
# key: Value of the entry's 'missing-msg' or entry name
# value: Text for the help
missing_blob_help = {}
def _ReadImageDesc(binman_node):
"""Read the image descriptions from the /binman node
@ -54,6 +60,66 @@ def _FindBinmanNode(dtb):
return node
return None
def _ReadMissingBlobHelp():
"""Read the missing-blob-help file
This file containins help messages explaining what to do when external blobs
are missing.
Returns:
Dict:
key: Message tag (str)
value: Message text (str)
"""
def _FinishTag(tag, msg, result):
if tag:
result[tag] = msg.rstrip()
tag = None
msg = ''
return tag, msg
my_data = pkg_resources.resource_string(__name__, 'missing-blob-help')
re_tag = re.compile('^([-a-z0-9]+):$')
result = {}
tag = None
msg = ''
for line in my_data.decode('utf-8').splitlines():
if not line.startswith('#'):
m_tag = re_tag.match(line)
if m_tag:
_, msg = _FinishTag(tag, msg, result)
tag = m_tag.group(1)
elif tag:
msg += line + '\n'
_FinishTag(tag, msg, result)
return result
def _ShowBlobHelp(path, text):
tout.Warning('\n%s:' % path)
for line in text.splitlines():
tout.Warning(' %s' % line)
def _ShowHelpForMissingBlobs(missing_list):
"""Show help for each missing blob to help the user take action
Args:
missing_list: List of Entry objects to show help for
"""
global missing_blob_help
if not missing_blob_help:
missing_blob_help = _ReadMissingBlobHelp()
for entry in missing_list:
tags = entry.GetHelpTags()
# Show the first match help message
for tag in tags:
if tag in missing_blob_help:
_ShowBlobHelp(entry._node.path, missing_blob_help[tag])
break
def GetEntryModules(include_testing=True):
"""Get a set of entry class implementations
@ -478,6 +544,7 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
if missing_list:
tout.Warning("Image '%s' is missing external blobs and is non-functional: %s" %
(image.name, ' '.join([e.name for e in missing_list])))
_ShowHelpForMissingBlobs(missing_list)
return bool(missing_list)
@ -563,7 +630,7 @@ def Binman(args):
tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
if missing:
tout.Warning("Some images are invalid")
tout.Warning("\nSome images are invalid")
finally:
tools.FinaliseOutputDir()
finally:

View File

@ -178,6 +178,7 @@ class Entry(object):
self.align_end = fdt_util.GetInt(self._node, 'align-end')
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
def GetDefaultFilename(self):
return None
@ -827,3 +828,11 @@ features to produce new behaviours.
True if allowed, False if not allowed
"""
return self.allow_missing
def GetHelpTags(self):
"""Get the tags use for missing-blob help
Returns:
list of possible tags, most desirable first
"""
return list(filter(None, [self.missing_msg, self.name, self.etype]))

View File

@ -3561,7 +3561,7 @@ class TestFunctional(unittest.TestCase):
self._DoTestFile('168_fit_missing_blob.dts',
allow_missing=True)
err = stderr.getvalue()
self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
def testBlobNamedByArgMissing(self):
"""Test handling of a missing entry arg"""
@ -3692,5 +3692,21 @@ class TestFunctional(unittest.TestCase):
self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
str(e.exception))
def testFitExtblobMissingHelp(self):
"""Test display of help messages when an external blob is missing"""
control.missing_blob_help = control._ReadMissingBlobHelp()
control.missing_blob_help['wibble'] = 'Wibble test'
control.missing_blob_help['another'] = 'Another test'
with test_util.capture_sys_output() as (stdout, stderr):
self._DoTestFile('168_fit_missing_blob.dts',
allow_missing=True)
err = stderr.getvalue()
# We can get the tag from the name, the type or the missing-msg
# property. Check all three.
self.assertIn('You may need to build ARM Trusted', err)
self.assertIn('Wibble test', err)
self.assertIn('Another test', err)
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,11 @@
# This file contains help messages for missing external blobs. Each message has
# a tag (MUST be just lower-case text, digits and hyphens) starting in column 1,
# followed by a colon (:) to indicate its start. The message can include any
# number of lines, including blank lines.
#
# When looking for a tag, Binman uses the value of 'missing-msg' for the entry,
# the entry name or the entry type, in that order
atf-bl31:
See the documentation for your board. You may need to build ARM Trusted
Firmware and build with BL31=/path/to/bl31.bin

View File

@ -29,9 +29,16 @@
hash-2 {
algo = "sha1";
};
blob-ext {
atf-bl31 {
filename = "missing";
};
cros-ec-rw {
type = "atf-bl31";
missing-msg = "wibble";
};
another {
type = "atf-bl31";
};
};
};
};