binman: Allow listing the entries in an image
authorSimon Glass <sjg@chromium.org>
Mon, 8 Jul 2019 20:25:43 +0000 (14:25 -0600)
committerSimon Glass <sjg@chromium.org>
Wed, 24 Jul 2019 19:54:08 +0000 (12:54 -0700)
It is useful to be able to summarise all the entries in an image, e.g. to
display this to this user. Add a new ListEntries() method to Entry, and
set up a way to call it through the Image class.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/bsection.py
tools/binman/entry.py
tools/binman/etype/cbfs.py
tools/binman/etype/section.py
tools/binman/ftest.py
tools/binman/image.py
tools/binman/test/127_list.dts [new file with mode: 0644]

index 9047e55a34afdcbfe1f8d0fa7a9230ed78f18e33..082f424241cc8dc55539117c15568b9c6cdf9dca 100644 (file)
@@ -10,6 +10,7 @@ from __future__ import print_function
 from collections import OrderedDict
 import sys
 
+from entry import Entry
 import fdt_util
 import re
 import state
@@ -512,3 +513,11 @@ class Section(object):
                 image size is dynamic and its sections have not yet been packed
         """
         return self._image._size
+
+    def ListEntries(self, entries, indent):
+        """Override this method to list all files in the section"""
+        Entry.AddEntryInfo(entries, indent, self._name, 'section', self._size,
+                           self._image_pos, None, self._offset,
+                           self._parent_section)
+        for entry in self._entries.values():
+            entry.ListEntries(entries, indent + 1)
index e38cb71c5966e6d8fe23163a8211246fdbcae3e6..ee63d183532a7696a3192215a6e827201a4bc13e 100644 (file)
@@ -33,6 +33,10 @@ our_path = os.path.dirname(os.path.realpath(__file__))
 # device-tree properties.
 EntryArg = namedtuple('EntryArg', ['name', 'datatype'])
 
+# Information about an entry for use when displaying summaries
+EntryInfo = namedtuple('EntryInfo', ['indent', 'name', 'etype', 'size',
+                                     'image_pos', 'uncomp_size', 'offset',
+                                     'entry'])
 
 class Entry(object):
     """An Entry in the section
@@ -617,3 +621,35 @@ features to produce new behaviours.
         if not self.HasSibling(name):
             return False
         return self.section.GetEntries()[name].image_pos
+
+    @staticmethod
+    def AddEntryInfo(entries, indent, name, etype, size, image_pos,
+                     uncomp_size, offset, entry):
+        """Add a new entry to the entries list
+
+        Args:
+            entries: List (of EntryInfo objects) to add to
+            indent: Current indent level to add to list
+            name: Entry name (string)
+            etype: Entry type (string)
+            size: Entry size in bytes (int)
+            image_pos: Position within image in bytes (int)
+            uncomp_size: Uncompressed size if the entry uses compression, else
+                None
+            offset: Entry offset within parent in bytes (int)
+            entry: Entry object
+        """
+        entries.append(EntryInfo(indent, name, etype, size, image_pos,
+                                 uncomp_size, offset, entry))
+
+    def ListEntries(self, entries, indent):
+        """Add files in this entry to the list of entries
+
+        This can be overridden by subclasses which need different behaviour.
+
+        Args:
+            entries: List (of EntryInfo objects) to add to
+            indent: Current indent level to add to list
+        """
+        self.AddEntryInfo(entries, indent, self.name, self.etype, self.size,
+                          self.image_pos, self.uncomp_size, self.offset, self)
index 175ecae15842d2c17371b09efd6de84c500f90a2..953d6f4868da6c6bacfe0f7cf7af69ce5e8af54d 100644 (file)
@@ -195,7 +195,6 @@ class Entry_cbfs(Entry):
                             entry._type)
             if cfile:
                 entry._cbfs_file = cfile
-                entry.size = cfile.data_len
         data = cbfs.get_data()
         self.SetContents(data)
         return True
@@ -249,3 +248,9 @@ class Entry_cbfs(Entry):
             state.SetInt(entry._node, 'image-pos', entry.image_pos)
             if entry.uncomp_size is not None:
                 state.SetInt(entry._node, 'uncomp-size', entry.uncomp_size)
+
+    def ListEntries(self, entries, indent):
+        """Override this method to list all files in the section"""
+        Entry.ListEntries(self, entries, indent)
+        for entry in self._cbfs_entries.values():
+            entry.ListEntries(entries, indent + 1)
index 23bf22113d4d66eaa87858bea270d20a95aaa4ee..178e89352e5f1fe4fbd6a1fdff7ac13f496c5d5b 100644 (file)
@@ -111,3 +111,7 @@ class Entry_section(Entry):
     def ExpandToLimit(self, limit):
         super(Entry_section, self).ExpandToLimit(limit)
         self._section.ExpandSize(self.size)
+
+    def ListEntries(self, entries, indent):
+        """List the files in the section"""
+        self._section.ListEntries(entries, indent)
index 21bea6c9d13a5abf862daa24595ecacd93fc57b3..de459b2b3b6322ff4188b6e3f6b75e1da9b5336f 100644 (file)
@@ -2191,6 +2191,82 @@ class TestFunctional(unittest.TestCase):
             self._DoReadFile('126_cbfs_bad_type.dts')
         self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
 
+    def testList(self):
+        """Test listing the files in an image"""
+        self._CheckLz4()
+        data = self._DoReadFile('127_list.dts')
+        image = control.images['image']
+        entries = image.BuildEntryList()
+        self.assertEqual(7, len(entries))
+
+        ent = entries[0]
+        self.assertEqual(0, ent.indent)
+        self.assertEqual('main-section', ent.name)
+        self.assertEqual('section', ent.etype)
+        self.assertEqual(len(data), ent.size)
+        self.assertEqual(0, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(None, ent.offset)
+
+        ent = entries[1]
+        self.assertEqual(1, ent.indent)
+        self.assertEqual('u-boot', ent.name)
+        self.assertEqual('u-boot', ent.etype)
+        self.assertEqual(len(U_BOOT_DATA), ent.size)
+        self.assertEqual(0, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(0, ent.offset)
+
+        ent = entries[2]
+        self.assertEqual(1, ent.indent)
+        self.assertEqual('section', ent.name)
+        self.assertEqual('section', ent.etype)
+        section_size = ent.size
+        self.assertEqual(0x100, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(len(U_BOOT_DATA), ent.offset)
+
+        ent = entries[3]
+        self.assertEqual(2, ent.indent)
+        self.assertEqual('cbfs', ent.name)
+        self.assertEqual('cbfs', ent.etype)
+        self.assertEqual(0x400, ent.size)
+        self.assertEqual(0x100, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(0, ent.offset)
+
+        ent = entries[4]
+        self.assertEqual(3, ent.indent)
+        self.assertEqual('u-boot', ent.name)
+        self.assertEqual('u-boot', ent.etype)
+        self.assertEqual(len(U_BOOT_DATA), ent.size)
+        self.assertEqual(0x138, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(0x38, ent.offset)
+
+        ent = entries[5]
+        self.assertEqual(3, ent.indent)
+        self.assertEqual('u-boot-dtb', ent.name)
+        self.assertEqual('text', ent.etype)
+        self.assertGreater(len(COMPRESS_DATA), ent.size)
+        self.assertEqual(0x178, ent.image_pos)
+        self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
+        self.assertEqual(0x78, ent.offset)
+
+        ent = entries[6]
+        self.assertEqual(2, ent.indent)
+        self.assertEqual('u-boot-dtb', ent.name)
+        self.assertEqual('u-boot-dtb', ent.etype)
+        self.assertEqual(0x500, ent.image_pos)
+        self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
+        dtb_size = ent.size
+        # Compressing this data expands it since headers are added
+        self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
+        self.assertEqual(0x400, ent.offset)
+
+        self.assertEqual(len(data), 0x100 + section_size)
+        self.assertEqual(section_size, 0x400 + dtb_size)
+
 
 if __name__ == "__main__":
     unittest.main()
index 6339d020e766dedc48e14826a8e5ee560501fd6c..6f4bd5d37b252a707d7e8efeaa52fa1fb1693b82 100644 (file)
@@ -162,3 +162,13 @@ class Image:
                   file=fd)
             self._section.WriteMap(fd, 0)
         return fname
+
+    def BuildEntryList(self):
+        """List the files in an image
+
+        Returns:
+            List of entry.EntryInfo objects describing all entries in the image
+        """
+        entries = []
+        self._section.ListEntries(entries, 0)
+        return entries
diff --git a/tools/binman/test/127_list.dts b/tools/binman/test/127_list.dts
new file mode 100644 (file)
index 0000000..c1d6fce
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               u-boot {
+               };
+               section {
+                       align = <0x100>;
+                       cbfs {
+                               size = <0x400>;
+                               u-boot {
+                                       cbfs-type = "raw";
+                                       cbfs-offset = <0x38>;
+                               };
+                               u-boot-dtb {
+                                       type = "text";
+                                       text = "compress xxxxxxxxxxxxxxxxxxxxxx data";
+                                       cbfs-type = "raw";
+                                       cbfs-compress = "lzma";
+                                       cbfs-offset = <0x78>;
+                               };
+                       };
+                       u-boot-dtb {
+                               compress = "lz4";
+                       };
+               };
+       };
+};