binman: Allow entry args to be required

If an entry argument is needed by an entry but the entry argument is not
present, then a strange error can occur when trying to read the file.

Fix this by allowing arguments to be required. Select this option for the
cros-ec-rw entry. If a filename is provided in the node, allow that to be
used.

Also tidy up a few related tests to make the error string easier to find,
and fully ignore unused return values.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/tools/binman/README.entries b/tools/binman/README.entries
index bf8edce..97bfae1 100644
--- a/tools/binman/README.entries
+++ b/tools/binman/README.entries
@@ -60,7 +60,7 @@
 
 Properties / Entry arguments:
     - <xxx>-path: Filename containing the contents of this entry (optional,
-        defaults to 0)
+        defaults to None)
 
 where <xxx> is the blob_fname argument to the constructor.
 
@@ -691,6 +691,11 @@
     name-prefix: Adds a prefix to the name of every entry in the section
         when writing out the map
 
+Properties:
+    _allow_missing: True if this section permits external blobs to be
+        missing their contents. The second will produce an image but of
+        course it will not work.
+
 Since a section is also an entry, it inherits all the properies of entries
 too.
 
diff --git a/tools/binman/etype/blob_named_by_arg.py b/tools/binman/etype/blob_named_by_arg.py
index e95dabe..7c486b2 100644
--- a/tools/binman/etype/blob_named_by_arg.py
+++ b/tools/binman/etype/blob_named_by_arg.py
@@ -17,7 +17,7 @@
 
     Properties / Entry arguments:
         - <xxx>-path: Filename containing the contents of this entry (optional,
-            defaults to 0)
+            defaults to None)
 
     where <xxx> is the blob_fname argument to the constructor.
 
@@ -28,7 +28,9 @@
 
     See cros_ec_rw for an example of this.
     """
-    def __init__(self, section, etype, node, blob_fname):
+    def __init__(self, section, etype, node, blob_fname, required=False):
         super().__init__(section, etype, node)
-        self._filename, = self.GetEntryArgsOrProps(
-            [EntryArg('%s-path' % blob_fname, str)])
+        filename, = self.GetEntryArgsOrProps(
+            [EntryArg('%s-path' % blob_fname, str)], required=required)
+        if filename:
+            self._filename = filename
diff --git a/tools/binman/etype/cros_ec_rw.py b/tools/binman/etype/cros_ec_rw.py
index 741372e..bf676b2 100644
--- a/tools/binman/etype/cros_ec_rw.py
+++ b/tools/binman/etype/cros_ec_rw.py
@@ -7,7 +7,6 @@
 
 from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
 
-
 class Entry_cros_ec_rw(Entry_blob_named_by_arg):
     """A blob entry which contains a Chromium OS read-write EC image
 
@@ -18,5 +17,5 @@
     updating the EC on startup via software sync.
     """
     def __init__(self, section, etype, node):
-        super().__init__(section, etype, node, 'cros-ec-rw')
+        super().__init__(section, etype, node, 'cros-ec-rw', required=True)
         self.external = True
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index e672967..f000a79 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1382,8 +1382,9 @@
         }
         with self.assertRaises(ValueError) as e:
             self._DoReadFileDtb('064_entry_args_required.dts')
-        self.assertIn("Node '/binman/_testing': Missing required "
-            'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
+        self.assertIn("Node '/binman/_testing': "
+            'Missing required properties/entry args: test-str-arg, '
+            'test-int-fdt, test-int-arg',
             str(e.exception))
 
     def testEntryArgsInvalidFormat(self):
@@ -1487,8 +1488,7 @@
         entry_args = {
             'cros-ec-rw-path': 'ecrw.bin',
         }
-        data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
-                                            entry_args=entry_args)
+        self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
 
     def testFill(self):
         """Test for an fill entry type"""
@@ -3523,5 +3523,12 @@
         err = stderr.getvalue()
         self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
 
+    def testBlobNamedByArgMissing(self):
+        """Test handling of a missing entry arg"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('068_blob_named_by_arg.dts')
+        self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
+                      str(e.exception))
+
 if __name__ == "__main__":
     unittest.main()