
From: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com
Add gzip bintool to binman to support on-the-fly compression of Linux kernel images and FPGA bitstreams. The SPL basic fitImage implementation supports only gzip decompression.
Signed-off-by: Stefan Herbrechtsmeier stefan.herbrechtsmeier@weidmueller.com ---
tools/binman/btool/gzip.py | 94 ++++++++++++++++++++++++++++++++++++++ tools/binman/comp_util.py | 17 +++++-- tools/binman/ftest.py | 18 ++++++++ 3 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 tools/binman/btool/gzip.py
diff --git a/tools/binman/btool/gzip.py b/tools/binman/btool/gzip.py new file mode 100644 index 0000000000..27fb654ed5 --- /dev/null +++ b/tools/binman/btool/gzip.py @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2022 Google LLC +# +"""Bintool implementation for gzip + +gzip allows compression and decompression of files. + +Documentation is available via:: + + man gzip +""" + +import re +import tempfile + +from binman import bintool +from patman import tools + +# pylint: disable=C0103 +class Bintoolgzip(bintool.Bintool): + """Compression/decompression using the gzip algorithm + + This bintool supports running `gzip` to compress and decompress data, as + used by binman. + + It is also possible to fetch the tool, which uses `apt` to install it. + + Documentation is available via:: + + man gzip + """ + def __init__(self, name): + super().__init__(name, 'gzip compression') + + def compress(self, indata): + """Compress data with gzip + + Args: + indata (bytes): Data to compress + + Returns: + bytes: Compressed data + """ + with tempfile.NamedTemporaryFile(prefix='comp.tmp', + dir=tools.get_output_dir()) as tmp: + tools.write_file(tmp.name, indata) + args = ['-c', tmp.name] + return self.run_cmd(*args, binary=True) + + def decompress(self, indata): + """Decompress data with gzip + + Args: + indata (bytes): Data to decompress + + Returns: + bytes: Decompressed data + """ + with tempfile.NamedTemporaryFile(prefix='decomp.tmp', + dir=tools.get_output_dir()) as inf: + tools.write_file(inf.name, indata) + args = ['-cd', inf.name] + return self.run_cmd(*args, binary=True) + + def fetch(self, method): + """Fetch handler for gzip + + This installs the gzip package using the apt utility. + + Args: + method (FETCH_...): Method to use + + Returns: + True if the file was fetched and now installed, None if a method + other than FETCH_BIN was requested + + Raises: + Valuerror: Fetching could not be completed + """ + if method != bintool.FETCH_BIN: + return None + return self.apt_install('gzip') + + def version(self): + """Version handler + + Returns: + str: Version number of gzip + """ + out = self.run_cmd('-V').strip() + if not out: + return super().version() + m_version = re.match(r'.*gzip ([0-9.]*).*', out) + return m_version.group(1) if m_version else out diff --git a/tools/binman/comp_util.py b/tools/binman/comp_util.py index 269bbf7975..1d30f1613c 100644 --- a/tools/binman/comp_util.py +++ b/tools/binman/comp_util.py @@ -8,6 +8,9 @@ import tempfile from binman import bintool from patman import tools
+GZIP = bintool.Bintool.create('gzip') +HAVE_GZIP = GZIP.is_present() + LZ4 = bintool.Bintool.create('lz4') HAVE_LZ4 = LZ4.is_present()
@@ -21,19 +24,21 @@ def compress(indata, algo): Note that for lzma this uses an old version of the algorithm, not that provided by xz.
- This requires 'lz4' and 'lzma_alone' tools. It also requires an output + This requires 'gzip', 'lz4' and 'lzma_alone' tools. It also requires an output directory to be previously set up, by calling PrepareOutputDir().
Args: indata (bytes): Input data to compress - algo (str): Algorithm to use ('none', 'lz4' or 'lzma') + algo (str): Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
Returns: bytes: Compressed data """ if algo == 'none': return indata - if algo == 'lz4': + if algo == 'gzip': + data = GZIP.compress(indata) + elif algo == 'lz4': data = LZ4.compress(indata) # cbfstool uses a very old version of lzma elif algo == 'lzma': @@ -48,12 +53,12 @@ def decompress(indata, algo): Note that for lzma this uses an old version of the algorithm, not that provided by xz.
- This requires 'lz4' and 'lzma_alone' tools. It also requires an output + This requires 'gzip', 'lz4' and 'lzma_alone' tools. It also requires an output directory to be previously set up, by calling PrepareOutputDir().
Args: indata (bytes): Input data to decompress - algo (str): Algorithm to use ('none', 'lz4' or 'lzma') + algo (str): Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
Returns: (bytes) Compressed data @@ -62,6 +67,8 @@ def decompress(indata, algo): return indata if algo == 'lz4': data = LZ4.decompress(indata) + elif algo == 'gzip': + data = GZIP.decompress(indata) elif algo == 'lzma': data = LZMA_ALONE.decompress(indata) else: diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index b1f564ed7d..5956ffa6e4 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -5226,6 +5226,24 @@ fdt fdtmap Extract the devicetree blob from the fdtmap comp_util.decompress(b'1234', 'invalid') self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
+ def testGzipCompress(self): + """Test gzip compress""" + if not comp_util.HAVE_GZIP: + self.skipTest('gzip not available') + data = comp_util.compress(COMPRESS_DATA, 'gzip') + gzip = bintool.Bintool.create('gzip') + orig = gzip.decompress(data) + self.assertEquals(COMPRESS_DATA, orig) + + def testGzipDecompress(self): + """Test gzip decompress""" + if not comp_util.HAVE_GZIP: + self.skipTest('gzip not available') + gzip = bintool.Bintool.create('gzip') + data = gzip.compress(COMPRESS_DATA) + orig = comp_util.decompress(data, 'gzip') + self.assertEquals(COMPRESS_DATA, orig) + def testBintoolDocs(self): """Test for creation of bintool documentation""" with test_util.capture_sys_output() as (stdout, stderr):