Simon Glass | a5c0a42 | 2022-01-09 20:14:05 -0700 | [diff] [blame] | 1 | # SPDX-License-Identifier: GPL-2.0+ |
| 2 | # Copyright 2022 Google LLC |
| 3 | # |
| 4 | """Bintool implementation for lz4 |
| 5 | |
| 6 | lz4 allows compression and decompression of files. |
| 7 | |
| 8 | Documentation is available via:: |
| 9 | |
| 10 | man lz4 |
| 11 | |
| 12 | Here is the help: |
| 13 | |
| 14 | *** LZ4 command line interface 64-bits v1.9.3, by Yann Collet *** |
| 15 | Usage : |
| 16 | lz4 [arg] [input] [output] |
| 17 | |
| 18 | input : a filename |
| 19 | with no FILE, or when FILE is - or stdin, read standard input |
| 20 | Arguments : |
| 21 | -1 : Fast compression (default) |
| 22 | -9 : High compression |
| 23 | -d : decompression (default for .lz4 extension) |
| 24 | -z : force compression |
| 25 | -D FILE: use FILE as dictionary |
| 26 | -f : overwrite output without prompting |
| 27 | -k : preserve source files(s) (default) |
| 28 | --rm : remove source file(s) after successful de/compression |
| 29 | -h/-H : display help/long help and exit |
| 30 | |
| 31 | Advanced arguments : |
| 32 | -V : display Version number and exit |
| 33 | -v : verbose mode |
| 34 | -q : suppress warnings; specify twice to suppress errors too |
| 35 | -c : force write to standard output, even if it is the console |
| 36 | -t : test compressed file integrity |
| 37 | -m : multiple input files (implies automatic output filenames) |
| 38 | -r : operate recursively on directories (sets also -m) |
| 39 | -l : compress using Legacy format (Linux kernel compression) |
| 40 | -B# : cut file into blocks of size # bytes [32+] |
| 41 | or predefined block size [4-7] (default: 7) |
| 42 | -BI : Block Independence (default) |
| 43 | -BD : Block dependency (improves compression ratio) |
| 44 | -BX : enable block checksum (default:disabled) |
| 45 | --no-frame-crc : disable stream checksum (default:enabled) |
| 46 | --content-size : compressed frame includes original size (default:not present) |
| 47 | --list FILE : lists information about .lz4 files (useful for files compressed |
| 48 | with --content-size flag) |
| 49 | --[no-]sparse : sparse mode (default:enabled on file, disabled on stdout) |
| 50 | --favor-decSpeed: compressed files decompress faster, but are less compressed |
| 51 | --fast[=#]: switch to ultra fast compression level (default: 1) |
| 52 | --best : same as -12 |
| 53 | Benchmark arguments : |
| 54 | -b# : benchmark file(s), using # compression level (default : 1) |
| 55 | -e# : test all compression levels from -bX to # (default : 1) |
| 56 | -i# : minimum evaluation time in seconds (default : 3s) |
| 57 | """ |
| 58 | |
| 59 | import re |
| 60 | import tempfile |
| 61 | |
| 62 | from binman import bintool |
| 63 | from patman import tools |
| 64 | |
| 65 | # pylint: disable=C0103 |
| 66 | class Bintoollz4(bintool.Bintool): |
| 67 | """Compression/decompression using the LZ4 algorithm |
| 68 | |
| 69 | This bintool supports running `lz4` to compress and decompress data, as |
| 70 | used by binman. |
| 71 | |
| 72 | It is also possible to fetch the tool, which uses `apt` to install it. |
| 73 | |
| 74 | Documentation is available via:: |
| 75 | |
| 76 | man lz4 |
| 77 | """ |
| 78 | def __init__(self, name): |
| 79 | super().__init__(name, 'lz4 compression') |
| 80 | |
| 81 | def compress(self, indata): |
| 82 | """Compress data with lz4 |
| 83 | |
| 84 | Args: |
| 85 | indata (bytes): Data to compress |
| 86 | |
| 87 | Returns: |
| 88 | bytes: Compressed data |
| 89 | """ |
| 90 | with tempfile.NamedTemporaryFile(prefix='comp.tmp', |
Simon Glass | 8002552 | 2022-01-29 14:14:04 -0700 | [diff] [blame] | 91 | dir=tools.get_output_dir()) as tmp: |
| 92 | tools.write_file(tmp.name, indata) |
Simon Glass | a5c0a42 | 2022-01-09 20:14:05 -0700 | [diff] [blame] | 93 | args = ['--no-frame-crc', '-B4', '-5', '-c', tmp.name] |
| 94 | return self.run_cmd(*args, binary=True) |
| 95 | |
| 96 | def decompress(self, indata): |
| 97 | """Decompress data with lz4 |
| 98 | |
| 99 | Args: |
| 100 | indata (bytes): Data to decompress |
| 101 | |
| 102 | Returns: |
| 103 | bytes: Decompressed data |
| 104 | """ |
| 105 | with tempfile.NamedTemporaryFile(prefix='decomp.tmp', |
Simon Glass | 8002552 | 2022-01-29 14:14:04 -0700 | [diff] [blame] | 106 | dir=tools.get_output_dir()) as inf: |
| 107 | tools.write_file(inf.name, indata) |
Simon Glass | a5c0a42 | 2022-01-09 20:14:05 -0700 | [diff] [blame] | 108 | args = ['-cd', inf.name] |
| 109 | return self.run_cmd(*args, binary=True) |
| 110 | |
| 111 | def fetch(self, method): |
| 112 | """Fetch handler for lz4 |
| 113 | |
| 114 | This installs the lz4 package using the apt utility. |
| 115 | |
| 116 | Args: |
| 117 | method (FETCH_...): Method to use |
| 118 | |
| 119 | Returns: |
| 120 | True if the file was fetched and now installed, None if a method |
| 121 | other than FETCH_BIN was requested |
| 122 | |
| 123 | Raises: |
| 124 | Valuerror: Fetching could not be completed |
| 125 | """ |
| 126 | if method != bintool.FETCH_BIN: |
| 127 | return None |
| 128 | return self.apt_install('lz4') |
| 129 | |
| 130 | def version(self): |
| 131 | """Version handler |
| 132 | |
| 133 | Returns: |
| 134 | str: Version number of lz4 |
| 135 | """ |
| 136 | out = self.run_cmd('-V').strip() |
| 137 | if not out: |
| 138 | return super().version() |
| 139 | m_version = re.match(r'.* (v[0-9.]*),.*', out) |
| 140 | return m_version.group(1) if m_version else out |